概要
vulcand という HTTP プロキシを使って Docker コンテナをブルーグリーンデプロイするという話。
Consul と Nginx を組み合わせて動的にロードバランスするという話とやりたいことは同じだと思う。
vulcand とは
vulcand は、Mailgun というメール系 SaaS の開発チームが作った HTTP プロキシ。
- etcd をバックエンドに利用した HTTP プロキシ
- 再起動なしで設定を反映できる
- HTTP API と CLI
- プラガブルなミドルウェア
- ゼロダウンタイムデプロイのサポート
- リアルタイムメトリクスレポート
- TLS と certificate の管理
といった特徴を持つ。設定ファイルを etcd に保存して再起動なしで設定反映できるというのが非常に便利なポイントだと思う。
vulcand の仕組み
vulcand に 以下の 2 つの主要な概念がある。
- locations
- upstreams
Location
Location はホスト名とリクエストパスの組み合わせからなり、名前を持つ。リクエストされた URL に対して正規表現マッチが行われる。
例
-
search
という名前の location でexample.com
を host として/search
を正規表現マッチャとして使う -
user
という名前の location でexample.com
を host として/^users.*$/
を正規表現マッチャとして使う
そして Location は後述する upstream を持ち、正規表現マッチしたリクエストをupstreams へプロキシする。
Upstream
Upstream は後述する endpoint の集合であり、名前を持つ。
例
-
search-backend
という名前の upstream で endpoint はhttp://10.10.1.2:8080
とhttp://10.10.1.3:8080
Endpoint
Endpoint は最終的にリクエストを処理するところ。 <schema>://<host>:<port>
形式で定義する
例
http://localhost:5000
Vulcand を使って Docker コンテナのブルーグリーンデプロイ
Vagrant で起動した CoreOS マシン上の vulcand に OS X から接続してブルーグリーンデプロイを試す。
イメージ図:
例として、example
というアプリケーションがあるとして、v1 から v2 への切り替えをするデプロイをする。
OS X 側の hosts を設定しておく
# on CoreOS
core@core-01 ~ $ cat /etc/environment
COREOS_PUBLIC_IPV4=172.17.8.101
COREOS_PRIVATE_IPV4=172.17.8.101
# on OS X
$ sudo vi /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
172.17.8.101 example.com # 追加
サービスコンテナ v1 の起動
example アプリケーションコンテナの v1 を2 台起動する
# on CoreOS
core@core-01 ~ $ docker run -d --name example-v1.1 -p 8086:80 coreos/example:1.0.0
0940df1b68a823e68d165196a7fde12922b6c57ff6b4ad95441a2fa9fd64a95b
core@core-01 ~ $ docker run -d --name example-v1.2 -p 8087:80 coreos/example:1.0.0
e35ed7de9766ae67e14bc05f95e5c1a207d74b03e3dd4f350b99192c4ff51845
Upstream example-v1
の設定
続いて、example-v1.1
, exaple-v1.2
を endpoint とする example
という upstream をセットする。
# on CoreOS
core@core-01 ~ $ etcdctl set /vulcand/upstreams/example-v1/endpoints/1 http://172.17.8.101:8086
http://172.17.8.101:8086
core@core-01 ~ $ etcdctl set /vulcand/upstreams/example-v1/endpoints/2 http://172.17.8.101:8087
http://172.17.8.101:8087
Location の設定
home
という名前の location を作成する。正規表現マッチャは /.*
つまり全てのリクエストをマッチさせる。
# on CoreoS
core@core-01 ~ $ etcdctl set "/vulcand/hosts/example.com/locations/home/path" '/.*'
/.*
そして home
location を example-v1
upstream にプロキシさせるようセットする
# on CoreOS
core@core-01 ~ $ etcdctl set /vulcand/hosts/example.com/locations/home/upstream example-v1
example-v1
vulcand コンテナの起動
# on CoreOS
core@core-01 ~ $ docker run \
--rm \
--name vulcan \
-p 80:80 \
-p 8182:8182 \
mailgun/vulcand \
/opt/vulcan/vulcand \
-apiInterface="0.0.0.0" \
-interface="0.0.0.0" \
-etcd="http://172.17.8.101:4001" \
-port=80 \
-apiPort=8182
アクセスしてみる
http://example.com
にアクセスしてみる。example アプリケーションの v1 が見れた :)
サービスコンテナ v2 の起動
# on CoreOS
core@core-01 ~ $ docker run -d --name example-v2.1 -p 8088:80 coreos/example:2.0.0
8aa0f8cd402fa8be29b96f37bc97a2899bb32510cc3a8899d1338d0f8c8e1040
core@core-01 ~ $ docker run -d --name example-v2.2 -p 8089:80 coreos/example:2.0.0
8db14040b1207ec42a5c08236bd4c7214323db36058d47e77606256231b6f5e8
upstream example-v2
の設定
# on CoreOS
core@core-01 ~ $ etcdctl set /vulcand/upstreams/example-v2/endpoints/1 http://172.17.8.101:8088
http://172.17.8.101:8088
core@core-01 ~ $ etcdctl set /vulcand/upstreams/example-v2/endpoints/2 http://172.17.8.101:8089
http://172.17.8.101:8089
v1 から v2 に切り替え
# on CoreOS
core@core-01 ~ $ etcdctl set /vulcand/hosts/example.com/locations/home/upstream example-v2
再度アクセスしてみる
example アプリケーションの v2 になってる :)
ゼロダウンタイムブルーグリーンデプロイ。
ここでまた
# on CoreOS
core@core-01 ~ $ etcdctl set /vulcand/hosts/example.com/locations/home/upstream example-v1
とすれば v1 のコンテナにプロキシされてロールバックができる。
ローリングデプロイ
上記の例だと、home
location へ紐づける upstream
を example-v1
から example-v2
に切り替えてデプロイを行ったが、upstream
を固定して、endpoint を追加・削除することでローリングデプロイも可能。
TODO: registrator を使って upstream の自動登録をする
registrator または docker-plugin を使って、コンテナの start
hook 時に etcd に起動 IP と Port を登録する
メモと感想
HA 構成できる
etcd から設定を読むので、HA 構成が実現できそう。例えば AWS で 3 台からなる CoreOS クラスタがあるとき、全台で vulcand を起動しておき、vulcand の前段に ELB を置く事で、
- Docker ホストレベル(=EC2 インスタンス)のロードバランスを ELB に
- Docker コンテナレベルのロードバランスを vulcan に
やらせることで割とシンプルな構成にできそう。
# requests:
# - www.example.com
# - admin.example.com
# - search.example.com
vulcan.1 on coreos.1
/ --> upstream `search`
/ /
request --> ELB --- vulcan.2 on coreos.2 ---> upstream `admin`
\ \
\ --> upstream `www`
vulcan.3 on coreos.3
Nginx と比べて
- コンテナとして動かすのに向いている
- プロキシとしての機能は nginx と比べると乏しい?
コンテナとして動かすことについて
nginx がコンテナとして動かそうと思うと後から設定をダイナミックには変更しづらい。なので、Docker ホスト側に Nginx をインストールすることになる。なるだけ全てをコンテナでやりたいと思うとこれは微妙。
頑張ってコンテナでやろうとするなら
- コンテナを Nginx として動かすが設定ファイルを -v でホストと共有して docker exec で nginx を reload
- コンテナを Nginx として動かすが、設定変更時は起動スクリプトに環境変数や引数を渡して動的に設定ファイル作ってコンテナ再起動
といった感じでできなくもないと思うが、とても複雑(他にもやり方はあると思う)
TODO: プロキシとしての機能について
ドキュメントまだ全部読めてない。deis は「色々足りてないからまだ Nginx 使うよ」 って言ってる。