こんにちは、山本和道です。
本記事は連載「若手エンジニアのためのDevOps入門」の第2回です。

第1回 インフラエンジニアにとってのDevOps
第2回 Webアプリでの開発環境構築
第3回 バージョン管理システム
第4回 継続的インテグレーション/デリバリー
第5回 DevOpsのための道具箱: APIを使いこなす
第6回 リリース/構成管理: 概要

第1回では「DevOpsとは何か、どのようなプロセスやツールがあるのか」という部分の概要について扱いました。

連載第2回である今回はDevOpsプロセスの中でも開発環境に注目してみます。

開発の時点で運用側(Ops)との連携を視野に入れた環境構築/プロセス構築を行なっておくことは円滑なDevOps導入にとって重要なポイントです。

なお本連載はモデルケースとしてWebアプリの開発を行うことを想定した内容となっています。実際の開発環境構築の際はアプリケーションの特性に応じて適宜調整を行なってください。

Webアプリでの開発環境

一口に開発環境といってもその中には様々な要素を含んでいます。例えば統合開発環境(IDE)やエディタ、コンパイラ、コード整形(フォーマット)、構文解析などのコーディング作業に直結するようなツールやテストツール、タスクランナー、ソースコードのバージョン管理などの周辺ツール、さらにはバグ/イシュートラッキングやデータベースなどの操作ツールといったものまで幅広い内容となっています。

これらの全てを扱うと考慮事項が膨大な数となってしまいますので、当記事では取り掛かりとして運用側(Ops)の担当領域とも重なる開発時のサーバ周りを中心にみていきます。

開発時のサーバ

Webアプリの開発を行う場合、動作確認のためにサーバが必要になります。
まずは手元のマシンや社内に立てた開発用サーバで動作確認してから本番投入といった流れになっていることが多いと思います。

開発中のWebアプリを手元のマシンで動作確認する場合、Webサーバを手元のマシンにインストールしたり、プログラミング言語やフレームワーク(と周辺ツール)が提供してくれるWebサーバ(例: Ruby on Railsの場合「rails server」コマンドで起動する開発用サーバ)を利用することになります。

開発用サーバで起こりがちな問題

ここでよく起こりがちなのが、「開発環境では動くのに本番環境では動かない」という問題です。開発用サーバと本番用サーバの設定の違いや利用するデータの違い、動作の違い(例: 本番環境ではコンパイル済みのアセット(JS/CSS/画像など)を利用するなど)などが原因になり、本番環境では期待する動作とならないというものです。

本来であれば最終的にWebアプリを動かす本番用サーバそのもの、もしくは本番環境とほぼ同等の条件を持つサーバで動作確認するのが理想ですが、以下のような様々な理由により難しいことも多いでしょう。

  • すでに稼働しているアプリや本番環境のデータには影響を与えたくない
  • 本番環境には開発時にしか必要とされないリソースは置きたくない
  • セキュリティの都合上、本番環境にアクセスできるユーザーを限定している
  • 本番環境と同等の環境を用意するには費用がかかる
  • 本番環境と手元のマシンがネットワーク的に離れており手元のマシンでの変更を反映するのに時間がかかる

このため、アプリの特性や後続プロセスとの兼ね合いといった様々な面でトレードオフを考慮したうえで本番環境とは別のサーバ環境を構築する必要があります。具体的には以下のような項目がトレードオフを考慮するポイントとなります。

  • 環境構築や変更適用の手順の容易さ
  • 変更適用までの速度
  • セキュリティ
  • 本番環境での安定動作に対する安全性
  • 費用

以下では大きく分けて3つの具体的な方法をご紹介していきます。実際にはこれらの方法のいずれかだけを利用するのではなく、アプリの特性や組織からの要請に合わせて適宜組み合わせ/調整して利用することになるかと思いますので、各方法を組み合わせて利用するケースについても解説いたします。

1: 開発者各自のマシンでサーバを構築する方法

開発者各自のマシンにWebサーバをインストールしたり、仮想環境を構築する方法です。
別途サーバを用意するコストは不要ですが、各自のマシンでWebサーバや仮想環境を動かせるだけのスペックが求められます。また各自のマシンでの環境構築の作業負荷についても考慮しておく必要があります。

本番環境との差異をなるべくなくすには以下のような点に注意する必要があります。

  • 本番環境に近い設定、理想的には同じ設定となるようにすること
  • 環境構築手順を明確にして各メンバーに展開しやすくすること
  • 環境を変更する際はメンバーに対し周知すること

Webサーバ/Appサーバ、ミドルウェアの種類やバージョン、設定はできるだけ本番環境と同様にしておく方がトラブルを少なくできます。
ただ、開発環境ではテスト用の証明書しか用意できないといった場合や、本番環境は他の大きなシステムのサブシステムであるといった場合などに本番環境と同様の設定にできないといった状況もありえます。その場合、アプリケーションの動作に影響を与えにくい箇所などについては差分を許容するというふうに各自の環境における現実的な落とし所を検討してみてください。

環境設定を展開しやすくするツール

サーバの環境設定を各メンバーに展開するには様々な方法があります。
手順書を用意しておき、各メンバーが手順書に従って環境構築を行うという方法もありますが、人力で行うと手順書の更新忘れや適用漏れといったヒューマンエラーが発生することもあります。

プロビジョニングツールの活用

そこで、環境構築は実行可能なスクリプトにしておいたり、プロビジョニングツールを用いるようにしておくと展開が楽になります。

プロビジョニングツールの有名どころとしてはPuppetやChef、Ansibleといったものがあります。

※プロビジョニングツールについては次回以降の記事で詳しく扱う予定です。

プロビジョニングツールを用いる際は、サーバなどの設定変更はツール経由でのみ行い、手動で設定変更を行うことはチーム内ルールとして禁止しておくという運用方法をとることで各開発者間での環境の差異を少なくするというような工夫が必要になる場合もあります。

仮想環境

開発環境はWindows、本番環境はLinuxといったように、OSから異なるという場合もあります。OSから異なる場合プロビジョニングツールのみでサーバ設定の差分を吸収しきれないこともあるでしょう。

このような場合にはVirtualBoxやHyper-V、KVMといった仮想環境を構築できるツールを用いるのも手です。仮想環境上にLinuxマシンを作成し、プロビジョニングツールを用いて環境設定を行うといった具合です。

仮想環境を扱いやすくしてくれるツールとしてはvagrantがあります。vagrantは仮想マシンの作成やプロビジョニングツールを用いた環境設定、開発マシンと仮想マシンの間のファイルのやり取りや仮想マシンへのポートフォワーディングといった作業をコマンドラインから行えるツールです。

これらのツールを活用することで仮想環境構築も現実的な作業量で行うことが可能となります。

展開時の注意点

Ansibleやvagrantといったツールを用いる場合、ツール用の設定ファイルをメンバー間で展開しやすくする工夫も合わせて必要です。例えばアプリケーションのソースの中にツール用の設定ファイル類を含めた上でgitなどのバージョン管理システムに乗せておくといった方法があります。他にもバージョン管理システムやCI/CDの仕組みと連動して、変更したら各メンバーに通知が届くような仕組みにするというのも手です。

2: 開発用サーバを別途構築する方法

社内のサーバやホスティング/クラウド等を利用して、本番用サーバとは別に、開発用のサーバを用意する方法です。別途サーバを構築するぶんコストはかかりますが、開発者の不在時でも動く状態のサーバを用意しておきたい場合や顧客に対し動作確認用のステージング環境を提供する場合などに有効です。

本番環境と開発用サーバとの環境設定の差異への対応は各開発者のマシンにサーバ構築する場合と同様にプロビジョニングツールを用いるなどの工夫が必要です。

別途マシンを購入したり仮想環境の構築、VPSの契約などでサーバを確保してもよいですし、クラウドを利用することで必要な時だけサーバ構築するという方法もあります。

例えばクラウドであればサーバなどのリソースの操作をAPIを利用して自動化することも可能ですので、GitHub上でPullRequestが作成されたら動作確認用にサーバ構築するというような使い方が可能となります。

3: インターフェース/規格に従うことで影響範囲を限定する方法

ここまではWebサーバやミドルウェア含めて本番環境に近いサーバ環境の構築を行う方法でしたが、特定のインターフェース/規格に従って開発しておくことで本番環境での動作をある程度保証するといった方法もあります。

インターフェース/規格の例としてはPythonでのWSGIがあります。WSGIとは、WebサーバとWebアプリケーションを接続するための仕様で、リクエスト/レスポンスをどのようにやり取りするかを定めたものです。WSGIに対応したWebアプリケーションであれば同じくWSGIに対応したWebサーバ上で動かすことが可能となります。

Python以外でも、RubyであればRack、JavaであればJava EEといったものがあり、これらの仕様に沿ったWebアプリケーション(とフレームワーク)とすることで、同じくこれらの仕様に従っている任意のインフラストラクチャ上でアプリケーションを稼働させることができるようになっています。

開発時はこのインターフェース/規格に従った開発用サーバを用いる(rubyだとrails serverやruckupなど)ことでWebサーバなどのインターフェース/規格の外側のプロビジョニングなどの詳細ついては意識せず作業できる = 開発者の責任範囲を限定する、というのも一つの方法です。

また、近年アプリケーション+実行環境をコンテナとしてパッケージングできる「Docker」もよく利用されるようになっています。Dockerについてもインターフェース/規格に沿って開発者が意識すべき範囲を限定できるという面があります。開発者はアプリケーションをビルドするための環境や実行するための環境をDockerfileを用いてDockerイメージとしてパッケージングすることで、Dockerコンテナを稼働させるインフラストラクチャの詳細を意識せずに作業できます。運用側はDockerコンテナを稼働させることに注力すればよく、アプリケーションの実装の詳細は意識せずに作業できます。

各方法を組み合わせて利用

前述の通り、実際の開発環境構築にあたっては費用や速度、作業負荷などを検討の上でこれらの方法を組み合わせて利用することになります。

<組み合わせ例>

  • 普段の開発は手元のマシンの開発用サーバ(rails serverなど)を利用
  • バージョン管理システムへのチェックイン時は仮想環境やDockerを用いて(本番に近い環境で)テスト
  • レビューを受ける際は別途立てた開発用サーバを利用
  • レビューに通ったらCI/CDを通じてステージング環境にデプロイ

各自の環境や制約、アプリケーションの特性などを考慮して適切な方法を検討してみてください。

まとめ

今回は開発環境構築について扱いました。本番環境で安定稼働することを目指しつつ開発の利便性やコスト面を考慮して開発用サーバを各マシンに構築する方法やその際に利用できるプロビジョニングツールなどを紹介しました。

次回は開発プロセスに密接に関係することとなるバージョン管理システムとバージョン管理システムを利用した開発フローについて扱います。

以上です。