GKE使えよって話ではあるんですが(汗)
Docker 1.12からSwarmがビルトインで入るようになりました。
そのおかげでクラスタ作成とかがずいぶんとやりやすくなったみたいなので試してみました。
Docker Swarm on Google Cloud Platformを見てやってます。
あとは公式のドキュメントを見ながら。
準備
Docker 1.12をインストールするだけ。
概念
まずは簡単に概念を説明
- Swarm:有り体に言えばクラスタ
- ノード:クラスタに属しているインスタンス
- マネージャノード:Swarmを管理するノード。
- ワーカーノード:タスクが動くノード。デフォルトだとマネージャもワーカーになる。(manager-only nodeにできる)
- サービス:アプリケーションが動くための定義。要するにコンテナを動かす時のパラメータとかを定義する。
- レプリカサービスとグローバルサービスがある
- レプリカサービス:レプリカ数を指定して指定した数だけノードにタスクを分散させるやつ
- グローバルサービス:クラスタ内の全ノードでタスクが動くやつ(正直いつ使うのかわからん)
- タスク:コンテナが実行するコマンド。大体動いてるコンテナのこと。動いてるノードは移動できない。(あとから出てきます。)
- ロードバランシング
- 内部DNSのおかげでSwarm内のサービス間はサービス名でやりとりできたりしてまあいい感じ。
- 対象ノードに対してアクセスした時にタスク(コンテナ)が実行されてなくても他の所にバランシングされる。
とりあえずサービスがk8sとは別物だよって所だけ認識しとけばいいんじゃないかな。
k8sだとサービスはpodsとservice両方かな。
Swarm(クラスタ)作る
作ると言っても、上記リンクのスクリプト(swarm-up.sh
)を実行するだけなんですが、ザックリやってることを説明しときます。
./swarm-up.sh
- Deployment ManagerでGCP上にインスタンスを作る
2. マネージャノードのインスタンス作る
3. startup-scriptでDockerをインストールする
4. swarmクラスタ初期化する(docker swarm init
)
5. プロジェクトメタデータにswarmにjoinするためのトークンを保存する
6. ワーカーノードのインスタンスグループ作る
7. インスタンステンプレート作る
8. startup-scriptでDockerをインストールする
9. プロジェクトメタデータからトークンとってくる
10. swarmクラスタにJoinする(docker swarm join --token $TOKEN:2377
)
1. インスタンステンプレ使ってインスタンスグループ作る - マネージャノードにDocker Machineをインストールする
超ざっくりこんな感じ。
同じような事を自分でしようとしてもわりかしまんま簡単にできるんじゃないかと思います。
だってそれぞれのインスタンスにDockerインストールしてクラスタ初期化してワーカーがジョインするだけだもの。
ちなみに、インスタンステンプレートを確認してもらえばわかりますが、シャットダウンスクリプトでdocker swarm leave
というコマンドが実行されてます。
Part2で触れますが、このままにしとくとワーカーノードで動かす分には問題ないけどさらにどうにかしようと思うとたぶんハマりますのでご注意を。
以下、マネージャノードでコマンド実行するとノードの状態が見れます。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
74wca83291ouja14y6qbx5v1d my-swarm-worker-81du Ready Active
8x1ev7mve4znsgs9f4n7rqa5x * my-swarm-manager Ready Active Leader
サービス作成
サービス作ります。
docker service create --replicas 1 -p 80:80/tcp --name nginx nginx
これでOK。
マウントオプションやらこの時に指定できます。
GCPで使っててかつContainer Registryを使ってる場合なんかはマネージャノードでgcloud docker --authorize-only
しておいて、サービスを作るときに--with-registry-auth
で認証状態をワーカーノードにも継承してあげればいいんじゃないかと思います。
今までDocker使ってた人なら大体どのパラメータがどういう動きするのかは分かるんじゃないかな、と思います。
自分は-v
が--mount
とかになってたりしてあれ?ってなりますけどまあ。
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
9wx1evw8mxvd web 1/1 nginx
スケール
docker service scale web=3
これでスケールします。
レプリカ数が変わって、各ノードにタスクが配置されます。
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
9wx1evw8mxvd web 3/3 nginx
こんな感じでどのノードでタスクが動いてるのか確認できます。
$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
5is5x1c1lgd8s5qpmlpq1fqlx web.1 nginx my-swarm-manager Running Running 4 hours ago
3odaytzvj2b9a0slitc5yw6i7 web.3 nginx my-swarm-worker-mz79 Running Running about an hour ago
1jcynkdz8gf8zy2eub5tojnpw web.9 nginx my-swarm-worker-mz79 Running Running 4 hours ago
ノードを増やす
これはManagedインスタンスグループを使ってるので楽勝ですね。
swarm-resize.sh
があるのでこいつでもいいです。
./swarm-resize.sh 3
これでノードが増やせます。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
30k0ojv3slev13x0nhryhblq7 my-swarm-worker-mz79 Ready Active
8x1ev7mve4znsgs9f4n7rqa5x * my-swarm-manager Ready Active Leader
b1scfttgcghn1z36ng182nv0a my-swarm-worker-bvm1 Ready Active
bg23v4d8jdi953blfbl4xnixf my-swarm-worker-ir8d Ready Active
サービスの再配置
先ほどのサービスをスケールした時点で気付いてる方もいるかと思いますが、1ノードに2つのコンテナが動いてます。
ノードを増やしたからそっちに分散させて欲しいところですが、自動で再配置はしないので注意です。
動いてるタスクは他のノードには移動できないというやつです。
じゃあどうするか。
レプリカ数を変更しましょう。
増やして減らしても、減らして増やしてもどっちでもいいです。場合によりけりですね。
$ docker service scale web=4
$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
5is5x1c1lgd8s5qpmlpq1fqlx web.1 nginx my-swarm-manager Running Running 5 hours ago
c58nz8o6ieaj9ik50dp7px3o3 web.2 nginx my-swarm-worker-bvm1 Running Running 4 minutes ago
3odaytzvj2b9a0slitc5yw6i7 web.3 nginx my-swarm-worker-mz79 Running Running 2 hours ago
1jcynkdz8gf8zy2eub5tojnpw web.9 nginx my-swarm-worker-mz79 Running Running 5 hours ago
んで、減らす。
$ docker service scale web=3
$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
5is5x1c1lgd8s5qpmlpq1fqlx web.1 nginx my-swarm-manager Running Running 5 hours ago
c58nz8o6ieaj9ik50dp7px3o3 web.2 nginx my-swarm-worker-bvm1 Running Running 4 minutes ago
3odaytzvj2b9a0slitc5yw6i7 web.3 nginx my-swarm-worker-mz79 Running Running 2 hours ago
マネージャノードにお任せではありますが、フラットな状態ならレプリカ数を平坦にならしてくれそうな感じがします。
減らして増やすパターンでも、重複してるやつ優先で落として他の所に配置するとかやってくれそう。
サービスへのアクセス
参照先だと、3つの方法を提示してます。
- シングルノードを参照
- DNSラウンドロビン
- Google Cloud Load Balancer
シングルノード参照
シングルノード参照の場合、マネージャーノードを参照するのがオススメらしいです。
マネージャノードへのアクセスの場合、マネージャノードでタスクが動いてなくても他の動いてるノードにリクエストを投げてくれます。
ただ、大して分散されてない感じがするので微妙です。
DNSラウンドロビン
複数マネージャにしている場合、シンプルな構成になっていいよね、って言ってます。
Google Cloud Load Balancer
まあGCPで動かすならこれでしょうね。
やり方は割愛。
なんかSwarmでLBあるぜ!って言ってるわりにはそんなガッツリLBを提供してるわけじゃなくて、あくまで内部LBで内部のやりとりも分散できてるぜって感じっぽい。
外部からはうまいことやってくれ感がする。
Mediumの記事ではここら辺まで。
以降は公式ドキュメントやってみた感。
ローリングアップデート
サービスのコンテナイメージの更新をすることで、ローリングアップデートができるっぽいです。
$ docker service update redis --update-parallelism 1 --update-delay 10s
--update-parallelism
でタスクを並列で更新する数を決められます。
createの際にも指定できます。
んで、未指定だと全部いっぺんに動かそうとします。
そうするとローリングアップデートが台無しです。
$ docker service update redis --image redis:3.0.7
ノードの解放
ノードは追加すると異常がなければステータスはActiveです。
ノードの状態を解放状態にすることで、タスクが振られなくなります。
あと、動いてたタスクは他のActiveなノードに移動します。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
30k0ojv3slev13x0nhryhblq7 my-swarm-worker-mz79 Ready Active
8x1ev7mve4znsgs9f4n7rqa5x * my-swarm-manager Ready Active Leader
b1scfttgcghn1z36ng182nv0a my-swarm-worker-bvm1 Ready Active
bg23v4d8jdi953blfbl4xnixf my-swarm-worker-ir8d Ready Active
$ docker node update my-swarm-worker-bvm1 --availability drain
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
30k0ojv3slev13x0nhryhblq7 my-swarm-worker-mz79 Ready Active
8x1ev7mve4znsgs9f4n7rqa5x * my-swarm-manager Ready Active Leader
b1scfttgcghn1z36ng182nv0a my-swarm-worker-bvm1 Ready Drain
bg23v4d8jdi953blfbl4xnixf my-swarm-worker-ir8d Ready Active
このDrainをマネージャノードに適用すると、最初の方に書いたmanager-only nodeになります。
Drainの間はタスクは振られません。
Activeに戻せば、タスクが振られるようになります。
その他Tips
シャットダウンしたサービスがうざい
docker service ps
使うとサービスの状態が見れますが、そのままだとシャットダウンされたやつもツリー表示されてて邪魔くさいです。
というわけで便利なフィルタパラメータ。
docker service ps web -f desired-stat=Running
これで動いてるサービスだけ表示できます。
他にidとかnameとかあるけど実際つかわんやろ。
だいぶ長くなったので、とりあえずこれくらいで。
続きはまた後で。