CoreOSクラスタ内のDockerコンテナの動的リンク
Dynamic Docker links with an ambassador powered by etcd
CoreOSのクラスタ内で複数ホスト間にまたがりDockerコンテナを連携させる方法について検証した.
複数ホストにまたがりDockerのコンテナを接続する方法としてはAmbassador パターンが有名である.これはトラフィックを別ホストへforwardすることに特化したコンテナを立てる方法で,ホストに無駄な設定なし,かつDockerコンテナのみで行えるシンプルな方法である.例えば,あるホストからredis-cliを使って,別ホストで動くredisに接続する場合は以下のように接続する.
1
| |
redis-cliコンテナとambassadorコンテナ,redisコンテナとambassadorコンテナはdockerのlink機能で接続し,ambassadorコンテナはトラフィックをネットワーク越しにフォワードする.
この方法は,接続側がその相手先のホストを知っている必要がある.例えば上記の場合,redis-cliコンテナ側のambassadorコンテナは以下のように相手先のホストのIP(e.g., 192.168.1.52)を指定して起動しなければならない.
1
| |
ホストが固定されている場合は問題ないが,CoreOSのように動的にホストが変わる可能性がある場合は問題になる.
CoreOSはクラスタの形成に分散Key-Valueストアであるetcdを使っている.そこに接続先のホスト情報を保存し続けることで,この問題を解決することができる.
想定する接続の例
Link via an Ambassador Containerと同様の例を用いる.クラスタ内のあるホストよりredis-cliコンテナを使って,別ホストのredisコンテナに接続する.
コンテナ
全部で5つのコンテナを用いる.
https://coreos.com/assets/images/media/etcd-ambassador-hosts.png
HostA (redisを動かすホスト)
- crosbymichael/redis - Ambassador パターンで使われているものと同様のRedisコンテナ
- polvi/simple-amb -
socatコマンドを使って,特定のポート(10000)のトラフィックを与えられたホストにforwardするだけのコンテナ.etcdへのフォーワードに利用する. - polvi/docker-register -
docker portコマンドを使って与えられたDockerコンテナのIPとPortを取得し,etcdにそれを登録するコンテナ
HostB (redis-cliを動かすホスト)
- polvi/simple-amb - HostAと同様のコンテナ.etcdへのフォーワードに利用する.
- polvi/dynamic-etcd-amb - etcdからRedisコンテナのホストとIPを取得し,環境変数にそれを設定するコンテナ.複数ホストが得られたらラウンドロビンする.
- relateiq/redis-cli - Ambassador パターンで使われているものと同様のコンテナ
Unitファイル
CoreOSはコンテナの管理とスケジューリングにFleetを用い,その設定はsystemdにFleet特有の設定を加えたUnitファイルで行う(詳しくは,“Fleetの使い方,Unitファイルの書き方”に書いた).
上述したDockerを起動するためのUnitファイルについて簡単に説明する.
HostA
crosbymichael/redisを動かすためのredis.serviceは以下.
1 2 3 4 5 6 7 8 9 10 11 12 | |
単純にredisコンテナを起動するだけ.polvi/docker-registerを使って,ホストのIPとPortをetcdに登録する必要があるので,-p ${COREOS_PRIVATE_IPV4}::6379を指定して起動する.CoreOSはそのホスト情報を/etc/environmentに保存しているので,それをそのまま使える.どのホストかを直接指定する必要はない.また,%nはsystemdのUnitファイルの記法で,そのファイル名が代入される(今回の場合は,redis.service).
polvi/simple-ambを動かすためのetcd-amb-redis.serviceは以下.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
このコンテナは特定のポート(10000)のトラフィックを与えられた引数のホストにforwardする.CoreOSのDockerコンテナからは172.17.42.1:4001でそのetcdにアクセスできる.引数にそれを与えることで,10000portへのトラフィックはすべてetcdにforwardされるようになる.
X-ConditionMachineOfにredis.serviceを指定することで,このコンテナは,redisコンテナと同じホストにスケジューリングされるようになる.
polvi/docker-registerのregister-redis-etcd.serviceは以下.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
このコンテナは与えられたコンテナのホストにおけるIPとPortのマッピング情報を取得し,それをetcdに登録する.今回はredisコンテナの6379portのホストにおけるIPとPortのマッピング情報をredis-Aという名前でetcdに登録する.polvi/docker-registerとlinkで接続することにより,環境変数でetcdの接続先を取得する.
X-ConditionMachineOfにredis.serviceを指定することで,このコンテナは,redisコンテナと同じホストにスケジューリングされるようになる.
HostB
polvi/simple-ambを動かすためのetcd-amb-redis-cli.serviceは以下.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
内容はHostAのetcd-amb-redis.serviceと同様だが,スケジューリングの条件が異なる.X-Conflictsにredis.serviceを指定することでredisコンテナとは異なるホストにスケジューリングされるようになる.
polvi/dynamic-etcd-ambのredis-dyn-amb.serviceは以下.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
このコンテナはetcdに保存されたホストへのプロキシとして動作する.6379portを解放し,そこへの接続をredis-Aという名前でetcdに登録されたredisコンテナが動くIPとPortに向けるようにする.polvi/docker-registerとlinkで接続することにより,環境変数でetcdの接続先を取得する.
redis-cliコンテナは,このコンテナと接続することで,ネットワーク越しにredisコンテナに接続する.
クラスタを立てる
利用するクラスタはtcnksm/vagrant-digitalocean-coreosを使って,VagrantでDigitalOcean上に立てる.使い方は,“CoreOSに入門した | SOTA”を参考.
1 2 | |
これで,DigitalOcean上に3つのCoreOSインスタンスが立ち上がる.
接続を試す
上述したUnitファイルで定義したサービスをCoreOSクラスタにデプロイしredisコンテナに接続してみる.
まず,サービスのデプロイする..serviceファイルがあるディレクトリで以下を実行する.
1
| |
サービスの起動を確認する.Unitファイルで定義したように別々のホストでサービスが起動していることが確認できる.
1 2 3 4 5 6 7 | |
redisコンテナに接続するには,etcd-amb-redis-cliコンテナが動いているホストに移動する必要がある.以下で移動できる.
1
| |
実際に接続してみる.
1 2 3 | |
何が起こっているのか
この時何が起こっているのかをそのログで確認してみる.まず,etcdに保存されている情報を確認してみる.
1 2 | |
Redis-Aにredis.serviceが動いているホストとIPが保存されている.
次にregister-redis-etcd.serviceのログを見てみる.
1 2 | |
etcdにホストのIPとPortをポストしているのがわかる.
最後にregister-redis-etcd.serviceのログを見てみる.
1 2 | |
etcdからホストのIPとPortを取得しているのがわかる.
耐障害性の確認
redisコンテナを再起動してもすぐに設定は更新され再接続できる.これらは,redisコンテナが動くホスト情報のetcdへの動的な書き込み,読み込みにより実現できている.
また,redisコンテナが動くホストを,ホストごと殺しても再び接続できる.これは,fleetによるフェイルオーバー(再スケジューリング)とetcdの動的に書き込み・読み込みにより実現できる.
まとめ
CoreOSのクラスタ内で複数ホスト間にまたがりDockerコンテナを連携させる方法について検証した.etcdに接続先のホストを保存することで,コンテナがどのホストで動いているかを意識しないでそれに接続することができた.