Part 4:Swarm

必要条件

  • Docker バージョン 1.13 以上のインストール
  • Docker Machine を入手。 Docker for Mac と Docker for Windows ではインストール済みですので、このまま読み進めてください。Linux システムでは 直接インストール をお使い下さい。
  • Part 1 の概要を読んでいること
  • Part 2 のコンテナの作成方法学んでいること
  • 自分で作成した friendlyhello イメージを レジストリに送信 して公開済みなのを確認します。ここでは、この共有イメージを使います。
  • イメージをコンテナとしてデプロイできるのを確認します。次のコマンドを実行しますが、 ユーザ名リポジトリ タグ は皆さんのものに置き換えます。コマンドは docker run -p 80:80 ユーザ名/リポジトリ:タグ です。そして http://localhost/ を表示します。
  • Part 3 で扱った docker-compose.yml のコピーを持っていること

はじめに

Part 3 では、 Part 2 で書いたアプリを元に、プロダクションで実行可能にサービスとして調整したものを定義し、5つのプロセスへとスケールアップしました。

この Part 4 では、アプリケーションをクラスタにデプロイし、複数のマシン上で実行します。複数のコンテナ、複数のマシンにおけるアプリケーションは、 swarm (スウォーム)と呼ぶ複数のマシンが参加する「Docker化」(Dockerized)クラスタで利用可能になります。

Swarm クラスタの理解

swarm とは Docker が動作し、クラスタに参加しているマシン・グループです。swarm を使えば、Docker コマンドをこれまで通り使い続けながら、 swam マネージャ を通してクラスタ上で実行可能になります。swarm 上のマシンは物理あるいは仮想どちらも使えます。swarm に加わった後は、これらは ノード として参照されます。

swarm マネージャはコンテナの実行時、複数のストラテジ(strategy;計画、方針)を扱います。例えば「emptiest node」(最も空いているノード)であれば、最も使われていないマシンが選ばれます。あるいは「global」(グローバル)であれば、特定の1つのマシンだけでなく、すべてのマシン上で特定のコンテナを実行します。このように様々なストラテジがありますが、 swarm マネージャには Compose ファイルを通して命令できます。

swarm マネージャは swarm における単なるマシンであり、コマンドの実行や、swarm に参加したマシンを ワーカ(workers) として認証できます。ワーカは収容能力(キャパシティ)を提供するのみであり、他のマシンに対して何ができる・できないといった権限を持ちません。

これまではローカルマシン上の単一ホスト上で動く Docker を使ってきました。しかし、Docker は swarm mode に切り替え可能であり、swarm(クラスタ)上でも利用できます。現在のマシンを swarm マネージャとしたら、簡単に swarm モードを有効化できます。あとは、現在のマシンで Docker を操作する代わりに、swarm クラスタ上で処理します。

swarm のセットアップ

swarm は複数のノードで構成します。物理マシンまたは仮想マシンどちらでもノードになれます。基本概念は極めてシンプルです。 docker swarm init を実行すると、 swarm mode を有効化し、現在のマシンを swarm マネージャにします。そして docker swarm join を実行し、他のマシンをワーカとして swarm に追加します。環境に応じて以下の項目を読み進めてください。ここでは2つの仮想マシを素早く作成し、swarm に追加します。

クラスタの作成

ローカルマシン上の仮想マシン(Mac、Linux、Windows 7 および 8)

まず、仮想マシンを作成できるハイパーバイザが必要です。そのため、各マシンの OS に対応した VirtualBox をインストール します。

Note: If you’re on a Windows system that has Hyper-V installed, such as Windows 10, there is no need to install VirtualBox and you should use Hyper-V instead. View the instructions for Hyper-V systems by clicking the Hyper-V tab above.

注釈

WIndows 10 のような Hyper-V をインストールした WIndows システムをお使いの場合、Hyper-V を利用する代わりに VirtualBox のインストールが必要です。ページ下方の Hyper-V に関する項目をご覧ください。

次に docker-machine を使い、2つの仮想マシンを作成します。ここでは VirtualBox ドライバを使います。

$ docker-machine create --driver virtualbox myvm1
$ docker-machine create --driver virtualbox myvm2

ローカルマシン上の仮想マシン(Windows 10/Hyper-V)

まず、仮想マシンが共有する仮想スイッチを作成したら、仮想マシンがお互い接続可能になります。

  1. Hyper-V マネージャを起動
  2. 右側メニューにある Virtual Switch Manager をクリック
  3. Create Virtual SwitchExternal タイプをクリック
  4. 名前を myswitch に指定子、ホストマシンのアクティブ・ネットワーク・アダプタとの共有ボックスにチェックを入れる

次にノード管理ツール docker-machine を使い、2つの仮想マシンを作成します。

$ docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm1
$ docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm2

作成

このように myvm1myvm2 という名前の2つの仮想マシン( docker-machine ls で表示 )を作成しました。1つめはマネージャとして docker コマンドを実行し、ワーカを swarm に追加する認証をします。2つめはワーカにします。

仮想マシンには docker-machine ssh を使ってコマンドを送ります。 myvm2 に対して docker swarm init で swarm マネージャになるよう命令します。次のような実行結果になるでしょう。

$ docker-machine ssh myvm1 "docker swarm init"
Swarm initialized: current node <node ID> is now a manager.

To add a worker to this swarm, run the following command:

  docker swarm join \
  --token <token> \
  <ip>:<port>

ヒント

エラーが出る場合は、 --advertise-addr を使う必要があるかもしれません

docker-machine ls を実行し、 myvm1 の IP アドレスをコピーします。それから docker swarm init コマンドを再び実行しますが、 --advertise-addr で IP アドレスとポート 2377 を指定(swarm が join に使うポート)します。実行例:

docker-machine ssh myvm1 "docker swarm init --advertise-addr 192.168.99.100:2377"

ご覧の通り、 docker swarm init の応答があれば、必要なあらゆるノードをあらかじめ調整済みの docker swarm join で追加できます。 myvm2 を新しい swarm でワーカとして追加するには、次のコマンドをコピーし、 docker-machine ssh 経由で myvm2 に送信します。

$ docker-machine ssh myvm2 "docker swarm join \
--token <token> \
<ip>:<port>"

This node joined a swarm as a worker.

これで初めての swarm (クラスタ)が完成しました。お疲れさまでした。

注釈

別の方法として、 docker-machine ssh myvm2 でコマンドを付与しなければ、仮想マシンに対するターミナル・セッションを開きます。ホスト側のシェル・プロンプトに戻る準備が整えば、 exit を実行します。場合によっては join コマンドを実行するよりも簡単でしょう。

ssh を使って接続し( docker-machine ssh myvm1 )、 この swarm のノード一覧を表示するため docker node ls を実行します。

docker@myvm1:~$ docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
brtu9urxwfd5j0zrmkubhpkbd     myvm2               Ready               Active
rihwohkh3ph38fhillhhb84sk *   myvm1               Ready               Active              Leader

exit を実行し、マシン側に戻ります。

別の方法として、 docker-machine ssh でコマンドをまとめ、直接ログインしてログアウトもできます。実行例:

docker-machine ssh myvm1 "docker node ls"

アプリをクラスタ上にデプロイ

大変な部分は終わりました。次は Part 3 で用いた手順を、新しい swarm 上で繰り返します。 myvm1 のような swarm マネージャは Docker コマンドを実行できるのを思い出してください。ワーカはキャパシティ(収容能力)のためのみです。

part 3 で作成した docker-compose.yml ファイルを、 swarm マネージャ myvm1 のホームディレクトリ(別名: ~ )に docker-machine scp コマンドを使ってコピーします。

docker-machine scp docker-compose.yml myvm1:~

これで myvm1 は swarm マネージャの力によりアプリをデプロイできるようになりました。part 3 で使ったのと同じ docker stack deploy コマンドを docker-machine ssh コマンドで myvm1 に送信します。

docker-machine ssh myvm1 "docker stack deploy -c docker-compose.yml getstartedlab"

これだけの作業で、アプリはクラスタ上にデプロイされました。

part 3 で使った全てのコマンドを docker-machine ssh で送るだけで、全て期待通りに動作します。今回のケースでは、コンテナは myvm1myvm2 の両方に分散したことが分かります。

$ docker-machine ssh myvm1 "docker stack ps getstartedlab"

ID            NAME        IMAGE              NODE   DESIRED STATE
jq2g3qp8nzwx  test_web.1  username/repo:tag  myvm1  Running
88wgshobzoxl  test_web.2  username/repo:tag  myvm2  Running
vbb1qbkb0o2z  test_web.3  username/repo:tag  myvm2  Running
ghii74p9budx  test_web.4  username/repo:tag  myvm1  Running
0prmarhavs87  test_web.5  username/repo:tag  myvm2  Running

クラスタにアクセス

アプリに対しては myvm1myvm2どちらか の IP アドレスでアクセスできます。作成したネットワークは双方のホストで共有され、負荷分散できます。 docker-machine ls を実行しs手仮想マシンの IP アドレスを確認し、ブラウザでどちらかを表示し、それから再読み込みします(あるいは curl でも同様です)。読み込み直すたびに、ランダムに5つのコンテナ ID のどれかを表示するでしょう。負荷分散のデモンストレーションです。

どちらの IP アドレスでも動作する理由は、swarm の各ノードが ingress ルーティング・メッシュ(rougint mesh) に所属しているからです。これにより、サービスのデプロイにあたり swarm 上で指定したポートを確保できるよう、コンテナが実際にどのノードで実行中か気にすることなく、ノード自身がポートを予約します。下図は my-web という名前のサービスが公開するポート 8080 を、3つの swarm ノード上で、どのようにルーティング・メッシュするかの説明です。

ingress ルーティング・メッシュ

ヒント

接続に問題がありますか?

swarm で ingress ネットワークを使うためには、swarm モード有効にする前に、swarm ノード間で以下のポートを開く必要がありますので、ご注意ください。

  • Port 7946 TCP/UDP を、コンテナのネットワーク・ディスカバリ用に
  • Port 4789UDP をコンテナ ingress ネットワーク用に

アプリの繰り返しとスケーリング

ここからは part 3 で学んだ全ての動作を行えます。

アプリのスケールは、docker-compose.yml ファイルを変更します。

アプリの挙動を変更するには、コードを編集します。

いずれにしろ、変更を反映(デプロイ)するには docker stack deploy を再び実行するだけです。

物理マシンと仮想マシンのどちらにしても、 myvm2 に対して実行したのと 同じ docker swarm join コマンドを使って swarm に追加でき、クラスタの収容能力に追加できます。そして docker stack deploy を実行するだけで、アプリは新しいリソースを利用可能になります。

クリーンアップ

スタックは docker stack rm で解体できます。実行例:

docker-machine ssh myvm1 "docker stack rm getstartedlab"

ヒント

swarm は維持?それとも削除?

後々、必要に応じてワーカを削除したい場合は docker-machine ssh myvm2 "docker swarm leave" を、マネージャの削除は docker-machine ssh myvm1 "docker swarm leave --force" で行えます。 ですが、swarm は part 5 でも使いますので、今はこのままにしておいてください。

まとめとチート・シート(オプション)

このページで扱ったターミナルの録画 がこちらです。

Part 4 では、swarm とは何か、swarm においてノードをマネージャまたはワーカにする方法、swarm の作成と、そこにアプリケーションをデプロイする方法を学びました。ご覧の通り、主なコマンドは part 3 と変わることはなく、単に実行対象が swarm マネージャになっただけでした。また、Docker ネットワークの力もご覧になったでしょう。コンテナ間で負荷分散(ロードバランサ)を組めるだけでなく、コンテナが異なったマシン上で実行していても可能なのです。最後に、クラスタ上でアプリの繰り返しとスケールを学びました。

ここでは swarm 上で実行すると便利なコマンドをいくつか紹介します。

docker-machine create --driver virtualbox myvm1          # 仮想マシン作成 (Mac, Win7, Linux)
docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm1             # Win10
docker-machine env myvm1                                      # ノードに関する基本情報の表示
docker-machine ssh myvm1 "docker node ls"                               # swarm のノード一覧
docker-machine ssh myvm1 "docker node inspect <node ID>"                      # ノードの調査
docker-machine ssh myvm1 "docker swarm join-token -q worker"           # join トークンの表示
docker-machine ssh myvm1          # 仮想マシンの SSH セッションを開く;"exit" を入力して終了
docker-machine ssh myvm2 "docker swarm leave"                      # ワーカを swarm から離脱
docker-machine ssh myvm1 "docker swarm leave -f"            # マスターを離脱し、swarm を停止
docker-machine start myvm1                            # 仮想マシンが起動していなければ、起動
docker-machine stop $(docker-machine ls -q)                 # 実行中の全ての仮想マシンを停止
docker-machine rm $(docker-machine ls -q)       # 全ての仮想マシンとディスク・イメージを削除
docker-machine scp docker-compose.yml myvm1:~ # ファイルをノードのホームディレクトリにコピー
docker-machine ssh myvm1 "docker stack deploy -c <file> <app>"            # アプリをデプロイ