仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

Docker Swarm modeを使ってコンテナアプリを展開してみる

[2020/04/20追記] MACアドレスを一部マスクしました。

Dockerは最もポピュラーなコンテナープラットフォームで、多くのユーザーに使われていると思います。 Dockerはアプリケーションの実行を迅速に行えるのがメリットです。万が一サービスに支障があった場合もDockerが正常に動くホストを用意して数行コマンドを実行するだけでアプリケーションを復旧可能な点がメリットです。

Docker 1.12以降のバージョンでは、Docker Swarm modeという機能が実装されるようになりました。おそらく現在Dockerを使っているユーザーはそれよりも新しいバージョンのDockerを使っていると思います。Docker Swarm modeを使えば簡単にコンテナークラスターを作ることができます。

本ブログでは主にKubernetesをよく取り上げていますが、今回はDocker Swarm mode(以下Swarm mode)の基本的な使い方についても紹介したいと思います。

以下はUbuntu Server 18.04.4 LTSで利用する流れを想定しています。ちなみに間も無くリリース予定のUbuntu 20.04 LTSでもDockerパッケージが用意されているので、今後もしばらくはDockerを使えそうで安心してます。

Swarm modeを使ったコンテナクラスターのセットアップ

Dockerのインストール

UbuntuにDockerをインストールします。バージョン19.03をインストールできます。

$ sudo apt update && sudo apt install -y docker.io && sudo systemctl enable --now docker

マネージャーノード作成

Swarm modeのマネージャーノードをセットアップします。listen-addrはそのノードのIPアドレスを指定します。 正常に実行できると、2台目以降のノードをクラスターに参加させるためのコマンドが表示されます。

$ sudo docker swarm init --listen-addr 172.17.28.99:2377

2台目以降のノード

2台目以降は docker swarm join コマンドを実行します。 先に実行した際に表示された docker swarm join コマンドを実行します。後から確認する場合は sudo docker swarm join-token (worker or manager) コマンドを実行してトークンキーを含んだコマンドを確認します。

今回は残りのノードは全てWorkerにするので、2台目以降のノードで次のように実行します。トークンキーとIPアドレスについては実際の物に置き換えて実行してください。

$ sudo docker swarm join --token SWMTKN-1-4lg6fg368g9td1ysvdnmvmo27a9quekdl9juaukob97jpzn2q3-djifh3mqpg6rlknwienodbsrz 172.17.28.99:2377

ノード一覧を確認

クラスターにノードを追加し終わると、 sudo docker node ls コマンドでノードの一覧が表示されます。

$ sudo docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
8r9erj75bvd1j88x9so24yfdt *   docker1             Ready               Active              Leader              19.03.6
zqiptycwmkaqvxko08duxfp2o     docker2             Ready               Active                                  19.03.6
i5pzjf56cdk7er0mj3ar5gbv8     docker3             Ready               Active                                  19.03.6
utrg0hx6robagpj1f4e0oxupb     docker4             Ready               Active                                  19.03.6

コンテナアプリを展開してみる

Dockerでアプリを展開するにはコマンドとオプション、パラメーターを使って行うか、Docker Composeを使ってYAMLファイルにデプロイしたいアプリケーションとパラメーターを記述して docker-compose up -d コマンドなどでアプリケーションを展開しました。

Docker Composeは非常に便利なのですが、Swarm modeでもYAMLファイルに書いた内容でアプリケーションを展開できます。

プロジェクトディレクトリを作成

まずはプロジェクトディレクトリーを作成します。ここはDocker Composeを使う時と同じです。

$ mkdir demo
$ cd demo

Compose YAMLを作成

まずは永続データという概念を忘れて、次のようなシンプルなYAMLファイルを書いてみます。

$ vi docker-compose.yml
version: '3'
services:
  nginx:
    image: nginx:alpine
    deploy:
      replicas: 2
    ports:
      - 51080:80

アプリをデプロイ

docker stack deploy コマンドを使ってアプリを展開します。

$ sudo docker stack deploy -c docker-compose.yml nginx

実行すると、ネットワークとサービスが作成されて、次のように標準出力されます。

Creating network nginx_default
Creating service nginx_nginx

Stackの確認

コンテナーが作られたことが確認できます。

$ sudo docker stack ls
NAME                SERVICES            ORCHESTRATOR
nginx               1                   Swarm

$ sudo docker stack ps nginx
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
icjdfqwrkicr        nginx_nginx.1       nginx:alpine        docker2             Running             Running 13 seconds ago                       
netw17314xy6        nginx_nginx.2       nginx:alpine        docker1             Running             Running 13 seconds ago       

Serviceの確認

サービスが作られたことがわかります。

$ sudo docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
mfszzmpnyzqv        nginx_nginx         replicated          2/2                 nginx:alpine        *:51080->80/tcp

$ sudo docker service ps nginx_nginx
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
icjdfqwrkicr        nginx_nginx.1       nginx:alpine        docker2             Running             Running about a minute ago                       
netw17314xy6        nginx_nginx.2       nginx:alpine        docker1             Running             Running about a minute ago

コンテナネットワークの確認

コンテナネットワークも確認してみましょう。

$ sudo docker network inspect nginx_default
[
    {
        "Name": "nginx_default",
        "Id": "wg8nyp0mcbjyoezn54yqhcb51",
        "Created": "2020-04-20T00:50:23.009084615Z",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.1.0/24",
                    "Gateway": "10.0.1.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "19d71f6c4a7658fe7e20ae4cb60b6547c90c7743473cce78e0ba49fa14ad47c1": {
                "Name": "nginx_nginx.2.netw17314xy6hv8i5anh921lm",
                "EndpointID": "148110e6237f3f8b41362432af554a47e5aae19dcac15be268446b66eac3b128",
                "MacAddress": "02:42:0a:00:xx:zz",
                "IPv4Address": "10.0.1.4/24",
                "IPv6Address": ""
            },
            "lb-nginx_default": {
                "Name": "nginx_default-endpoint",
                "EndpointID": "4bdd32c9a63429bf94543d3236ea09920443f453124808846c0e4ccfc60a58e8",
                "MacAddress": "02:42:0a:00:xx:zz",
                "IPv4Address": "10.0.1.6/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.driver.overlay.vxlanid_list": "4097"
        },
        "Labels": {
            "com.docker.stack.namespace": "nginx"
        },
        "Peers": [
            {
                "Name": "70d40231e046",
                "IP": "172.17.28.99"
            },
            {
                "Name": "9370d2b12ac9",
                "IP": "172.17.28.96"
            }
        ]
    }
]

Ingressの確認

Ingressの確認は次のように行います。Docker Swarm modeで複数のアプリケーションを実行する場合はこのIngressを使ってコンテナーアプリケーションにアクセスできます。

$ sudo docker network inspect ingress
[
    {
        "Name": "ingress",
        "Id": "kpgo1irlexh4hbewuy7ag8f5e",
        "Created": "2020-04-20T00:42:23.29114384Z",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": true,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "19d71f6c4a7658fe7e20ae4cb60b6547c90c7743473cce78e0ba49fa14ad47c1": {
                "Name": "nginx_nginx.2.netw17314xy6hv8i5anh921lm",
                "EndpointID": "668e92dd068329b60fc9b6df6d174578209af3823893f19237077542400e207c",
                "MacAddress": "02:42:0a:00:xx:zz",
                "IPv4Address": "10.0.0.8/24",
                "IPv6Address": ""
            },
            "ingress-sbox": {
                "Name": "ingress-endpoint",
                "EndpointID": "5608bfec46fdd5d0b138673c02499440ffe56fead5951a0b2e99adb29d0ea5ea",
                "MacAddress": "02:42:0a:00:xx:zz",
                "IPv4Address": "10.0.0.2/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.driver.overlay.vxlanid_list": "4096"
        },
        "Labels": {},
        "Peers": [
            {
                "Name": "70d40231e046",
                "IP": "172.17.28.99"
            },
            {
                "Name": "9370d2b12ac9",
                "IP": "172.17.28.96"
            },
            {
                "Name": "e06b209d80ed",
                "IP": "172.17.28.102"
            },
            {
                "Name": "9cf0109b5005",
                "IP": "172.17.28.186"
            }
        ]
    }
]

ブラウザでアクセスしてみる

マネージャーノードに指定したポート宛でアクセスしてみましょう。NGINXのデフォルトページが表示されるはずです。

f:id:virtualtech:20200420135412p:plain
NGINX default page

永続データを考慮してみる

永続したデータの置き場としてDocker Volumeを利用する方法で説明します。 より詳しく知りたい場合は以下のドキュメント(Use Volumes)を確認してください。

Volumeの作成

全てのノードで以下を実行し、Dockerボリュームを作成します。今回はLocalドライバーを用いていますが、Dockerには永続データの持たせ方としていくつかの方法がありますので、前のリンク先の情報で確認してください。

$ sudo docker volume create web-data

以下コマンドを実行して、ボリュームが作成できているか確認します。「web-data」という名前のボリュームが作られていることを確認します。

$ sudo docker volume ls
DRIVER              VOLUME NAME
local               web-data

永続データを考慮したCompose YAMLを書いてみる

前半の記述は前のものと一緒ですが、volumesの項目が少々増えているのがわかると思います。次例はLocalドライバーベースの「web-data」という名前のDocker Volumeをコンテナーのディレクトリー「/usr/share/nginx/html」にマウントするように記述しています。

ちなみに今回は一般に配布されているDockerイメージを使っていますが、本来はアプリケーションやHTMLなどのコンテンツを含めたカスタムDockerイメージを作った上でCompose YAMLにそのイメージを指定する必要があります。

version: '3'
services:
  nginx:
    image: nginx:alpine
    deploy:
      replicas: 2
    volumes:
      - web-data:/usr/share/nginx/html
    ports:
      - 52080:80
volumes:
  web-data:
    driver: local

アプリケーションの展開

YAMLファイルを準備できたら、前半同様にコマンドを実行して展開してみましょう。アプリケーション名は変更しておきます。

$ sudo docker stack deploy -c docker-compose.yml nginx-vol
Creating network nginx-vol_default
Creating service nginx-vol_nginx

$ sudo docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
v5va53z7fc35        nginx-vol_nginx     replicated          2/2                 nginx:alpine        *:52080->80/tcp

同様に、サービスポートにアクセスすると、NGINXのデフォルトページが表示されます。

アプリケーションを編集してみる

デフォルトのページをみていてもしょうがないので、ちょっと編集してみましょう。 まずはどこのDockerホストにアプリケーションコンテナーが展開されたか確認します。

docker3とdocker4に展開されたようです。

$ sudo docker service ps nginx-vol_nginx
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
7ytywp67l9py        nginx-vol_nginx.1   nginx:alpine        docker3             Running             Running 8 minutes ago                       
cqjfqxw9sb4j        nginx-vol_nginx.2   nginx:alpine        docker4             Running             Running 8 minutes ago             

sudo docker container ls コマンドで正確なコンテナー名を確認して、次のようにコンテナーのシェルに入り、コンテンツを書き換えてみます。

ubuntu@docker3:~$ sudo docker container exec -it nginx-vol_nginx.1.7ytywp67l9pysgn5amtaljste sh
/ # echo "This site: nginx-vol_nginx.1.7ytywp67l9pysgn5amtaljste" > /usr/share/nginx/html/index.html

ubuntu@docker4:~$ sudo docker container exec -it nginx-vol_nginx.2.cqjfqxw9sb4jcv9hur6twc515 sh
/ # echo "This site: nginx-vol_nginx.2.cqjfqxw9sb4jcv9hur6twc515" > /usr/share/nginx/html/index.html

ブラウザーでアクセスしてみます。すると次のように表示されるはずです。ブラウザーのキャッシュが存在するはずなので、確認の際はスーパーリロードを実行してください。

f:id:virtualtech:20200420150436p:plain

以上です。 Swarm modeの使い方についてはいろいろ情報があったのですが、適当なコンテナーアプリケーションをYAMLファイルを使ってデプロイして、ブラウザーでアクセスしてみる流れがまとまっている情報が少なかったので調べてその結果をブログにまとめてみました。誰かのお役に立てば幸いです。

参考にしたページ