log.fstn

技術よりなことをざっくばらんにアウトプットします。

Consul Template + Registrator で、コンテナ上のWebサーバをHAProxyへリアルタイムに登録してみる

はじめに

先日、Consul Templateという便利そうなツールがHashiCorpから発表されました。 Introducing Consul Template - HashiCorp

何かおもしろいこと出来ないかなっと思ってちょっと考えていたら、Registrator(progrium/registrator · GitHub)と相性が良さそうだったので組み合わせて使ってみた、というはなしを本エントリでまとめました。

Consul Template について

Consul Templateは、Consulに登録されているサービスやK/Vの内容を元に、ミドルウェア等の設定ファイルを生成するためのツールです。 また、Consulを常に監視し、内容が変化するとリアルタイムに設定ファイルを更新して指定したコマンドを発行することができます。

ユースケースとして、HAProxy配下にWebサーバを配置する構成での利用が挙げられています。
この構成をとる場合、HAProxyの設定ファイルには対象のWebサーバを全て記述する必要があり、 Webサーバを追加するときや削除するときはその度に設定ファイルを更新して、リロードしてやる必要があります。 しかしConsul Template を利用すると、

  • WebサーバのConsulのクラスタへのJoinやLeaveを検知
  • HAProxyの設定ファイルを更新
  • リロードして設定を反映

これらを全て簡単に自動で行えるようになります。

なおテンプレートは、template - The Go Programming Language の記述に従って柔軟に書くことが出来ます。

詳しい使い方や仕様に関しては、上記の記事かレポジトリを直接参照してください(相変わらずREADMEがしっかりしてる)。
hashicorp/consul-template · GitHub

Registrator について

Registratorは、Dockerで立ち上げたコンテナに関する情報を、Consul や etcd、SkyDNS 2へ登録するためのツールです。

詳しい使い方や仕様に関しては、レポジトリを直接参照してください(こちらのREADMEもかなり丁寧です)。

progrium/registrator · GitHub

概要

今回はタイトルにあるように、Consul TemplateとRegistratorを組み合わせて、コンテナ上のWebサーバをHAProxyへリアルタイムに登録してみます。

f:id:foostan:20141026021814p:plain

1台のマシン上で

  • Docker
  • Consul
  • Consul Template
  • Registrator
  • HAProxy

を動かし、その上にWebサーバを提供するコンテナを立ち上げます。 サービスへのエンドポイントはこのサーバ(今回の場合192.168.33.11)の80ポートとなります。 なお通常だと、コンテナでサービスを提供する場合はコンテナ側のポートを意識する必要がありますが、Registratorを利用することで意識しないで済みます。

環境構築

上図の環境を構築していきます。

VMの準備

VagrantVMを1台建てて、

  • Docker
  • Consul
  • Consul Template
  • Registrator

をインストールします。

$ git clone https://github.com/foostan/consul-with-docker.git
$ cd consul-with-docker
$ vagrant up

十数分待つとできあがり。
※ ansibleの実行環境が必要

以降はこのVM内で作業します。

$ vagrant ssh
vagrant@node-1:~$ 

Consul agent 起動

今回は1台しか使わないので、-server-bootstrap オプションを付けておきます。

vagrant@node-1:~$ consul agent -data-dir=/tmp/consul -server -bootstrap
==> WARNING: BootstrapExpect Mode is specified as 1; this is the same as Bootstrap mode.
==> WARNING: Bootstrap mode enabled! Do not enable unless necessary
==> WARNING: It is highly recommended to set GOMAXPROCS higher than 1
==> Starting Consul agent...
==> Starting Consul agent RPC...
==> Consul agent running!
         Node name: 'node-1'
        Datacenter: 'dc1'
            Server: true (bootstrap: true)
       Client Addr: 127.0.0.1 (HTTP: 8500, DNS: 8600, RPC: 8400)
      Cluster Addr: 10.0.2.15 (LAN: 8301, WAN: 8302)
    Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false

Consul template 起動

vagrant@node-1:~$ sudo consul-template\
 -consul=localhost:8500\
 -template=/vagrant/haproxy.ctmpl:/etc/haproxy/haproxy.cfg:"/etc/init.d/haproxy reload"

template.ctmpl の内容はこちら

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    user  haproxy
    group haproxy
    daemon

defaults
    log    global
    mode   http
    option httplog
    option dontlognull
    contimeout 5000
    clitimeout 50000
    srvtimeout 50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

frontend  main *:80
    default_backend    tinyweb

backend tinyweb
    balance roundrobin{{range service "tinyweb"}}
    server {{.ID}} {{.Address}}:{{.Port}} check{{end}}

デフォルトのhaproxy.cfgにfrontendbackendを追記しています。

Registrator 起動

vagrant@node-1:~$ registrator consul:

以上で準備完了です。

Webサーバイメージの作成とコンテナの起動

HAProxy で振り分ける先となるWebを構築していきます。

イメージ作成

これ用のDockerfileを用意したので、ビルドしてイメージを作成します。

vagrant@node-1:~$ docker build -t tinyweb /vagrant/tinyweb/

Dockerfileの中身はこちら

FROM ubuntu:trusty

MAINTAINER foostan ks@fstn.jp

EXPOSE 80

CMD while true; do ( echo "HTTP/1.0 200 Ok"; echo; echo `hostname` ) | nc -l 80; done

trustyをベースにして、ncコマンドで hostname を返すWebサーバを80ポートに立ちあげています。

コンテナの起動

docker run -p 80 -d tinyweb
c437b2717b76dde8c31211fea09bc5bb60b8c16892161db24cb31a1b49543ae1
vagrant@node-1:~$ docker ps
CONTAINER ID        IMAGE                    COMMAND                CREATED             STATUS              PORTS                   NAMES
c437b2717b76        foostan/tinyweb:latest   "\"/bin/sh -c 'while   5 minutes ago       Up 5 minutes        0.0.0.0:49178->80/tcp   romantic_carson

動作確認

コンテナを立ち上げた時点で、RegistratorによってConsulにserviceが追加され、Consul Templateによって、HAProxyの設定ファイルが更新されています。

Consulのserviceを見てみます。

$ curl -s localhost:8500/v1/catalog/services | jq .
{
  "consul": [],
  "tinyweb": []
}
vagrant@node-1:~$ curl -s localhost:8500/v1/catalog/service/tinyweb | jq .
[
  {
    "Node": "node-1",
    "Address": "10.0.2.15",
    "ServiceID": "node-1:romantic_carson:80",
    "ServiceName": "tinyweb",
    "ServiceTags": null,
    "ServicePort": 49178
  }
]

tinywebサービスが新たに追加され、ノードのIPやPortが登録されていることが確認できます。

続いて、HAProxyの設定ファイルを見てみます。

vagrant@node-1:~$ tail -n 7 /etc/haproxy/haproxy.cfg

frontend  main *:80
    default_backend    tinyweb

backend tinyweb
    balance roundrobin
    server node-1:romantic_carson:80 10.0.2.15:49178 check

登録されていることがわかります。

実際にアクセスしてみます。

vagrant@node-1:~$ curl localhost
c437b2717b76

VM外からでももちろんOK

$ curl 192.168.33.11
c437b2717b76

複数のコンテナを立てたり消したりしてみる

5台追加してみる。

vagrant@node-1:~$ docker run -d -p 80 foostan/tinyweb
df9d19738e7610c448478c94ec10ab63259a2c78cfbe6437de2d3e7a8870b63e
vagrant@node-1:~$ docker run -d -p 80 foostan/tinyweb
b7ddc05c645490c21c18b98161bef0994b9c2ad366ff6e85a0b45652ff204e6d
vagrant@node-1:~$ docker run -d -p 80 foostan/tinyweb
0c31735035d4da4519ebbe7a6957ddb9bc1f865e5448c9ab838a742bff3178d3
vagrant@node-1:~$ docker run -d -p 80 foostan/tinyweb
8be6547a4a418faf34be1727b40386c149dd34d41ce5f8efb8c37d37050849ee
vagrant@node-1:~$ docker run -d -p 80 foostan/tinyweb
a7969a2dfa63d137d77369b5e9c519b5565ec0bc2b14126c300b24c11c25deb5

HAProxyの設定に反映されていることが確認できます。

vagrant@node-1:~$ tail -n 12 /etc/haproxy/haproxy.cfg

frontend  main *:80
    default_backend    tinyweb

backend tinyweb
    balance roundrobin
    server node-1:hopeful_newton:80 10.0.2.15:49181 check
    server node-1:hopeful_torvalds:80 10.0.2.15:49179 check
    server node-1:naughty_elion:80 10.0.2.15:49182 check
    server node-1:romantic_carson:80 10.0.2.15:49178 check
    server node-1:sad_darwin:80 10.0.2.15:49180 check
    server node-1:thirsty_kowalevski:80 10.0.2.15:49183 check

各コンテナにアクセスしていることがわかります

$ curl 192.168.33.11
0c31735035d4
$ curl 192.168.33.11
df9d19738e76
$ curl 192.168.33.11
8be6547a4a41
$ curl 192.168.33.11
c437b2717b76
$ curl 192.168.33.11
b7ddc05c6454
$ curl 192.168.33.11
a7969a2dfa63

削除も問題ないです

vagrant@node-1:~$ docker kill a7969a2dfa63 b7ddc05c6454 c437b2717b76
a7969a2dfa63
b7ddc05c6454
c437b2717b76
vagrant@node-1:~$ tail -n 9 /etc/haproxy/haproxy.cfg

frontend  main *:80
    default_backend    tinyweb

backend tinyweb
    balance roundrobin
    server node-1:hopeful_newton:80 10.0.2.15:49181 check
    server node-1:hopeful_torvalds:80 10.0.2.15:49179 check
    server node-1:naughty_elion:80 10.0.2.15:49182 check

おわりに

Consul TemplateとRegistratorの相性が予想以上によく検証もすんなり出来ました。 今回はConsul Templateの一例を載せましたが、汎用性が高いため、まだまだ色々できそうです。

本エントリがConsulやDockerを使用する上で、何かの参考になれば幸いです。