サービス環境での事例も耳にすることが多くなった Docker ですが、皆さんの現場でも活用されてますでしょうか?ヌーラボでは2014年の夏にローンチした開発者向けのウェブサイトである Nulab Developers にて Docker を利用したブルーグリーン・デプロイメントを行っています。本エントリではサイト更新時のワークフローなども含めその全体像を紹介します。
ミドルウェアの構成
上図にあるとおり EC2 インスタンス上にブルーとグリーンの Docker コンテナを常時二つ上げており、同じインスタンス上に nginx がリバースプロキシとして動いています。ウェブサイトの構築には Drupal を利用しており、ブルーとグリーン環境内の Drupal が利用する MySQL のデータベースをおのおの用意しています。Docker のイメージは baseimage-docker に Apache と PHP および Drupal をインストールしています。
ブルーグリーン・デプロイメントの実現方法
ロードバランサー配下のホストを切り替えるやり方がよく例にあげられますが、このサイトでは nginx のリバースプロキシの設定を切り替える形で実現しています。
まず各々の Drupal のコンテナ内の Apache のポートを以下のようにホスト側のポートとマッピングしておきます。
# docker port drupal-blue 80/tcp -> 0.0.0.0:8080 # docker port drupal-green 80/tcp -> 0.0.0.0:8081
この各々のポートに対応する形で nginx では以下のように upstream を定義します。
upstream blue { server localhost:8080; } upstream green { server localhost:8081; }
そしてリバースプロキシの設定では、$upstream 変数を利用するようにしておきます。
location / { proxy_intercept_errors on; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://$upstream; }
この $upstream 変数の定義は upstream_green.conf と upstream_blue.conf として各々 green と blue が $upstream 変数として定義されたものを用意しておきます。そして有効にしたい環境 ( 以下の例では green ) に対して upstream.conf という名前でシンボリックリンクを張ります。
# ls -lt upstream* lrwxrwxrwx 1 root root 41 Mar 24 05:34 upstream.conf -> /usr/local/nginx/conf/upstream_green.conf -rw-r--r-- 1 root root 206 Feb 17 03:52 upstream_green.conf -rw-r--r-- 1 root root 205 Feb 17 03:52 upstream_blue.conf
nginx.conf では upstream.conf を include します。環境を切り替えたいときには、シンボリックリンクを張り替えて nginx を reload すれば OK です。設定ファイルは Ansible 配下で構成管理をしていることもあり、切り替えの度にファイルの中身そのものの書き換えは行わずにすむように、このような方式にしています。
またこの切り替えは Jenkins を利用した ChatOps のエントリで紹介した機能を利用して、 Typetalk からメンバー誰もが行えるようにしています。
サイト更新のワークフロー
さてこれでブルーグリーン・デプロイメントは実現できたわけですが、スタンバイ側のコンテナも活用すべく、それをステージング環境として利用しています。このステージングを利用したサイト更新のワークフローは以下のようになります。
まず開発で利用している Git リポジトリは、2014 年に Drupal Camp Taipei の発表で使ったサンプルとほぼ同じ構成です。このリポジトリでは
- Drupal 本体とモジュール
- Nulab Developers 用のテーマや独自開発したモジュール
- Vagrant / Docker 構成用の Ansible の設定ファイル
が管理されています。Drupal のセキュリティアップデート、スタイルの変更、PHP の設定追加、といった変更が加わった時はいつでも Jenkins が新しく Docker イメージをビルドしてインハウスの Docker レジストリに最新版を push します。そして自動的にステージング環境を新しく生成されたイメージで置き換えます。 そしてステージング環境の確認に問題なければ、ブルーグリーン・デプロイメントを行います。
現在の課題
現状のところ開発環境は Vagrant を利用しており、Docker のメリットとしてよくあげられる「開発で使っている環境をそのまま本番でも使う」事が出来ていません。最近では docker-compose により複数の Docker コンテナの管理も行いやすくなってきてますが、この環境を作りはじめた頃はまだ Drupal と MySQL のコンテナを別々に立ち上げて管理をすることは少し手間のかかることでした。それよりは Vagrant に Drupal や MySQL など必要なものを全てインストールしてしまい、Synced Folder を利用したテーマやモジュール開発のススメ方がマッチしていた、といった理由もあって Vagrant と Docker を併用するやり方になっています。今後の方針としては WordPress を Docker 上で動かす Wocker のように、Vagrant の中で Docker を利用する、といったやり方も検討中です。
また、現在はディスカッション・フォーラムのようなユーザがデータを登録するような仕組みがなく、基本的にはステージング環境側のみでデータの更新をかけることを前提としたワークフローを組んでいます。そのおかげでブルーとグリーンのデータの同期もシンプルに行えるのですが、今後そういった機能を提供する場合にはデータの同期や切り替えといったこともデプロイメントのワークフローに組み込む必要が出てくるかとは考えています。
まとめ
上記はこの Docker のブルーとグリーンの各々のアクセス数のモニタリングの様子です。ブルーグリーン・デプロイメントを行っている雰囲気が伝わりますでしょうか? 幸い今のところ差し戻したことはないですが、ブルーグリーン・デプロイメントでは、問題があればすぐに環境ごと元に戻せるという安心感は大きなものです。A/B テストやデザイン変更などの色々な試行錯誤をスピーディに行いたいウェブサイトでは、大胆なことでも実験しやすくなるためブルーグリーン・デプロイメントがもたらす安心感は大きいように思います。
ステージング環境の自動更新では、いわゆるイミュータブル・インフラストラクチャを体感できました。Git リポジトリに変更を push してから数分もすれば過去の環境が捨て去られ、新しいイメージでステージング環境が更新されるといった事を体験してみて、ようやく Docker のメリットの一つである「速さ」が腑に落ちた感がありました。
ウェブサイトの運用でステージングサイトを利用している方は多いと思いますが、環境を独立させようとすれば、平時はトラフィックが少なくとも専用のサーバが必要になります。それを避けて同一サーバ内で複数サイトを管理しようとすると、たとえば Apache や PHP のバージョンをあげる事が簡単には出来ません。今回のように 同一サーバ内で Docker で環境は分離しながら運用することで、コストもおさえつつステージング側では大胆な実験も出来る、というのは良い形のように思います。
これまでサービスを AWS で運用してきた経験から、一つの EC2 インスタンスに色々な役割を持たせるのはスケーラビリティや耐障害性を考えて避けてきました。そのためミニマムな構成で環境構築をする際も、結果としてある程度の台数のインスタンスを用意していました。Docker を利用すればコンテナの独立性を担保し将来的にもスケールし易い構成を保ちつつ、最初はリソースは小さめに抑えることも出来るのでは、と考えています。
ヌーラボではまだ Docker のサービスにおける導入はまだすすんでいません。ただ、アプリケーション開発技術と同様に、こういったインフラ側の技術も現場で活用してみて見えてくる部分も多く、今回ご紹介したワークフローをひと通り組んでみることで色々な知見を得ることができました。今ではこの開発者向けのウェブサイトでの導入に引き続き、CI 環境の一部でも Docker の活用がはじまってます。
こういったインフラ方面からヌーラボ全体のサービスを支え、より良いワークフローを一緒に作り上げていただけるインフラエンジニアの方を絶賛募集中です。ご興味のある方はこちらの採用ページを是非ご覧ください!