INTRODUCING EXPERIMENTAL DISTRIBUTED APPLICATION BUNDLES
https://blog.docker.com/2016/06/docker-app-bundle/
とか
What's New in Docker 1.12 (June 20, 2016) by Mike Goelzer & Andrea Luzzardi
http://www.slideshare.net/MikeGoelzer/whats-new-in-docker-112-goelzerluzzardi
とか
Docker Stacks and Distributed Application Bundles
https://github.com/docker/docker/blob/master/experimental/docker-stacks-and-bundles.md
あたりを見ると分かるんですが、 docker stack
コマンドが新しくできまして、この stack
をつかうことで「サービスのまとまり」を可搬性高く管理することができるようになります。
例えばマイクロサービスな開発をしてるときに、自分の担当外のサービスとの連携をローカル環境で試したい、みたいな状況のときに、その担当外のサービスの構成がかいてある foo_service.dab
( 現状だと .dsb
形式になってるけど間違いなのでそのうち .dab
になるはず )を受け取るだけで、自分のローカルにそのサービスの環境を構築できる、みたいな未来が待ってるわけです。
現在でも docker-compose.yml
を使えば似たようなことができはしますが、 docker-compose
だとポートが重複してたりするので、自分のサービスとそのサービスの両方が80をLISTENしてるような状況の場合に問題が発生するわけですが、この docker stack
を使うと、その辺のことを何かいい感じにしてくれます。
使い方は比較的簡単で
-
docker-compose bundle
コマンドを実行してhoge.dab
ファイルを作る -
docker stack deploy hoge
でhoge.dab
ファイルが読まれてサービスが展開される - すごい
これだけなんですが、 docker-compose
の感覚でいるといくつか失敗します。
links未対応とその解決策
まず、 docker-compose.yml
が対応している構文の全てに対応しているわけじゃないです。
実際に docker-compose bundle
を実行すると以下のようなWARNINGがでてくるはずです。
$ docker-compose bundle
WARNING: Unsupported key 'network_mode' in services.web - ignoring
WARNING: Unsupported key 'links' in services.web - ignoring
WARNING: Unsupported key 'network_mode' in services.app - ignoring
つまり、 docker-compose
のウリである勝手にhosts書き換えちゃいましたテヘペロ links
が使えないという、超残念仕様なのであります。
「え・・・じゃぁどうすんの・・・・コンテナ間のIPとか分からんよ・・・・」と思うんですが、そこは流石に対策があり、 docker-compose.yml
のルートのコンテナ名の代わりに、サービス名でアクセスすることができます。
たとえば以下みたいな docker-compose.yml
があったとして(中身は適当なので雰囲気を感じ取ってください)
web:
image: nginx
ports:
- 80:80
expose:
- 80
links:
- app:php
app:
image: php
expose:
- 9000
nginx->appへの通信は tcp://php:9000/
みたいな感じで行えるのが docker-compose
なわけですが、これに対して docker stack
の場合は(仮にstack名がpiyoだったとすると)、 tcp://piyo_app:9000/
でアクセスできるようになってます。
つまり app:php
のようなかたちで links
の設定はできませんが、この例でいうと(仮にstack名がpiyoだったとすると) piyo_web
というサービスと piyo_app
というサービスが作られ、そのサービス名がDocker内部のDNSに登録されている、というようなイメージです。
立ち上がったStackのポートが分からん件
というわけで (仮にpiyoという名前の) stack を docker stack deploy piyo
みたいにすると、内部でいい感じに piyo_web
piyo_app
みたいに スタック名_サービス名
形式のサービスが立ち上がります。
これで大勝利かと思いきや、先ほど申したとおり、stackはポートの重複が起こらないように何かいい感じにしてくれるので、たとえ以下のようにまるで80をLISTENしてそうな雰囲気でもLISTENしてくれません。
{
"services": {
"app": {
"Image": "xxxxxx",
"Networks": [],
"Ports": [
{
"Port": 9000,
"Protocol": "tcp"
}
]
},
"web": {
"Image": "yyyyyy",
"Networks": [],
"Ports": [
{
"Port": 80,
"Protocol": "tcp"
}
]
}
},
"version": "0.1"
}
「OKなるほどね。んじゃ何かいい感じのGatewayが設定されてるんだね。きっとそうだね。」
と思っていろいろ調べたけど全然見当たらなくて、ぐぬぬったんですが、何のことはなくて80じゃないPortをLISTENしてました。
というわけで困ったときのinspectコマンドですので、docker service inspect piyo_web
みたいな感じでinspectすると以下みたいな結果が返ってきます。(内容は適当ですので雰囲気)
$ docker service inspect mystack_web
[
{
"ID": "abcdefghijklmn",
"Version": {
"Index": 18
},
"CreatedAt": "2016-06-25T08:20:01.126619833Z",
"UpdatedAt": "2016-06-25T08:20:01.141201786Z",
"Spec": {
"Name": "piyo_web",
"Labels": {
"com.docker.stack.namespace": "piyo"
},
"TaskTemplate": {
"ContainerSpec": {
"Image": "yyyyyy",
}
},
"Mode": {
"Replicated": {
"Replicas": 1
}
},
"EndpointSpec": {
"Mode": "vip",
"Ports": [
{
"Protocol": "tcp",
"TargetPort": 80
}
]
}
},
"Endpoint": {
"Spec": {},
"Ports": [
{
"Protocol": "tcp",
"TargetPort": 80,
"PublishedPort": 30001
}
],
"VirtualIPs": [
{
"NetworkID": "abcdefg",
"Addr": "10.255.0.6/16"
}
]
}
}
]
見るべきは Endpoint
の Ports
の PublishedPort
で、外に露出してるポートが30001なことがわかります。このポートは30001固定なのではなく、docker task
さんがdeploy時にいい感じに決めてくれるので、例えばこれと同じ設定のstackを複数個デプロイしてもポートの重複は起こりません。
というわけで、今回の例でいうと http://localhost:30001/
にアクセスすることで piyo_web
にアクセスすることができました。
サービスのPublishedPortを取得するコマンド
GoTemplate が独特で覚えられる気がしないんでメモがてら。
docker service inspect -f '{{with index .Endpoint.Ports 0}}{{.PublishedPort}}{{end}}' piyo_web
こんな感じで、たぶんサービスのPublishedPortの取得はできると思うので、Dockerネットワークの外から何かしようとした場合も、動的に処理できそうな感じはしてます。
感想
マジまだドキュメントとか無いようなもんだし、いろいろ辛いけど夢はあるので、全てのサービスが *.dab
ファイルを持つ時代がくるといいなと思いました。まる。
あとたぶんデプロイが楽になるんじゃって噂もあるんだけど、それにしては *.dab
の構文が弱い(レプリカ数とかの設定どうすんの・・・?)んで、早く整備されるといいなと思いましたとさ。