ども、cloudpack の デプロイ市民の かっぱ (@inokara) です。
はじめに
とりあえず AWS CodeDeploy で docker run
出来るので docker run
で Web サーバーを上げておいて HAProxy のバックエンドに自動的に追加させるところまでを AWS CodeDeploy で一気にやってみたいと思ったので、まずは HAProxy のバックエンドを自動で登録する方法の確認を行います。
尚、HAProxy のバックエンドへの自動登録については以前、consul-haproxy ツールが紹介されていたのですが、現在は consul-template に内包されてしまっているようですので、こちらのツールにて行ってみたいと思います。
参考
- progrium/registrator
- hashicorp/consul-template
- Consul Template + Registrator で、コンテナ上のWebサーバをHAProxyへリアルタイムに登録してみる
Consul の用意
Consul とは?
これについては Qiita 内に蓄積されている Consul の各記事を御覧ください。
Consul のインストールと起動
インストールはとても簡単です。
wget https://dl.bintray.com/mitchellh/consul/0.4.1_linux_amd64.zip
で取得して…
./consul agent -server -bootstrap -client=127.0.0.1 -dc=local -node=consul1 -data-dir=/tmp/consul -bind=127.0.0.1 &
起動します。今回はお試しで一台で server と agent を担います。
試しにサービス登録
以下のようにして Consul にサービスを登録してみます。
$ cat << EOT | curl -XPUT http://127.0.0.1:8500/v1/agent/service/register -d @- { "ID": "web-app", "Name": "web-app", "tags": ["web-app"], "port": 80 } EOT
登録されたサービスを確認してみます。
$ curl -s http://127.0.0.1:8500/v1/catalog/services | jq . { "consul": [], "web-app": [ "web-app" ] }
web-app
が登録されていますね。
さらに web-app
サービスに登録されているノード情報等を確認するには以下のように実行します
$ curl -s http://127.0.0.1:8500/v1/catalog/service/web-app | jq .
consul-template とは
Consul に登録されているサービスの一覧を取得して各ミドルウェアの設定ファイルを自動的に生成してくれるツールのようです。
サービスとして起動させることで consul に登録されるサービスを監視してサービスノードの増減に応じて対象となる設定ファイルを書き換えてサービスを起動します。
consul-temaplate を使ってみる
consul-template のインストール
こちらも Consul 同様にインストールは簡単です。
wget https://github.com/hashicorp/consul-template/releases/download/v0.3.0/consul-template_0.3.0_linux_amd64.tar.gz tar zxvf consul-template_0.3.0_linux_amd64.tar.gz
以上です。簡単ですな。
サービスを展開する
先ほど登録したサービスを HAProxy の設定ファイルに展開してみたいと思いますので、以下のようなテンプレートファイルを用意します。
global daemon maxconn 1024 defaults mode http timeout 300 listen http-in bind *:8000{{range service "release.webapp"}} server {{.Node}} {{.Address}}:{{.Port}}{{end}}
{{...}}
で囲まれている部分は Go のテンプレートになります。
以下のように consul-template を実行します。
./consul-template -consul 127.0.0.1:8500 -template haproxy.ctmpl:./hoge -dry
以下のように出力されました。
global daemon maxconn 1024 defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms listen http-in bind *:8000 server consul1 127.0.0.1:80
おお、先ほど登録したサービスが server consul1 127.0.0.1:80
として展開されていることが判ります。
Docker コンテナの用意
Sinatra で Web アプリケーションを用意する
以下のような簡単なアプリケーションを起動するにコンテナに仕込んでおきます。
require 'json' require 'sinatra' get '/' do http_headers = request.env.select { |k, v| k.start_with?('HTTP_') } "#{http_headers}""n" end
このアプリケーションを docker run
時に起動出来るように /root/web.sh
というファイル名で以下のようなシェルスクリプトを用意しておきます。
#!/usr/bin/env bash cd /opt/app ruby -rubygems test.rb -o 0.0.0.0 -p 8081
試しに起動する
docker run -t -d -p 8081 test_app /root/web.sh
引続き、以下のようにバインドされているポートを確認してアクセスを試します。
$ docker run -t -d -p 8081 test_app /root/web.sh e94c75a1539887a7f4102e056bf72037c65fb670515191b5c4e50f1dff55347f $ docker port e94c75a1539887a7f4102e056bf72037c65fb670515191b5c4e50f1dff55347f 8081 0.0.0.0:49190 $ curl localhost:49190 {"HTTP_USER_AGENT"=>"curl/7.38.0", "HTTP_HOST"=>"localhost:49190", "HTTP_ACCEPT"=>"/", "HTTP_VERSION"=>"HTTP/1.1"}
おお。
consul-template との連携
連携のシェルスクリプト
以下のようにコンテナを起動して consul にサービスとして登録するようなスクリプトをサクッと書きました。
#!/usr/bin/env bash ID=docker run -t -d -p 8081 test_app /root/web.sh
echo $ID PORT=docker port ${ID} 8081 | sed s/0.0.0.0://g
cat << EOT | curl -XPUT http://127.0.0.1:8500/v1/agent/service/register -d @- { "ID": "web-app_${ID}", "Name": "web-app", "tags": ["web-app"], "port": ${PORT} } EOT
consul-template の起動
consul-template は以下のように起動しておきます。
./consul-template -consul 127.0.0.1:8500 -template haproxy.ctmpl:/etc/haproxy/haproxy.cfg:service haproxy restart &
demo
上記の test.sh を実行するとコンテナの起動と consul へのサービス登録が行われます。
./test.sh
以下のように出力されました。
$ ./test.sh 11870daf56ef96d9609de05b4d3b1b9a2184b610d5969696566b4deba220ed01 $ 2014/11/17 01:23:18 [INFO] agent: Synced service 'web-app_11870daf56ef96d9609de05b4d3b1b9a2184b610d5969696566b4deba220ed01' Stopping haproxy: [ OK ] Starting haproxy: [ OK ]
上記のように HAProxy の再起動まで一気通貫で行われました。
一応、サービスが登録されていることを確認します。
$ curl -s http://127.0.0.1:8500/v1/catalog/service/web-app | jq . [ { "Node": "consul1", "Address": "127.0.0.1", "ServiceID": "web-app_11870daf56ef96d9609de05b4d3b1b9a2184b610d5969696566b4deba220ed01", "ServiceName": "web-app", "ServiceTags": [ "web-app" ], "ServicePort": 49191 } ]
また、HAProxy の設定も確認してみます。
global daemon maxconn 1024 defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms listen http-in bind *:8000 server consul1 127.0.0.1:49191
ちゃんと登録されていますね。
HAProxy が Listen しているポートにアクセスしてみます。
$ curl localhost:8000 {"HTTP_USER_AGENT"=>"curl/7.38.0", "HTTP_HOST"=>"localhost:8000", "HTTP_ACCEPT"=>"/", "HTTP_VERSION"=>"HTTP/1.1"}
おおっちゃんとアクセス出来ました!
すげえ。
最後に
ということで…
CodeDeploy で色々とやる為の事前準備として Consul と consul-template と Docker を組み合わせて HAProxy のバックエンドを自動追加してみました。
consul 自体をちゃんと勉強する必要はありますが、クラスタを動的に構築したい場合等は consul-template は色々と使えそうなツールだと思いました。
ちなみに…docker run
して HAProxy への自動登録を CodeDeploy でヤル意味あんのかってところはとりあえず無視で…(汗
元記事はこちらです。
「Docker + consul-template で HAProxy のバックエンド登録の自動化を試す」