swarm tutorialをdindでやってみる
お題
dockerのオーケストレーションツールのひとつにswarmというのがある
複数のdockerホストをクラスタリングしたり,ロードバランシングしたりできるらしい.
これ系は今はKubernetesが優勢だとは思うが,デフォルトでdocker engineに組み込まれているということもあり,せっかくなので少し使ってみようと思った
やること
素人なので,いつも通りチュートリアルをやる.
docker swarm tutorialは公式のものだと以下が見つかった
注意書きにある通り,ここにはplay-with-dockerでできるチュートリアルをローカルでやる手順が書かれている.
具体的にはdocker-machine createというコマンドで,dockerがインストールされたVMを複数台立て,swarmでクラスタリングし,webというサービスをデプロイしている.
MacやWindows(linuxでもいいけど)のふつうのPCにvirtualboxをインストールして,ここに書かれている通りやればだいたいうまくいくと思われる.
自分はなんとなくホストPCのMacに手を入れたくなかったので,前回使ってみたdind(docker in docker)を使って似たようなことができないか試してみた
結果,docker-machineを使ったチュートリアルとだいたい同じような挙動を追うことができた
完成形を図にするとたぶんこんなかんじ
以下,上記の公式チュートリアルのbash scriptとだいたい同じことをdindでやった場合の手順を書いていく. (今回の記事ではクラスタを立てるところまでで,次回の記事でこのクラスタにサービスをデプロイしたり,nodeを退出させたりするところをやる予定.)
注意
- あくまでチュートリアルなので,セキュリティ設定等は考慮していない
- dindはdockerと異なる仕組みで動いているため,環境によってはこの通り動かない
環境
Docker 18.09.3 on Ubuntu 18.04 (virtualbox on macOS)
ubuntuにdockerをインストールする手順はこちら:
koimedenshi.hatenablog.com
手順
元のbash scriptを参考に作成したbash scriptはこちら.
細かい点を除けば,docker-machine
がやっていることをdocker container run
やdocker exec -it
で置き換えているだけ
このスクリプトをローカルに保存して実行すれば,上図のようなdindクラスタが構築される
#!/bin/bash ## output debug_output # exec 5> debug_output.txt # BASH_XTRACEFD="5" # PS4='$LINENO: ' # set -x # create user defined bridge network echo "======> Creating $nw network ..."; nw=dind-net docker network create -d bridge $nw # Swarm mode using Docker in Docker managers=3 workers=3 # create manager machines echo "======> Creating $managers manager machines ..."; for node in $(seq 1 $managers); do echo "======> Creating manager$node machine ..."; docker run -it --privileged --network $nw --name manager$node --hostname manager$node -d docker:stable-dind; done # create worker machines echo "======> Creating $workers worker machines ..."; for node in $(seq 1 $workers); do echo "======> Creating worker$node machine ..."; docker run -it --privileged --network $nw --name worker$node --hostname worker$node -d docker:stable-dind; done # list all machines docker container ls # initialize swarm mode and create a manager echo "======> Initializing first swarm manager ..." docker exec -it manager1 docker swarm init --listen-addr $(docker exec -it manager1 hostname -i | tr -d '\r') --advertise-addr $(docker exec -it manager1 hostname -i | tr -d '\r') # get manager and worker tokens manager_token=$(docker exec -it manager1 docker swarm join-token manager -q | tr -d '\r') worker_token=$(docker exec -it manager1 docker swarm join-token worker -q | tr -d '\r') echo "manager_token: $manager_token" echo "worker_token: $worker_token" # other masters join swarm for node in $(seq 2 $managers); do echo "======> manager$node joining swarm as manager ..."; docker exec -it manager$node \ docker swarm join \ --token $manager_token \ --listen-addr $(docker exec -it manager$node hostname -i | tr -d '\r') \ --advertise-addr $(docker exec -it manager$node hostname -i | tr -d '\r') \ $(docker exec -it manager1 hostname -i | tr -d '\r'); done # show members of swarm docker exec -it manager1 docker node ls # workers join swarm for node in $(seq 1 $workers); do echo "======> worker$node joining swarm as worker ..." docker exec -it worker$node \ docker swarm join \ --token $worker_token \ --listen-addr $(docker exec -it worker$node hostname -i | tr -d '\r') \ --advertise-addr $(docker exec -it worker$node hostname -i | tr -d '\r') \ $(docker exec -it manager1 hostname -i | tr -d '\r'); done # show members of swarm docker exec -it manager1 docker node ls
順を追って説明する.
まずユーザ定義ネットワークを作成する.
ネットワークタイプはbridgeを選択
# create user defined bridge network echo "======> Creating $nw network ..."; nw=dind-net docker network create -d bridge $nw
swarmに参加させるノードコンテナを起動.
swarmでは必ずmanagerかworkerかのいずれかのロールを割り当てる.
それぞれの役割は読んで字のごとくという感じ?(雑)
manager node, worker nodeをそれぞれ3台ずつ,dindコンテナで起動する
# Swarm mode using Docker in Docker managers=3 workers=3 # create manager machines echo "======> Creating $managers manager machines ..."; for node in $(seq 1 $managers); do echo "======> Creating manager$node machine ..."; docker run -it --privileged --network $nw --name manager$node --hostname manager$node -d docker:stable-dind; done # create worker machines echo "======> Creating $workers worker machines ..."; for node in $(seq 1 $workers); do echo "======> Creating worker$node machine ..."; docker run -it --privileged --network $nw --name worker$node --hostname worker$node -d docker:stable-dind; done # list all machines docker container ls
- --privilegedをつけるのは元のチュートリアルに倣っている.これをつけないと自分以外のコンテナの設定を変えることができない.
- --name と --hostname で二回名前を指定しており冗長な感じもするが,--name がコンテナ名,--hostname がホスト名.前者はコンテナ同士の名前解決に用いる名前で,後者はこの後に出てくる
node ls
などの際に表示するホスト名となる. - 使用するコンテナイメージは
docker:stable-dind
.(dindの中のdockerバージョンは"DockerVersion": "18.06.1-ce"
)
この時点では6台のdockerホストを立てただけ.ここからswarmクラスタを構築していく.
manager1を最初のswarmの参加者に指定する(リーダーになる)
# initialize swarm mode and create a manager echo "======> Initializing first swarm manager ..." docker exec -it manager1 docker swarm init --listen-addr $(docker exec -it manager1 hostname -i | tr -d '\r') --advertise-addr $(docker exec -it manager1 hostname -i | tr -d '\r')
--listen-addrおよび--advertise-addrに自身のホストIPを指定する.
manager1がswarmクラスタのmanager nodeになったので,クラスタ参加に必要なトークンを払い出す.
# get manager and worker tokens manager_token=$(docker exec -it manager1 docker swarm join-token manager -q | tr -d '\r') worker_token=$(docker exec -it manager1 docker swarm join-token worker -q | tr -d '\r') echo "manager_token: $manager_token" echo "worker_token: $worker_token"
見ての通り,ロールによってトークンが異なる.
払い出したトークンで,他のnodeをswarmクラスタに参加させる.
# other masters join swarm for node in $(seq 2 $managers); do echo "======> manager$node joining swarm as manager ..."; docker exec -it manager$node \ docker swarm join \ --token $manager_token \ --listen-addr $(docker exec -it manager$node hostname -i | tr -d '\r') \ --advertise-addr $(docker exec -it manager$node hostname -i | tr -d '\r') \ $(docker exec -it manager1 hostname -i | tr -d '\r'); done # show members of swarm docker exec -it manager1 docker node ls # workers join swarm for node in $(seq 1 $workers); do echo "======> worker$node joining swarm as worker ..." docker exec -it worker$node \ docker swarm join \ --token $worker_token \ --listen-addr $(docker exec -it worker$node hostname -i | tr -d '\r') \ --advertise-addr $(docker exec -it worker$node hostname -i | tr -d '\r') \ $(docker exec -it manager1 hostname -i | tr -d '\r'); done # show members of swarm docker exec -it manager1 docker node ls
正常に終了していれば,6台のノードがmanager/workerいずれかのロールでswarmクラスタに参加している状態となる.
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION vjgd1myk9r10msdhi1x835kou * manager1 Ready Active Leader 18.09.3 10ddklb0bysyhpadxjr6lvyar manager2 Ready Active Reachable 18.09.3 q0cxi5rkcayiuac2kopjsg1j1 manager3 Ready Active Reachable 18.09.3 i78pa70deqx1aspefqvmjs4bj worker1 Ready Active 18.09.3 r2zv3coxlzvn6oh9xul8bf8ss worker2 Ready Active 18.09.3 quzmoin1qesj7gnqh9ffvq0st worker3 Ready Active 18.09.3
以上,dindでswarmクラスタを立てるところまでを実施した.
次回はこのクラスタにサービスをデプロイしたり,nodeを退出させたりするところをやる.
完結編はこちら↓
うまくいかないとき
環境によりけりなので,エラーを潰していくしかない.
先述の通りdindは完全ではないらしいので,最初から無理という可能性もある.
その場合は元のチュートリアルをやるか,ふつうにplay-with-dockerをやるしかないかも
後片付け
用済みであれば,docker stop -> docker rm / network rmすればok
docker stop manager1 manager2 manager3 worker1 worker2 worker3 docker rm manager1 manager2 manager3 worker1 worker2 worker3 docker network rm dind-net
P.S.
正直docker-machineの方が便利かも.