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 の構文が弱い(レプリカ数とかの設定どうすんの・・・?)んで、早く整備されるといいなと思いましたとさ。