概要
あるホストで動作している Docker コンテナから別のネットワークにある別ホスト上で動作しているコンテナをリンクしたい.しかし,ネットワーク間の通信は信頼できないためセキュアな通信を張る必要がある.本来ならば,VPNを用意してオーバーレイネットワークを構築すべきかもしれないが,小規模な実験的プロジェクトのため,SSHトンネルとAmbassadorパターンで解決する.
AmbassadorS
AmbassadorS は Ambassador パターンを SSH トンネル上で実行するための Docker イメージである.
現在,Alpine Linux ベースのイメージと Raspberry Pi 用に Raspbian ベースのイメージの二種類を公開している.以下では,Alpine Linux ベースの jkawamoto/ambassadors
を使う場合を考える.(Raspberry Pi から利用する場合は jkawamoto/rpi-ambassadors
を使う.)
AmbassadorS には,サーバ,クライアントそしてトンネルの三つのモードがある.それぞれ次のように接続して使用する.
つまり,リンク先のコンテナが走っているホスト上にサーバモードの AmbassadorS コンテナを走らせ,リンク元のコンテナが走っているホスト上でクライアントモードとトンネルモードの AmbassadorS コンテナを走らせる.
リンク先のコンテナが複数ある場合でも,各ホストにサーバモードのコンテナは一つあれば良い.トンネルモードのコンテナは,接続先のホスト一台に付き一つ必要になる.クライアントモードのコンテナは,元々の Ambassadorパターンと同じくリンク先のコンテナ数分必要になる.
AmbassadorS の実行は,基本的に
$ docker run -dt jkawamoto/ambassadors (server|client|tunnel) [-v]
Options:
-v Verbose mode for debugging.
の形で,第一引数としてモードを指定 (server
, client
, tunnel
のいずれか) する.第二引数に -v
を渡すとデバッグ用に詳細なログを出力するようになる.
なお,各モードとも上記に Docker へのオプション指定,マウントやリンクの設定が必要になる.具体的な設定方法は次の接続例で説明する.
接続例
ホスト A で MySQL と MongoDB のコンテナが走っていて,ホスト B からこれらのコンテナを利用する場合を考える.なお,MySQL と MongoDB のコンテナはそれぞれ mysql, mongo という名前とする.
サーバモードコンテナの用意
まず始めに,ホスト A で MySQL と MongoDB のコンテナにリンクするサーバモードの AmbassadorS コンテナを用意する.
$ docker run -d --name ambassadors_server \
-v ~/.ssh/authorized_keys:/data/authorized_keys -p 10022:22 \
--link mysql:mysql --link mongo:mongo \
jkawamoto/ambassadors server
サーバモードの AmbassadorS コンテナ はホスト B からの SSH 接続を認証するためにホスト B の公開鍵が必要で,この公開鍵は /data/authorized_keys
に置く必要がある.上の例では,ホスト A の ~/.ssh/authorized_keys
にホスト B の公開鍵が含まれているものとして,-v ~/.ssh/authorized_keys:/data/authorized_keys
によってマウントしている.
サーバモードの AmbassadorS コンテナは,ホスト B からの SSH 接続用に 22番ポートを公開している.-p 10022:22
では,22番の代わりに 10022番を AmbassadorS 用に指定している.
--link mongo:mongo --link mysql:mysql
では,AmbassadorS コンテナを MySQL と MongoDB のコンテナにリンクさせている.
トンネルモードコンテナの用意
ホスト B では,まずホスト A へトンネルを張るトンネルモードの AmbassadorS コンテナを用意する.
$ docker run -dt --name ambassadors_tunnel \
-v ~/.ssh/id_rsa:/root/.ssh/id_rsa -e PORT=10022 -e HOST=<ホスト A のアドレス> \
jkawamoto/ambassadors tunnel
トンネルモードでは,サーバモードのコンテナに接続するための情報が必要になる.環境変数 HOST
及び PORT
は,それぞれサーバモード AmbassadorS コンテナが走っているホスト A のアドレスと公開しているポート番号を指定する.そして,ホスト A で設定した公開鍵に対応する秘密鍵を /root/.ssh/id_rsa
に置く.ここでは,ホスト A の ~/.ssh/id_rsa
が秘密鍵だとして -v ~/.ssh/id_rsa:/root/.ssh/id_rsa
によってマウントしている.
クライアントモードコンテナの用意
最後に,ホスト B でクライアントモードのコンテナを用意する.これは,リンク先のコンテナ数分,この例では2個用意する.
$ docker run -d --name mysql_ambassadors \
--link ambassadors_tunnel:tunnel --expose 3306 -e PORT=3306 \
jkawamoto/ambassadors client
$ docker run -d --name mongo_ambassadors \
--link ambassadors_tunnel:tunnel --expose 27017 -e PORT=27017 \
jkawamoto/ambassadors client
クライアントモードのコンテナは,トンネルモードのコンテナを tunnel
という名前でリンクしなければならない.また,リンク先のコンテナが公開しているポート番号を,--expose
と環境変数 PORT
の両方に指定しなければならない.MySQL コンテナの場合,3306番を公開しているため --expose 3306 -e PORT=3306
を指定している.
サービスコンテナの利用
最後に,MySQL と MongoDB を利用するコンテナをクライアントモードのコンテナに接続する.
$ docker run -d --link mysql_ambassadors:mysql --link mongo_ambassadors:mongo some-app
docker-compose
上記の例を docker-compose で行う場合,各ホストの設定ファイルは次の通り.
ホスト A 用
mysql:
image: mysql
mongo:
image: mongo
ambassadors:
image: jkawamoto/ambassadors
command: server
volumes:
- ~/.ssh/authorized_keys:/data/authorized_keys
ports:
- "10022:22"
links:
- mysql
- mongo
ホスト B 用
tunnel:
image: jkawamoto/ambassadors
command: tunnel
volumes:
- ~/.ssh/id_rsa:/root/.ssh/id_rsa
environment:
HOST: xxx.xxx.xxx.xxx
PORT: 10022
mysql_ambassadors:
image: jkawamoto/ambassadors
command: client
expose: 3306
environment:
PORT: 3306
links:
- tunnel
mongo_ambassadors:
image: jkawamoto/ambassadors
command: client
expose: 27017
environment:
PORT: 27017
links:
- tunnel
app:
image: some-app-image
links:
- mysql_ambassadors:mysql
- mongo_ambassadors:mongo
コンテナ間のリンクが多数必要になるので,上記のように docker-compose の利用を検討したい.
まとめ
SSH トンネリングと Ambassador パターンを提供する AmbassadorS コンテナを用いると,別のネットワークにある docker コンテナをセキュアにリンクすることができる.SSH トンエリングが切断した場合,トンネルモードのコンテナが終了するので,長期的に運用する場合には再接続する設定が必要である.