Part 4:Swarm

必要条件

  • Docker バージョン 1.13 またはそれ以上をインストールしていること。
  • Part 3 の必要条件 で説明した Docker Compose を入手していること。
  • Docker Machine を入手していること。 Docker for Mac と Docker for Windows ではインストール済みであるが Linux システムでは 直接インストール が必要。
  • Part 1 の概要を読んでいること。
  • Part 2 のコンテナの作成方法を理解していること。
  • レジストリに送信 して作成した friendlyhello イメージが共有可能であることを確認します。ここではその共有イメージを使います。
  • デプロイしたコンテナとしてイメージが動作することを確認します。以下のコマンドを実行してください。docker run -p 80:80 username/repo:tag ここで username、repo、tag の部分は各環境に合わせて書き換えてください。そして http://localhost/ にアクセスします。
  • Part 3 で扱った docker-compose.yml ファイルが用意できていること。

はじめに

Part 3 では、 Part 2 で書いたアプリを元に、本番環境において実行可能なサービスとして調整したものを定義し、プロセスを5倍にスケールアップしました。

この Part 4 では、デプロイするアプリケーションをクラスタにして、複数のマシン上で実行します。複数コンテナ、複数マシンによるアプリケーションは、各マシンを「Docker化」(Dockerized)したクラスタ、すなわち swarm (スウォーム)と呼ばれるものに集約することによって実現されます。

Swarm クラスタの理解

swarm とは Docker の動作するマシンがひとまとまりとなってクラスタを構成するものです。swarm を使うようになると、これまで使ってきた Docker コマンドは引き続き用いることにはなりますが、今度はクラスタに対しての swarm マネージャ として処理操作を行うものとなります。swarm 内のマシンは物理マシン、仮想マシンのいずれでも構いません。マシンを swarm に含めた後は、 ノード として参照されます。

swarm マネージャでは、コンテナの実行にあたってストラテジというものが指定できます。たとえば「emptiest node」(最も空いているノード)です。これは最も使われていないマシンをコンテナに割り当てます。「global」というものは、個々のマシンには、指定されたコンテナの1インスタンスのみを割り当てます。swarm マネージャに対してのストラテジ指定は Compose ファイルにて行います。既に利用してきたファイルです。

swarm マネージャは swarm 内でコマンド実行ができる唯一のマシンです。 そして他のマシンの swarm への参加を認証します。 swarm に参加したマシンは ワーカ (worker)と呼ばれます。 ワーカは処理提供するために加えられたわけですが、他のマシンの機能を制約する権限を持つわけではありません。

これまではローカルマシン上において、シングルホストモードにより Docker を利用してきました。Docker は swarm モード に切り替えることが可能であり、このモードにすることで swarm が利用できるようになります。swarm を有効にした時点で現在のマシンが swarm マネージャとなります。これ以降の Docker に対するコマンドは swarm に対して実行されます。もうそれまでのマシンに対して実行するものではなくなります。

swarm のセットアップ

swarm は複数のノードにより構成されます。それは物理マシン、仮想マシンのどちらでも構いません。基本的な考え方はとても簡単です。 docker swarm init の実行により swarm モードが有効となり、現在のマシンが 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 システムの場合、VirtualBox のインストールは不要であり、かわりに Hyper-V を利用してください。上記の Hyper-V に関するタブをクリックして Hyper-V システムの手順を参照してください。Docker Toolbox を利用する場合は、その一部としてすでに VirtualBox がインストールされるため、このまま先に進んでください。

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

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

ローカルマシン上の仮想マシン(Windows 10)

はじめに、仮想マシンが共有する仮想スイッチを作成して、仮想マシンが互いに接続できるようにします。

  1. Hyper-V マネージャーを起動
  2. 右側のメニューにある 仮想スイッチ マネージャー をクリック
  3. 仮想スイッチの作成 のタイプ 外部 をクリック
  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 を使ってコマンドを送ります。 myvm1 に対して 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 を実行して仮想マシンの 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>"            # アプリをデプロイ