Created 2018年6月27日12:20
Updated 2018年7月6日11:24
Categories
Docker
自宅サーバー
swarm
以前からdocker swarmについてまとめようと思っていたので、この機会にまとめておきます。
とはいえ今はKubernetesがオーケストレーションツールとしてはデファクトになっているので、ガッツリ使うには向かないかもしれません。
しかし、Dockerのデフォルトの機能として入っており、なおかつ手軽に使えるという点ではかなり便利です。
我が家の自宅サーバーも冗長化にdocker swarmを使っており、かなり手軽に冗長構成を実現できますので、ライトな自宅サーバー勢には十分おススメできると思います。
本稿では、とりあえずdocker swarmでクラスタを作成してサービスを展開してみるところまでを紹介したいと思います。
まず、構築するノードを4台用意します。
物理サーバーを準備するのは面倒なのでdocker-machine
コマンドを使って仮想マシンを作ります。
docker-machine create --driver virtualbox swarm1
docker-machine create --driver virtualbox swarm2
docker-machine create --driver virtualbox swarm3
docker-machine create --driver virtualbox swarm4
作った仮想マシンを確認してみましょう。
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
swarm1 - virtualbox Running tcp://192.168.99.100:2376 v18.05.0-ce
swarm2 - virtualbox Running tcp://192.168.99.101:2376 v18.05.0-ce
swarm3 - virtualbox Running tcp://192.168.99.102:2376 v18.05.0-ce
swarm4 - virtualbox Running tcp://192.168.99.103:2376 v18.05.0-ce
続いてswarmクラスタを初期化します。
初期化にはマシンのIPアドレスが必要なので、docker-machine ip
コマンドで調べます。
$ docker-machine ip swarm1
192.168.99.100
swarm1のDockerデーモンに接続して、swarmクラスタの初期化を行います。
$ eval "$(docker-machine env swarm1)"
$ docker swarm init --advertise-addr 192.168.99.100
Swarm initialized: current node (ucjwdjmhay5yoneclus2ocdfm) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-4sf90z050mwii6mtq599fk2d6cma51tuxulz8txiwomh6jsued-6wffxdh7cyxc0ei4lj9ycdf27 192.168.99.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
swarm1がリーダーノードとして初期化されました。
ただ、このままではswarm1がダウンした際にクラスタがダウンしてしまうので、リーダーノードをもう1台追加します。
リーダーを追加する場合は、次のコマンドでトークンを調べます。
$ docker swarm join-token manager
To add a manager to this swarm, run the following command:
docker swarm join --token SWMTKN-1-4sf90z050mwii6mtq599fk2d6cma51tuxulz8txiwomh6jsued-62ihat1ahqs06tzuzzznfwg8q 192.168.99.100:2377
丁寧に実行するコマンドまで教えてくれるので、swarm2に接続してこちらを実行しましょう。
$ eval "$(docker-machine env swarm2)"
$ docker swarm join --token SWMTKN-1-4sf90z050mwii6mtq599fk2d6cma51tuxulz8txiwomh6jsued-62ihat1ahqs06tzuzzznfwg8q 192.168.99.100:2377
This node joined a swarm as a manager.
これでリーダーノードが2台に増えました。どちらかが落ちた場合は、残っている方がリーダーとなります。
続いてワーカーを追加します。
追加するにはswarm1でのdocker swarm init
時に表示されていたコマンドをswarm3とswarm4で実行します。
$ eval "$(docker-machine env swarm3)"
$ docker swarm join --token SWMTKN-1-4sf90z050mwii6mtq599fk2d6cma51tuxulz8txiwomh6jsued-6wffxdh7cyxc0ei4lj9ycdf27 192.168.99.100:2377
This node joined a swarm as a worker.
$ eval "$(docker-machine env swarm4)"
$ docker swarm join --token SWMTKN-1-4sf90z050mwii6mtq599fk2d6cma51tuxulz8txiwomh6jsued-6wffxdh7cyxc0ei4lj9ycdf27 192.168.99.100:2377
This node joined a swarm as a worker.
ここまでの作業でリーダー2台、ワーカー2台のswarmクラスタが作成できました。
再びswarm1に接続し、クラスタの内容を確認してみましょう。
$ eval "$(docker-machine env swarm1)"
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
ucjwdjmhay5yoneclus2ocdfm * swarm1 Ready Active Leader 18.05.0-ce
llgmuqlmpj7cqusxjamv16rdg swarm2 Ready Active Reachable 18.05.0-ce
ba994vu4dksynpfkt4eqd0hji swarm3 Ready Active 18.05.0-ce
jldw462nkzy9maowqm9gpeb7w swarm4 Ready Active 18.05.0-ce
クラスタが作成できたので、いよいよサービスを展開していきます。
今回はシンプルにHTMLを表示するWebサイトをnginxコンテナとして建ててみましょう。
まず、ローカルにhtmlリソースとなるディレクトリを作成し、swarm1~4にマウントポイントを作成します。
$ mkdir -p mnt/html
$ docker-machine ssh swarm1 mkdir html
$ docker-machine ssh swarm2 mkdir html
$ docker-machine ssh swarm3 mkdir html
$ docker-machine ssh swarm4 mkdir html
ちなみに、docker-machineで作成される仮想マシンはboot2dockerというイメージを使っており、ホームディレクトリは/home/docker
となります。
なので、このコマンドでは/home/docker/html
が作成されています。
続いて、mnt/html
内にindex.htmlを配置します。
$ nano mnt/html/index.html
Hello swarm!!
最後にdocker-machine mount
コマンドを用いてmnt/html
をswarm1~4の/home/docker/html
にマウントします。
sudo docker-machine mount swarm1:/home/docker/html mnt/html
sudo docker-machine mount swarm2:/home/docker/html mnt/html
sudo docker-machine mount swarm3:/home/docker/html mnt/html
sudo docker-machine mount swarm4:/home/docker/html mnt/html
これですべてのノードから同一のリソースを参照できるようになりました。
続いて、クラスタに展開するサービスの設定を書いていきます。
サービスの設定はdocker-composeと同じ書式でstack.yml
というファイルに記述します。
今回は以下の条件の設定を記述しました。
/home/docker/html
をリソースとしてマウント$ nano stack.yml
version: '3.3'
services:
nginx:
image: nginx
ports:
# 外部からの8080番へのアクセスをnginxの80番に仕向ける
- 8080:80
deploy:
# 全てのノードに展開する
mode: global
volumes:
# htmlディレクトリをマウントしてnginxのリソースとして使用する
- /home/docker/html:/usr/share/nginx/html:ro
設定ができたので、docker stack deploy
コマンドでtest
というstack名でクラスタに展開します。
展開したら、docker service ls
でサービスが無事にデプロイできているか確認してください。
$ docker stack deploy -c stack.yml test
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
rvr59910pl3p test_nginx global 4/4 nginx:latest *:8080->80/tcp
REPLICASが4/4となっているので、4ノード全てに展開できていることが確認できました。
続いて、クラスタの一部のノードにサービスを展開してみます。
docker stack rm
で先ほど展開したサービスを削除して、stack.yml
を少し編集します。
$ docker stack rm test
$ nano stack.yml
...
deploy:
# クラスタ中の2台に展開
mode: replicated
replicas: 2
...
この設定だと、クラスタ内から選ばれた2台にnginxが展開されます。
もう一度docker stack deploy
でサービスを展開してください。
$ docker stack deploy -c stack.yml test
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
nxe74tu11s1j test_nginx replicated 2/2 nginx:latest *:8080->80/tcp
今度はREPLICASの値が2になっていますね。
どのノードでサービスを展開しているか調べます。
$ docker stack ps test
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
u52pbqn4xdjn test_nginx.1 nginx:latest swarm2 Running Running 8 minutes ago
q8ralejxn1oe test_nginx.2 nginx:latest swarm1 Running Running 8 minutes ago
swarm1とswarm2に展開されているようですね。
docker service scale
コマンドでnginxをクラスタ内の3台に展開するよう設定してみましょう。
$ docker service scale test_nginx=3
test_nginx scaled to 3
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
$ docker stack ps test
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
u52pbqn4xdjn test_nginx.1 nginx:latest swarm2 Running Running 9 minutes ago
q8ralejxn1oe test_nginx.2 nginx:latest swarm1 Running Running 9 minutes ago
215vusgx0dpm test_nginx.3 nginx:latest swarm3 Running Running 20 seconds ago
swarm3にもnginxが展開され、3台の冗長構成になりました。
手軽にサービスをスケールできてとても良いですね。
さて、せっかく冗長構成にしたので、ノードを1台落としてフェイルケースを試してみましょう。
現在、swarm1~3の3台にnginxが展開されていますが、もしswarm3が何かしらの理由でシャットダウンしてしまったらどうなるでしょうか。
$ docker-machine stop swarm3
(少し時間をおきます)
$ docker stack ps test
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
u52pbqn4xdjn test_nginx.1 nginx:latest swarm2 Running Running 12 minutes ago
q8ralejxn1oe test_nginx.2 nginx:latest swarm1 Running Running 12 minutes ago
szpb28c5uorv test_nginx.3 nginx:latest swarm4 Running Running 2 seconds ago
215vusgx0dpm \_ test_nginx.3 nginx:latest swarm3 Shutdown Running 18 seconds ago
swarm3がシャットダウンとなり、代わりにswarm4でnginxが実行されています。
クラスタ内のノードが落ちてしまった場合にもしっかりとスケールの規模が維持されることが確認できました。
とりあえず今回はここまでです。今後も複雑なサービスの展開や続きの記事を書きたいと思いますので、その際はこちらに引用を追加したいと思います。
今回紹介した手法は物理マシンにも同じように適用可能です(セキュリティや共有ファイルの設定についてはちゃんと考える必要がありますが・・・)。
自宅サーバーは定期的に掃除したりシステムをアップデートしたりする際にどうしてもダウンタイムが発生しがちですが、docker swarm
をうまく使ってあげればダウンタイム無しでのクラスタのアップデートも夢ではありません。
何より、手軽にクラスタが連携してる感を味わえますのでとても楽しいです。
docker swarmを使って自宅サーバーライフを楽しんでいただければ幸いです。
試してみました。とても参考になります。 1点、 docker-machine mount swarm1:/home/docker/html mnt/html のところで、以下のようなエラーになり実行できません。 You must have a copy of the sshfs binary locally to use the mount feature なにかヒントがあればよろしくお願い致します。
管理人です。返信が遅れてしまいすみません。けろっぴさんはおそらくWindowsで実行されていると思うのですが、WindowsではDocker Swarmを動かすにあたって不都合が多いのだと思います。ネットでけろっぴさんが遭遇したエラー文を検索するといくつか解決策のような書き込みが見つかりましたが、UbuntuなどのLinuxで試すというのが全体的に成功率が高くておススメです(DockerはもともとLinux向けに作られたものなので、Linuxと相性が良いのだと思います)。