#play-with-dockerとは
クラウド上で素早くdockerを試すことが出来るツール。
簡単にノードを追加することが出来、swarmやkubernetesのクラスターを作成するのにもとても役立つツールなのである。
4時間限定でdockerの仮想環境が素早く構築することが出来、ノードを増やすことが出来る。追加するノードの数は限られているが。
なお今回のこの記事はudemyの
Docker Mastery: with Kubernetes +Swarm from a Docker Captain
を参考にしながら作成しております。
解釈などの間違っている箇所はあると思いますがその時はコメントしていただければ幸いです。文法や作り方はめちゃくちゃだと思います。これから頑張ります。
##今回やってみること
今回はノード3台を使用してswarmクラスターを作ってみたいと思います!!その後に投票アプリケーションを作成します。
###準備完了までの手順、3台のノードを追加するまで
###①play-with-dockerにアクセスしdockerにログインする
持っているdocker IDでアクセスする。dockerに登録してない人は登録する必要がある。
###②ログインしたら+ADD NEW INSTANCEボタンを押してノードを3つ追加する。
###③swarmクラスターに必要なtokenを取得する
node1
$ docker swarm init
Error response from daemon: could not choose an IP address to advertise since this system has multiple addresses on different interfaces (192.168.0.23 on eth0 and 172.18.0.60 on eth1) - specify one with --advertise-addr
docker swarm initがswarmのスタートですがサーバーでは、SwarmサービスをアドバタイズするIPアドレスを指定する必要があります。今回はErrorに書かれている「192.168.0.23」を指定して再度実行します。
###IP指定
$ docker swarm init --advertise-addr="192.168.0.23"
Swarm initialized: current node (yoetefvzciclzubndes69sywy) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-3ifftddkbbe9yl8ir43l9zujir5umk8oh7nq1td1g5w2m68hg2-cisy1qe7f8g67vu11z5gg5v4v 192.168.0.23:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
###④「③」のコマンドの出力結果から以下のようなトークンを取得する
docker swarm join --token SWMTKN-1-3ifftddkbbe9yl8ir43l9zujir5umk8oh7nq1td1g5w2m68hg2-cisy1qe7f8g67vu11z5gg5v4v 192.168.0.23:2377
###⑤取得したtokenをコピーしnode2とnode3に貼り付け実行する
node2
$ docker swarm join --token SWMTKN-1-3ifftddkbbe9yl8ir43l9zujir5umk8oh7nq1td1g5w2m68hg2-cisy1qe7f8g67vu11z5gg5v4v 192.168.0.23:2377
This node joined a swarm as a worker.
node3
$ docker swarm join --token SWMTKN-1-3ifftddkbbe9yl8ir43l9zujir5umk8oh7nq1td1g5w2m68hg2-cisy1qe7f8g67vu11z5gg5v4v 192.168.0.23:2377
This node joined a swarm as a worker.
これによりnodeがswarmの一部となる。
node1がクラスターの「Leader」となる。node2とnode3は「worker」となる。
現在の状態になるとnode1が「Leader」のためnode1からswarm全体を操作することが可能になる
###⑥「worker」を「manager」に昇格させる
node1
$ docker node update --role manager node2
node2(output)
node1
$ docker node update --role manager node3
node3(output)
###⑦クラスターが3つのノードで構成されているか確認する
node1
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
yoetefvzciclzubndes69sywy * node1 Ready Active Leader 19.03.11
2njm4yd3lvrjyjy61g06n4u9g node2 Ready Active Reachable 19.03.11
40ooxzfo4m117oftkbocbooze node3 Ready Active Reachable 19.03.11
*は今使用しているノードです。という意味。
これで「swarmクラスターを3つのノードで構成したという状態になる」
#基本コマンド
###現在のクラスターのノード一覧
$ docker node ls
ちなみにnode-2,node-3は普通のworkerのためdocker node lsをしても効果はない
###現在稼働しているクラスターのトークンの入手方法
$ docker swarm join-token manager
新しくノードを追加するにはtokenを取得して新規のノードに貼り付けすればいけると思います。
###稼働しているserviceの確認
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
po9c2ygakrbs amazing_ramanujan replicated 3/3 alpine:latest
###ローカルノードがどのタスク又はどのコンテナを起動しているかの確認
$ docker node ps
###サービスを確認したい場合
$ docker service ps <service name>
###サービスの削除
$ docker service rm <service name>
#swarmクラスターを使用しアプリを作成してみる
これからは全てnode1で操作を行なっていきます。
##オーバーレイネットワークを作成
Swarmでは、オーバーレイを使用すると、まるでローカルネットワーク上にあるかのように、ノードをまたがることができます。
###ネットワーク 1
node1
$ docker network create -d overlay backend
skkw2p6ndobql31crysmjv9fe
出力結果の「skkw2p6ndobql31crysmjv9fe」はネットワーク IDとなります。
###ネットワーク 2
$ docker network create -d overlay frontend
zjo3f6xpmky5cewrdjtp98qt3
##使用するサービスの作成
###サービスを作成 1
$ docker service create --name vote -p 81:80 --network frontend --replicas 2 dockersamples/examplevotingapp_vote:before
in32sdlgnefwm8rcm8uqz58sl
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged
コマンド実行すぐに現れた文字列はサービス IDです。
--name -> 作成したサービスに名前を付与する
--network -> 作成したサービスはどのネットワークを使用するか
--replica -> 起動するタスクの数
今回host側portを81にしているのは80のポートが塞がっているためです。塞いだ覚えはないのですが
遠い昔にwebサーバーを立ち上げた時にそのままにしてしまったようです。psコマンドでもプロセスが見当たらないので
ちょっと困り中です。
###サービスを作成 2
$ docker service create --name redis --network frontend --replicas 2 redis:3.2
xxnws00rb51gdzdqx9xl37nx0
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged
###サービスを作成 3
$ docker service create --name worker --network frontend --network backend dockersamples/examplevotingapp_worker
n4hijthb2anlbe4sra9koy3ad
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
###サービスを作成 4
$ docker service create --name db --network backend --mount type=volume,source=db-data,target=/var/lib/postgresql/data postgres:9.4
e0lf7bv4ni8bovty3c1qx42kd
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
--mountフラグは、ボリュームが作成される前に、ボリュームのカスタムメタデータ(「ラベル」)を指定することができます。
type=volume -> マウント方法はボリュームマウントを指定するという意味です。
※バインドマウントとボリュームマウントの違いとは 参考文献(https://qiita.com/kubocchi/items/793c327cf3c72cc7af1c)
source=db-data -> ボリューム名を指定する
target=/var/lib/postgresql/data -> コンテナ上のマウント先ディレクトリ
(docker document参照)
###サービスを作成 5
$ docker service create --name result --network backend -p 5001:80 dockersamples/examplevotingapp_result:before
uf9e9pew31gp45brh79vsb6db
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
###ここで起動したサービスが全て作成されているか確認する
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
e0lf7bv4ni8b db replicated 0/1 postgres:9.4
xxnws00rb51g redis replicated 2/2 redis:3.2
uf9e9pew31gp result replicated 1/1 dockersamples/examplevotingapp_result:before *:5001->80/tcp
in32sdlgnefw vote replicated 2/2 dockersamples/examplevotingapp_vote:before *:81->80/tcp
n4hijthb2anl worker replicated 0/1 dockersamples/examplevotingapp_worker:latest
REPLICASは本来設定しないとデフォルトでは1になります。
なぜかworkerとdbが思うように動いていません。
###各サービスの状況を確認してみます。
$ docker service ps db
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
0l67ecgagwwg db.1 postgres:9.4 node1 Ready Ready 1 second ago
24ew7b6x7bfj \_ db.1 postgres:9.4 node1 Shutdown Failed 1 second ago "task: non-zero exit (1)"
cddv0r2zt8vf \_ db.1 postgres:9.4 node1 Shutdown Failed 8 seconds ago "task: non-zero exit (1)"
jba84u0j4eai \_ db.1 postgres:9.4 node1 Shutdown Failed 14 seconds ago "task: non-zero exit (1)"
c72n1rv6iuwe \_ db.1 postgres:9.4 node2 Shutdown Failed 21 seconds ago "starting container failed: fa…"
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
t8hkcojxg271 redis.1 redis:3.2 node1 Running Running 10 minutes ago
2mjjlnfnvnau redis.2 redis:3.2 node3 Running Running 10 minutes ago
$ docker service ps vote
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
0cdz4ggwhotl vote.1 dockersamples/examplevotingapp_vote:before node1 Running Running 11 minutes ago
pkm3ir1y8ukz vote.2 dockersamples/examplevotingapp_vote:before node2 Running Running 11 minutes ago
$ docker service ps worker
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
lbysaf6osku8 worker.1 dockersamples/examplevotingapp_worker:latest node3 Running Running less than a second ago
yyra79dzg3at \_ worker.1 dockersamples/examplevotingapp_worker:latest node1 Shutdown Failed 7 seconds ago "task: non-zero exit (1)"
q7f4bzw8zeuj \_ worker.1 dockersamples/examplevotingapp_worker:latest node3 Shutdown Failed 14 seconds ago "task: non-zero exit (1)"
t9ccjueiu5yg \_ worker.1 dockersamples/examplevotingapp_worker:latest node2 Shutdown Failed 21 seconds ago "task: non-zero exit (1)"
hxivx6ttwcwm \_ worker.1 dockersamples/examplevotingapp_worker:latest node3 Shutdown Failed 32 seconds ago "task: non-zero exit (1)"
$ docker service ps result
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
n1fqj9teruwx result.1 dockersamples/examplevotingapp_result:before node2 Running Running about a minute ago
こうみるとwokerサービスなどははじめは何回かシャットダウンされてるみたいです。
この状態で全てREPLICASが1/1,3/3みたいな動いていてくれるとありがたいですが動いてないのでログをみてみます。
###サービスのログを確認する(db service)
$ docker service logs db
db.1.09758ad58qj3@node1 | Error: Database is uninitialized and superuser password is not specified.
db.1.09758ad58qj3@node1 | You must specify POSTGRES_PASSWORD for the superuser. Use
db.1.09758ad58qj3@node1 | "-e POSTGRES_PASSWORD=password" to set it in "docker run".
db.1.09758ad58qj3@node1 |
db.1.09758ad58qj3@node1 | You may also use POSTGRES_HOST_AUTH_METHOD=trust to allow all connections
db.1.09758ad58qj3@node1 | without a password. This is *not* recommended. See PostgreSQL
db.1.yvqhwmc1nm4k@node3 | Error: Database is uninitialized and superuser password is not specified.
db.1.09758ad58qj3@node1 | documentation about "trust":
db.1.yvqhwmc1nm4k@node3 | You must specify POSTGRES_PASSWORD for the superuser. Use
db.1.yvqhwmc1nm4k@node3 | "-e POSTGRES_PASSWORD=password" to set it in "docker run".
(以下同じことが起きていたので省略)
パスワードが設定されていないので設定してくださいみたいなことが書かれている気がします。
###--envオプションで環境変数を指定し再度実行
$ docker service create --name db --network backend --mount type=volume,source=db-data,target=/var/lib/postgresql/data --env POSTGRES_PASSWORD=mypasswd postgres:9.4
r8fn4ue8gcpfbqdj3ve1ifbos
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
結果:正常に動きました。
###サービスのログを確認する(worker service)
$ docker service logs
workerworker.1.pyc8dghi4pp5@node3 | System.AggregateException: One or more errors occurred. (No such device or address) ---> System.Net.Internals.SocketExceptionFactory+ExtendedSocketException: No such device or address
worker.1.pyc8dghi4pp5@node3 | at System.Net.Dns.HostResolutionEndHelper(IAsyncResult asyncResult)
worker.1.pyc8dghi4pp5@node3 | at System.Net.Dns.EndGetHostAddresses(IAsyncResult asyncResult)
worker.1.pyc8dghi4pp5@node3 | at System.Net.Dns.<>c.<GetHostAddressesAsync>b__14_1(IAsyncResult asyncResult)
worker.1.pyc8dghi4pp5@node3 | at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
よくわかりません。デバイスやアドレスがないみたいです。
###再度実行してみる
$ docker service create --name worker --network frontend --network backend dockersamples/examplevotingapp_workerz9z81eeqgkyxov44rhtmg6mys
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
dbとworkerの順番は関係ないだろうと思いworkerの方を何度も再起動していましたが、dbの方の環境変数の方を修正しdbが動いてからこっちも動かすと正常に動きました。
うーん、こういう仕組みがわからないとまだまだな気がします。
###この状態が見たかった!!
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
r8fn4ue8gcpf db replicated 1/1 postgres:9.4
xxnws00rb51g redis replicated 2/2 redis:3.2
uf9e9pew31gp result replicated 1/1 dockersamples/examplevotingapp_result:before *:5001->80/tcp
in32sdlgnefw vote replicated 2/2 dockersamples/examplevotingapp_vote:before *:81->80/tcp
z9z81eeqgkyx worker replicated 1/1 dockersamples/examplevotingapp_worker:latest
###webアプリにアクセスしてみます
$ curl 192.168.0.21:81
<!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">
<link rel='stylesheet' href="/static/stylesheets/style.css" />
<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 b10bce8983a9
</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>
</html>
chromeなどの方でアクセスするにはplay-with-docker画面のOPEN PORTボタンの横のポート番号ボタンにアクセスするといけます。