はじめに
Docker 1.12が2016年7月28日に正式リリースされました。
今回リリースは非常に大規模なもので、特にdocker engineにクラスタ管理機能がビルトインされたことが大きな話題になっています。
今回の記事では、このクラスタ管理機能に絞って触った結果をまとめました。
さらに、experimentalな機能ですが、ビルトインSwarmクラスタ上にDocker Composeのように複数サービスをデプロイする方法についても触れたので、おまけ的に記事に載せてみました。
Docker 1.12で追加された機能
Docker1.12 で追加された細かい機能は、以下のリリース情報を参照してください。
https://github.com/docker/docker/releases/tag/v1.12.0
この記事で関係ある部分としては、見出しで「Swarm Mode」となっている部分です。
Standalone Docker Swarm と Docker Engine 内蔵 Swarmの違い
Docker1.12でビルトインされたswarmと、今まで使用されていたスタンドアロンSwarmの違いを(穴だらけですが)表で簡単にまとめてみました。
KVSを使用しなくてもよくなった点や、サービス単位でクラスタにデプロイが可能になった点が、違いとして大きいと思います。
スタンドアロン Swarm | ビルトイン Swarm | |
---|---|---|
クラスタの構築 | Swarmコンテナの起動 | docker swarmコマンドの実行 |
Key Value Storeの有無 | 有 | 無 |
コンテナをクラスタ上に起動するコマンド | docker run | docker service |
クラスタ上で実行する単位 | コンテナ単位 | サービス単位 |
Docker Machineとの連携 | 有 | 無? |
コンテナのリスケジューリング | コンテナ起動時にオプションを付ける | 特に指定しなくても実行される |
Docker 1.12 で実際にクラスタを構成
導入環境
- OS: Ubuntu 16.04 (64bit) * 3台
- kernel: 4.4.0-28-generic
- Docker Engine : 1.12.0
- Docker Compose : 1.8.0
構築するクラスタ
- 今回はクラスタを以下のように構成します。
- manager + node: 2台
- node: 1台
Dockerのインストール
まずは、Docker1.12のexperimental版を全てのマシンにインストールします。
# curl -fsSL https://experimental.docker.com/ | sh
インストールが完了したら、Dockerのバージョンが1.12であることを確認します。
# docker version
Client:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 22:20:10 2016
OS/Arch: linux/amd64
Experimental: true
Server:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 22:20:10 2016
OS/Arch: linux/amd64
Experimental: true
Docker Swarmクラスタの構築
Docker 1.12のSwarmモードでの、クラスタの構築手順を説明します。
Docker 1.12から、Swarmクラスタは非常に簡単に作成できるようになりました。
具体的には、Swarmクラスタの初期化と、ノードのSwarmクラスタへの参加を行うだけでクラスタを作成できます。
Docker Swarm クラスタの初期化
まず、docker-masterでSwarmクラスタを初期化します。
初期化を行うコマンドはdocker swarm init
です。
クラスタの初期化を行うと、クラスタへnode
として参加するコマンドと、manager
として参加するコマンドが表示されます。
docker-master:~# docker swarm init --listen-addr 10.255.19.1:2377 --advertise-addr 10.255.19.1
Swarm initialized: current node (f16o8xd50nrlcjasiswk9zxjv) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-0t9g8kk9u7976lk30737ykjswtmgb3wfqqbnkoy4nyp98immyg-a6i7vo6az2jhp7h5kaik5h901 \
10.255.19.1:2377
To add a manager to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-0t9g8kk9u7976lk30737ykjswtmgb3wfqqbnkoy4nyp98immyg-8itaveatjiykl20fq9e8jrasy \
10.255.19.1:2377
docker-master:~#
docker-master:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
csmk41357kk8y53loldgpsm7h * docker-master Ready Active Leader
Docker Swarm クラスタに参加
dicker swarm init
時に表示されたコマンドをクラスタに参加させたいノード上で実行します。
docker-node01はnode
としてクラスタに参加し、docker-node02はmanager兼node
としてクラスタに参加します。
docker-node01:~# docker swarm join \
--token SWMTKN-1-5z5tkorsbo07neq446j07e1kpyjt3h1a43bjkaez5veyakv72x-aius9gmwk5lg8ydyiccj0sw5x \
10.255.19.1:2377
This node joined a swarm as a worker.
docker-node02:~# docker swarm join \
--token SWMTKN-1-5z5tkorsbo07neq446j07e1kpyjt3h1a43bjkaez5veyakv72x-4azspb12qwb8edyxbyfuhnk95 \
This node joined a swarm as a manager.
これでmanger + node:2台、node:1台の計3台構成のDockerクラスタの構築ができました。
docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
c1h1zgz0f62ttimde2cm2fyb5 docker-node02 Ready Active Reachable
csmk41357kk8y53loldgpsm7h * docker-master Ready Active Leader
d2ia3um0iyink4fs2xszvy2c0 docker-node01 Ready Active
クラスタ構成の編集
各ノードのmanager/nodeのroleを変更できるので試してみます。
nodeからmanagerに昇格
唯一のnode
roleであるdocker-node01をmanager
roleに昇格してみます。
- docker-node01をmanagerに昇格させるには
docker node promote
コマンドをmanager
roleのマシンで実行します。 - Leader以外の
manager
ノードはReachable
というステータスを持ちます。
docker-master:~# docker node promote docker-node01
Node docker-node01 promoted to a manager in the swarm.
docker-master:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
c1h1zgz0f62ttimde2cm2fyb5 docker-node02 Ready Active Reachable
csmk41357kk8y53loldgpsm7h * docker-master Ready Active Leader
d2ia3um0iyink4fs2xszvy2c0 docker-node01 Ready Active Reachable
managerからnodeに降格
では、今度はdocker-node02をmanagerからnodeに降格してみます。
- docker-node02をmanagerからnodeに降格させるには
docker node demote
コマンドををmanager roleのマシン上で実行します。 - managerから降格したdocker-masterでは、クラスタの情報を取得することができなくなります。
docker-master:~# docker node demote docker-node02
Manager docker-node02 demoted in the swarm.
docker-master:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
c1h1zgz0f62ttimde2cm2fyb5 docker-node02 Ready Active
csmk41357kk8y53loldgpsm7h * docker-master Ready Active Leader
d2ia3um0iyink4fs2xszvy2c0 docker-node01 Ready Active Reachable
クラスタ上にサービスを作成
構築したクラスタ上にnginx imageから、nginという名前のサービス(コンテナ)を作成します。
docker-master:~# docker service create --name ngin -p 8080:80 nginx
docker-master:~# docker service ls
ID NAME REPLICAS IMAGE COMMAND
b0h4m6jf9tf9 ngin 1/1 nginx
docker-master:~# docker service ps ngin
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
eyybcfh9wtfrmlohyrod457jp ngin.1 nginx docker-master Running Running 31 seconds ago
作成したサービスはdocker service rm
で削除可能です。
docker-master:~# docker service rm ngin
ngin
クラスタ上で使える便利な機能
Docker クラスタ上でオプション指定を行うことで便利な機能が使用できます。
今回の記事では、以下の3つの機能を紹介したいと思います。
- コンテナのスケール
- コンテナの自動リスケジュール
- コンテナのローリングアップデート
コンテナのスケール
クラスタ内でコンテナのスケールを簡単に行うことができます。
- サービスのレプリカ数を変える方法は2パターンあります。
- 1.
docker service update
: サービスの状態を色々変更可能 - 2.
docker service scale
: 複数サービスのレプリケーション数を一度に変更可能
- 1.
docker-master:~# docker service ps ngin
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bblpwo69rn1m6wdwc7449rll7 ngin.1 nginx docker-node02 Running Running 35 seconds ago
docker-master:~#
docker-master:~# docker service update --replicas 3 ngin
docker-master:~# docker service ps ngin
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bblpwo69rn1m6wdwc7449rll7 ngin.1 nginx docker-node02 Running Running about an hour ago
7wwcvo8r19ceoksotjm23wf45 ngin.2 nginx docker-master Running Running 11 seconds ago
e3f3ubpyppppzbxwcf53eszb4 ngin.3 nginx docker-node01 Running Running 12 seconds ago
docker-master:~#
docker-master:~# docker service scale ngin=6
ngin scaled to 6
docker-master:~# docker service ps ngin
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bblpwo69rn1m6wdwc7449rll7 ngin.1 nginx docker-node02 Running Running about an hour ago
7wwcvo8r19ceoksotjm23wf45 ngin.2 nginx docker-master Running Running 2 minutes ago
e3f3ubpyppppzbxwcf53eszb4 ngin.3 nginx docker-node01 Running Running 2 minutes ago
4ggj14auikb1plytdc6nqa8db ngin.4 nginx docker-master Running Preparing 2 seconds ago
2laq1kxpdb4rff8xr72m3lr07 ngin.5 nginx docker-node02 Running Ready less than a second ago
dji94wy1tdo2nkb9x0fqv6r32 ngin.6 nginx docker-node01 Running Preparing 2 seconds ago
コンテナの自動リスケジュール
障害がクラスタ内で発生した時、特に何も設定しなくても、コンテナは自動リスケジュールされます。
今回は、クラスタ内の1ノードがシャットダウンしてしまった場合と、NICがダウンした時を想定して、コンテナのリスケジュールの様子を見てみます。
ノードがシャットダウンしてしまった時
各ノードで2コンテナずつ動作している環境が動作しています。
# docker service ps ngin
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
37739ros8fhwut1o6bv6bm0pb ngin.1 nginx docker-node02 Running Preparing 2 seconds ago
3egtwo22yl0gwowm55vkkdczy ngin.2 nginx docker-master Running Preparing 2 seconds ago
0whuiqad3o9g8r5vj545ym3gx ngin.3 nginx docker-node02 Running Preparing 2 seconds ago
7kphzzw5y24hapvwrq8t49t7d ngin.4 nginx docker-master Running Preparing 2 seconds ago
c8o89xnnc14hd1lvulm38xi9s ngin.5 nginx docker-node01 Running Preparing 2 seconds ago
15vuulew16u4qqdprtyvmybgg ngin.6 nginx docker-node01 Running Preparing 2 seconds ago
- docker-node02の電源を落とします
docker-node02~# shutdown -h now
- すると、docker-node02にいたコンテナが生き残っているクラスタ内に再スケジュールされます。
docker-master:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
c1h1zgz0f62ttimde2cm2fyb5 docker-node02 Down Active
csmk41357kk8y53loldgpsm7h * docker-master Ready Active Leader
d2ia3um0iyink4fs2xszvy2c0 docker-node01 Ready Active Reachable
docker-master:~# docker service ps ngin
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
99dj47rlphkbyv7hh8r1jy1yn ngin.1 nginx docker-node01 Ready Preparing less than a second ago
37739ros8fhwut1o6bv6bm0pb \_ ngin.1 nginx docker-node02 Shutdown Running 33 seconds ago
3egtwo22yl0gwowm55vkkdczy ngin.2 nginx docker-master Running Running 34 seconds ago
e1ks7kcpscb5zaiqffsaljk1b ngin.3 nginx docker-master Ready Preparing less than a second ago
0whuiqad3o9g8r5vj545ym3gx \_ ngin.3 nginx docker-node02 Shutdown Running 33 seconds ago
7kphzzw5y24hapvwrq8t49t7d ngin.4 nginx docker-master Running Running 34 seconds ago
c8o89xnnc14hd1lvulm38xi9s ngin.5 nginx docker-node01 Running Running 34 seconds ago
15vuulew16u4qqdprtyvmybgg ngin.6 nginx docker-node01 Running Running 34 seconds ago
- docker-node02を再起動すると、自動的にDockerクラスタへ復帰します。
- この時、別ノードに再スケジュールされたコンテナはdocker-node02には戻りません
NICダウン
NICダウンした時のコンテナ再スケジュールの様子を見ていきます。
各ノードで2コンテナずつ動作しているクラスタ内の、docker-node02のNICを落とします。
docker-node02~# ifdown ens160
すると、docker-node02にいたコンテナの数と同じ2コンテナ分が、クラスタ内に再スケジュールされます。
docker-master:~# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
c1h1zgz0f62ttimde2cm2fyb5 docker-node02 Down Active
csmk41357kk8y53loldgpsm7h * docker-master Ready Active Leader
d2ia3um0iyink4fs2xszvy2c0 docker-node01 Ready Active Reachable
docker-master:~# docker service ps ngin
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
0cmw5u3ltdhef88ft5nydsy39 ngin.1 nginx docker-master Ready Preparing less than a second ago
b2p4o6f086q4wxunjst2clzgj \_ ngin.1 nginx docker-node02 Shutdown Running 45 seconds ago
9xm8mkwe9456nq2g1xun3lazq ngin.2 nginx docker-master Running Running 44 seconds ago
3y26d6xl0g4qtiwi7x7bmvz8i ngin.3 nginx docker-node01 Running Running 45 seconds ago
12hveh2vcmmqcnkg3trgbidz0 ngin.4 nginx docker-node01 Running Running 44 seconds ago
bw0n128l5pg6h2phhl4r01cxm ngin.5 nginx docker-node01 Ready Preparing less than a second ago
0gf5hlm0shhlc37y8hpcw52y8 \_ ngin.5 nginx docker-node02 Shutdown Running 45 seconds ago
b4wf19a1ya7wsob54khdfqpdb ngin.6 nginx docker-master Running Running 44 seconds ago
docker-node02はdocker自体は止まっていないので、NIC停止前に起動したコンテナはまだ動いています。
docker-node02のNICを起動します。
docker-node02~# ifup ens160
- NIC回復後docker-node02はクラスタへ復帰します。しかし、docker-node02上で動いていた
ngin
のコンテナはクラスタ復帰後削除されることを確認しました。
コンテナのローリングアップデート
コンテナのローリングアップデートを行うことができます。
- nginxコンテナが各ノードに1コンテナずつ起動している状態から、nginxコンテナをdockercon2016で使用されていた、投票アプリに1分間隔で1コンテナずつ入れ替えていきます。
docker-master:~# docker service ps ngin
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
b5sl2ste8zvnum4wou5ax6ggd ngin.1 nginx docker-master Running Running 3 seconds ago
3ct7khgjefjnl0yg26mutg4zk ngin.2 nginx docker-node02 Running Running 3 seconds ago
3zpssl78bcbrmav5yrfjbrhly ngin.3 nginx docker-node01 Running Running 3 seconds ago
docker-master:~$ curl 10.255.19.1:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
docker-master:~# docker service update --image instavote/vote:latest --update-delay 60s --update-parallelism 1 ngin
docker-master:~# docker service tasks ngin
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
5tx5smm7tjc217ddw8xoh3tfq ngin.1 instavote/vote:latest docker-node01 Running Running 49 seconds ago
b5sl2ste8zvnum4wou5ax6ggd \_ ngin.1 nginx docker-master Shutdown Shutdown 50 seconds ago
1mi5moqfzu8x4g3szy9gp8v3e ngin.2 instavote/vote:latest docker-master Running Running 2 minutes ago
3ct7khgjefjnl0yg26mutg4zk \_ ngin.2 nginx docker-node02 Shutdown Shutdown 2 minutes ago
8ta3maek8n621p0ailhqidxsa ngin.3 instavote/vote:latest docker-node02 Running Running about a minute ago
3zpssl78bcbrmav5yrfjbrhly \_ ngin.3 nginx docker-node01 Shutdown Shutdown about a minute ago
docker-master:~# curl 10.255.19.1:80
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cats vs Dogs!</title>
<base href="/index.html">
<meta name = "viewport" content = "width=device-width, initial-scale = 1.0">
<meta name="keywords" content="docker-compose, docker, stack">
<meta name="author" content="Tutum dev team">
<style type="text/css">
~省略~
</style>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
</head>
<body>
<div id="content-container">
<div id="content-container-center">
<h3>Cats vs Dogs!</h3>
<form id="choice" name='form' method="POST" action="/">
<button id="a" type="submit" name="vote" class="a" value="a">Cats</button>
<button id="b" type="submit" name="vote" class="b" value="b">Dogs</button>
</form>
<div id="tip">
(Tip: you can change your vote)
</div>
<div id="hostname">
Processed by container ID 35b4fb6615b9
</div>
</div>
</div>
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>
</body>
Experimental: Distributed Application Bundles(DAB)
まだExperimentalな機能ながら、今回のビルトインSwarmクラスタと絡んでくる機能として、Docker Composeのように、複数サービスを管理する機能があります。
その中で新しく出てくるファイル形式として、Distributed Application Bundles(DAB)があります。
このDABファイルは、docker-compose の1.8で実装されたdocker-compose bundle
を実行することで作成できます。
DABファイルを使用することで、複数サービスのまとまりをswarmクラスタ上にまとめてデプロイできるようになります。
メモ:以下のdocker-compose.ymlファイルを作成して、docker-compose upを実行するとcomposeはserviceコマンドに対応してないというメッセージが出る。
version: '2'
services:
web:
image: wordpress
environment:
- "WORDPRESS_DB_HOST=wordpress_db"
- "WORDPRESS_DB_USER=root"
- "WORDPRESS_DB_PASSWORD=password"
ports:
- 8000:80
container_name: "wordpress_web"
db:
image: mariadb
environment:
- "MYSQL_ROOT_PASSWORD=password"
container_name: "wordpress_db"
docker-master:~# docker-compose up -d
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use the bundle feature of the Docker experimental build.
More info:
https://docs.docker.com/compose/bundles
Creating network "wordpress_default" with the default driver
Creating wordpress_web
Creating wordpress_db
では先ほどのdocker-compose.ymlファイルを使用してDABファイルを作成します。
docker-master:~# docker-compose bundle
WARNING: Unsupported key 'container_name' in services.web - ignoring
WARNING: Unsupported key 'container_name' in services.db - ignoring
Wrote bundle to wordpress.dab
docker-master:~# ls
docker-compose.yml wordpress.dab
docker-master:~# cat wordpress.dab
{
"Services": {
"db": {
"Env": [
"MYSQL_ROOT_PASSWORD=password"
],
"Image": "mariadb@sha256:c5984a0db84a3eaef09bb25af32052686ffa976e15e59789bceb7b5d1678433d",
"Networks": [
"default"
]
},
"web": {
"Env": [
"WORDPRESS_DB_HOST=wordpress_db",
"WORDPRESS_DB_USER=root",
"WORDPRESS_DB_PASSWORD=password"
],
"Image": "wordpress@sha256:0f73fa5e20b0194c6cffc78143e9b9b966c952b57118be12526edb058726cd92",
"Networks": [
"default"
],
"Ports": [
{
"Port": 80,
"Protocol": "tcp"
}
]
}
},
"Version": "0.1"
}
作成されたwordpress.dabをdocker swarm クラスタ上にデプロイします。
デプロイにはdocker service deploy
コマンドを使用します。
docker-master:~# ls
docker-compose.yml wordpress.dab
docker-master:~# docker stack deploy wordpress
Loading bundle from wordpress.dab
Creating network wordpress_default
Creating service wordpress_db
Creating service wordpress_web
docker-master:~# docker stack ps wordpress
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
9qtvjbi2uq7zj9vkt4hw2r8xr wordpress_web.1 wordpress@sha256:0f73fa5e20b0194c6cffc78143e9b9b966c952b57118be12526edb058726cd92 docker-node01 Running Running 2 minutes ago
5ztyx62uudemewue9zju3zkiu wordpress_db.1 mariadb@sha256:c5984a0db84a3eaef09bb25af32052686ffa976e15e59789bceb7b5d1678433d docker-master Running Running 2 minutes ago
docker-master:~# docker service ls
ID NAME REPLICAS IMAGE COMMAND
9yyxr3ial9qk wordpress_db 1/1 mariadb@sha256:c5984a0db84a3eaef09bb25af32052686ffa976e15e59789bceb7b5d1678433d
bv2cdvgym33o ngin 3/3 instavote/vote:latest
e3oo6tztgllq wordpress_web 1/1 wordpress@sha256:0f73fa5e20b0194c6cffc78143e9b9b966c952b57118be12526edb058726cd92
これでDocker 1.12で追加された、クラスタ周りの機能について一通り触れることができました。
おわりに
いかかでしたでしょうか?
Docker 1.12のリリースによって、今までのDocker Swarmクラスタよりも、より早く・簡単に多機能なクラスタを作成できるようになりました。
今まで、「クラスタ組むのめんどくさそうだな」と思っていたそこのあなたも楽しいDockerクラスタライフをぜひエンジョイしてみてください。