概要
ECS + awsvpc + Consul でService Discoveryができるようにします。
最終的にConsulにDNS問い合わせすることでECSのコンテナのIPを知ることができるようにします。
環境
- Consul 1.1.0
Task Definition
結論を先にいうと以下のようになります。
[ { "name": "consul-agent", "image": "consul:1.1.0", "memoryReservation": 128, "network_mode": "awsvpc", "environment": [ { "name": "CONSUL_LOCAL_CONFIG", "value": "{\"service\":{\"name\":\"api\",\"tags\":[\"development\"]}}" }, { "name": "CONSUL_BIND_INTERFACE", "value": "eth0" } ], "command": [ "agent", "-retry-join", "consul-1a-01.example.io", "-retry-join", "consul-1c-01.example.io", "-retry-join", "consul-1d-01.example.io" ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-region": "ap-northeast-1", "awslogs-group": "dev-consul" } } }, { // APIコンテナ } ]
ポイントとしては以下で
- network_modeを
awsvpc
に CONSUL_LOCAL_CONFIG
でサービスのconfigを設定CONSUL_BIND_INTERFACE
でbindするNICをeth0
に指定
どうしてこういった設定になったかを下で説明します。
注意したところ・ハマったところ
Consulにconfigを渡すのにどうすればよいか
KubernetesであればConfigMapという仕組みがあるので、Podにconfigファイルをマウントする、といったことが簡単に行なえます。
しかしECSではあらかじめホストに置いておくなりしておかないといけないため、ファイルとしてconfigを渡すのが難しいです。
なのでConsulのconfigを極力コマンドライン引数や、CONSUL_LOCAL_CONFIG
という環境変数で埋めるようにしました。
join対象を複数もたせる
configファイルではretry_join
フィールドは配列なので簡単に設定できますが、↑にあるようにコマンドライン引数の場合どうすればよいのかドキュメントを読んでも分かりませんでした。
いろいろ試した結果
$ consul agent -retry-join domainA -retry-join domainB -retry-join domainC
のように、-retry-join
を複数回書くことで実現することができました。
ログには
2018/05/31 06:58:20 [INFO] agent: (LAN) joining: [domainA domainB domainC]
のように表示されてjoin対象を複数ドメインにすることができてることが確認できます。
Multiple private IPv4 addresses found.
最初に起動したとき、
==> Multiple private IPv4 addresses found. Please configure one with 'bind' and/or 'advertise'.
というエラーが起きました。NICが複数あり、Private IPが複数あるとConsul agentは起動できないというエラーです。
どうやらawsvpcで起動したコンテナは内部でNICを複数持っているようです。
ECSのインスタンス上ではdocker0
やらecs-bridge
が確認できるので、コンテナ側も通信のためそういったNICがあるのかもしれません。
しかしながらエラーメッセージのアドバイスどおりにbind
でPrivate IPを固定すると言っても起動までそのIPを知ることはできません。
そこでCONSUL_BIND_INTERFACE
という環境変数でNICをeth0
に指定することで対応しました。
対応後は以下のようにうまくいきました。
==> Found address '10.11.200.156' for interface 'eth0', setting bind option... ==> Starting Consul agent... ==> Consul agent running!
Consul ServerのDNS参照時のロードバランシングができない
AWSのLBはどれもUDPに対応していません。
またRoute53はUDPに対応していますがヘルスチェッカーはVPC外なのでパブリックIPが必要です。
なので内部だけでConsul serverを立てている場合はNginxなどのProxyを自前で立てるしかありません。