Help us understand the problem. What is going on with this article?

Docker Swarmで学ぶサービスメッシュ

はじめに

本記事はDocker Swarmでクラスタを構築し、サービスメッシュについて学びます。

環境はAWSのELB(Elastic Load Balancing)と、EC2(Amazon EC2)インスタンス2台を使用し、Docker Swarmのクラスタを構築します。

Qiita_swarm.png

Kubernetesと比較した際にDocker Swarmを導入するメリットは、導入コストが低いことです。Docker SwarmはKubernetesに比べてハードルが低いため、本番環境にコンテナ技術を導入しようとしているシステムには最適だと考えます。

Docker Swarmを通してサービスメッシュの意義を体感しましょう。

Docker Swarm

Docker Swarmは、Docker社が提供するオーケストレーションツールです。
Docker Swarmを使用することで複数のホストを集約し、簡単にコンテナのデプロイとスケールが実現できます。

logo.png

Docker Swarmはマネージャとノードで構成され、Swarmは群れを意味します。
Docker Swarのクラスタを構築するためには、以下の作業が必要です。

  • マネージャとノードにDockerをインストールする。
  • マネージャとノード間で通信ができるように、ファイアウォールで必要な通信を許可する。

  • ファイアウォールで許可するルール

ポート番号 用途
2377/tcp クラスタ管理用の通信
4789/udp オーバーレイ・ネットワーク
7946/tcp ノード間通信
7946/udp ノード間通信

サービスメッシュ

サービスメッシュはマイクロサービスアーキテクチャを前提とし、アプリケーション間で通信を制御する仕組みを提供します。この制御された通信はメッシュの様に編みがけになっているため、信頼性を向上します。

例として2台構成のホストの場合、通常のアクセスパスは以下になります。

ブラウザでロードバランサーのDNS名にアクセスすると、HTTPリクエストを受け付けたロードバランサーは、ラウンドロビンでバックエンドであるホストの公開ポートにHTTPリクエストを振り分けます。

swarm2-1.png

例えば、片方のホストで何らかの障害が発生し、コンテナがダウンした場合でも以下の経路により、サービスを継続することができます。

swarm2-2.png

要約すると、単純にホストレベルでアプリケーションを分ける構成の場合は、片方のホストに何らかの障害が発生したときにサービスの提供ができなくなります。よって、コンテナ技術を活用し、サービスメッシュにすることで単一障害点をなくすことができます。

Docker Swarm構築

Docker Swarmの構築手順について記載します。
Docker Swarmの構築は、マネージャ、ノードの順に作業を行います。

本記事の例ではweb1がマネージャ、web2がノードになり、Nginxのイメージを使用してデプロイします。

前提条件としてDockerは既にインストールされた状態で、上記で解説したファイアウォールも許可されていることとします。また、本記事では最低限の構成としているため、マネージャ1台、ノード1台になります。

マネージャ

まずはじめに、Docker Swarmの初期化を行います。docker swarm initコマンドを実行することでSwarmモードが有効になります。

複数IPアドレスを持つ場合は、他のノードとの通信で使用するインターフェースのIPアドレスをadvertise-addrの引数に指定します。

  • Docker Swarmの初期化
    # docker swarm init --advertise-addr <IPアドレス>
Swarm initialized: current node (zirc78nsch77ox8di6021ux4n) is now a manager.

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

    docker swarm join --token SWMTKN-1-459p0pkyqgxgkhaggjhavd419ldujenqttm1mqmwup0qz9m5qv-1kj3jy6ozwrr2fkj1qvas294a <マネージャのIPアドレス>:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

コマンド実行後、出力結果のdocker swarm join --token SWMTKN-1-(略) <マネージャのIPアドレス>:2377を控えます。

  • node確認
    # docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
zirc78nsch77ox8di6021ux4n *   web1          Ready               Active              Leader              18.09.9-ce

マネージャの場合は、MANAGER STATUSにLeaderと出力されます。

  • ネットワーク確認
    # docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
53703efd3d07        bridge              bridge              local
aacf6f5e0eb4        docker_gwbridge     bridge              local
1f0d0e4ae3e7        host                host                local
xip5tlqmokpb        ingress             overlay             swarm
2d36f1c8c80f        none                null                local

Swarmの初期化を行うと新たに2つのネットワーク(docker_gwbridge、ingress)が作成されます。

ノード

次にノードをDocker Swarmのクラスタに参加させるため、ノード側で以下のコマンドを実行します。

--tokenの引数にしている値は例になります。上記docker swarm initコマンドの出力結果をコピーしてペーストすれば大丈夫です。

なお、マネージャ側でdocker swarm join-token workerコマンドを実行することで、トークンの再表示もできます。

  • クラスタ参加
    # docker swarm join --token SWMTKN-1-(略) <マネージャのIPアドレス>:2377
This node joined a swarm as a worker.

マネージャ側で確認のため、再度、docker node lsコマンドを実行すると、nodeが認識されていることが確認できます。

  • node確認
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
zirc78nsch77ox8di6021ux4n *   web1          Ready               Active              Leader              18.09.9-ce
n2o22ptdmyhan8qg0ijmo0qn5     web2          Ready               Active                                  18.09.9-ce

Docker Swarmのデプロイ

本記事では管理しやすいdocker-commposeでデプロイします。
また、docker service createコマンドでもデプロイできます。serviceやstackの説明については割愛します。

デプロイ作業はマネージャ側で行います。
任意のディレクトリに移動し、以下のdocker-commpose.ymlファイルを作成します。

  • docker-commpose.yml
version: "3"
services:
  web:
    image: nginx
    deploy:
      replicas: 2
      #resources:
      #  limits:
      #    cpus: "0.1"
      #    memory: 100M
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"
    networks:
      - webnet
networks:
  webnet:

docker-commpose.ymlファイル作成後、以下のコマンドを実行し、デプロイします。
testは例となるため、任意の名前を指定します。

# docker stack deploy -c docker-commpose.yml test

Updating service test_web (id: egubeieuri00rzmm9imsna93o)

デプロイ後、以下のコマンドでサービスの状態が確認できます。
REPLICASは2となっているので、2つのコンテナが起動しています。

# docker service ls

ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
r04mfg1se3nh        test_web            replicated          2/2                 nginx:latest        *:80->80/tcp

マネージャとノード側でdocker container ps -aコマンドを実行すると、コンテナが起動しているのが確認できます。

  • マネージャ側
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
4a26c3ca6df7        nginx:latest        "nginx -g 'daemon of…"   3 seconds ago       Up 2 seconds        80/tcp              test_web.1.mnnz40tdykzd2intwz5hf68bs
  • ノード側
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
614c19349bf0        nginx:latest        "nginx -g 'daemon of…"   2 minutes ago       Up 2 minutes        80/tcp              test_web.2.6om5oazbavassohd4akucbum2

Docker Swarmの動作確認

Docker Swarmの動作確認を行います。

ブラウザからロードバランサーのDNS名にアクセスを行い、正常に負荷分散されることを確認します。

  • ロードバランサーのDNS名にアクセス

スクリーンショット 2020-02-05 23.37.20.png

コンテナのログを確認すると、ラウンドロビンで負荷分散されているのが確認できます。
CONTAINER IDdocker container ps -aのコマンドで確認します。

# docker logs -f <CONTAINER ID>

10.255.0.3 - - [06/Feb/2020:14:20:51 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" "<アクセス元のグローバルIP>"

試しにweb2上(ノード側)で稼働しているコンテナを停止します。

# docker stop <CONTAINER ID>

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
423f673b0513        nginx:latest        "nginx -g 'daemon of…"   19 hours ago        Exited (0) 5 seconds ago                       test_web.2.kc7yypyasgvjtolsb1zwmhjoy

このときweb2上でコンテナは稼働していません。
ロードバランサーのDNS名にアクセスできることを確認します。

alb-acces.png

例としてブラウザから停止したweb2の公開IPにアクセスします。

web2-acces.png

Web1(マネージャ)上のコンテナのアクセスログに、停止したweb2(ノード)の公開IPに対するアクセスが確認できます。

10.255.0.3 - - [07/Feb/2020:02:19:01 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" "-"

停止したweb2(ノード側)のローカルからも、以下のコマンドを実行することでコンテナにアクセスができます。

# curl localhost 80

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
curl: (7) Couldn't connect to server

web1(マネージャ)のログでは以下の様に出力されます。

10.255.0.2 - - [07/Feb/2020:02:41:47 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.61.1" "-"

web1(マネージャ)で4789ポートをダンプして見ていると、オーバーレイ・ネットワークの通信を見ることができます。

# tcpdump -nli eth0 port 4789 -Av

Docker Swarmのスケール

既にサービスが起動している状態で、以下のコマンドを実行することでスケールができます。以下のコマンドはコンテナの数を4コンテナに変更しています。

# docker service scale test_web=4

test_web scaled to 4
overall progress: 4 out of 4 tasks 
1/4: running   [==================================================>] 
2/4: running   [==================================================>] 
3/4: running   [==================================================>] 
4/4: running   [==================================================>] 
verify: Service converged 

スケール後、docker container ps -aコマンドを実行すると、コンテナが増えていのが分かります。

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
41962946aa48        nginx:latest        "nginx -g 'daemon of…"   3 minutes ago       Up 3 minutes        80/tcp              test_web.4.pytl36ejcd81ybthisxfo47br
423f673b0513        nginx:latest        "nginx -g 'daemon of…"   7 hours ago         Up 7 hours          80/tcp              test_web.2.kc7yypyasgvjtolsb1zwmhjoy

デプロイ時はサーバ1台ずつに対してアプリケーション資産の入れ替えを行う必要がなく、マネージャ1台で済みます。

Docker Swarmの性質

Docker Swarmは冪等性を持っています。

具体的には、Docker Swarmは指定したreplicas数のコンテナを維持するため、クラスタ化している片方のホストがダウンした場合は、片方のホストでコンテナを起動します。

以下はdocker container ps -aコマンドの出力になります。
例としてweb1とweb2でそれぞれコンテナが起動しています。

  • web1
e5ccbfa9739b        nginx:latest                      "nginx -g 'daemon of…"   3 minutes ago       Up 3 minutes        80/tcp              test_web.1.mrgkhbd7juer72v6bv0l42fxq
  • web2
4820c7bbe9c1        nginx:latest                      "nginx -g 'daemon of…"   3 minutes ago       Up 3 minutes        80/tcp              test_web.2.wfe1n11s8940rdl8r1c47o6nc

web2のホストを停止しました。web2のダウンを検知すると、web1上でコンテナを作成します。

0a88f53039a3        nginx:latest                      "nginx -g 'daemon of…"   5 seconds ago       Created                                 test_web.2.p06zas3c3kt9ekjojhhfnl3co
e5ccbfa9739b        nginx:latest                      "nginx -g 'daemon of…"   4 minutes ago       Up 4 minutes        80/tcp              test_web.1.mrgkhbd7juer72v6bv0l42fxq

web1上でコンテナが2台起動しています。

0a88f53039a3        nginx:latest                      "nginx -g 'daemon of…"   37 seconds ago      Up 31 seconds       80/tcp              test_web.2.p06zas3c3kt9ekjojhhfnl3co
e5ccbfa9739b        nginx:latest                      "nginx -g 'daemon of…"   5 minutes ago       Up 5 minutes        80/tcp              test_web.1.mrgkhbd7juer72v6bv0l42fxq

Docker Swarm解除

Docker Swarmの解除方法について記載します。

先にマネージャ側で以下のコマンドを実行し、サービスの削除を行いす。

# docker service rm test_web

test_web

次にノード、マネージャの順に作業を行います。

ノード

  • ノードの切り離し
    # docker swarm leave
Node left the swarm.

マネージャ

ノードのSTATUSがDOWNになったことを確認します。

  • node確認
    # docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
zirc78nsch77ox8di6021ux4n *   web1          Ready               Active              Leader              18.09.9-ce
n2o22ptdmyhan8qg0ijmo0qn5     web2          Down                Active                                  18.09.9-ce

ノードを削除します。オプションの引数には、ノード名を指定します。

  • node削除
    # docker node rm --force web2
web2

マネージャからノードが認識されなくなったことを確認します。

  • node確認
    # docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
zirc78nsch77ox8di6021ux4n *   web1          Ready               Active              Leader              18.09.9-ce

最後にマネージャ自身を切り離します。

  • マネージャの切り離し
    # docker swarm leave --force
Node left the swarm.

Docker Swarm解体

Docker Swarmを使用しない場合は、マネージャ側で以下の作業を行います。

ノードが存在しないことを確認します。

  • node確認
    # docker node ls
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.

Docker Swarmで作成されたネットワークが削除されたことを確認します。docker_gwbridgeのネットワークは残っています。

# docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
987cfc73d87c        bridge              bridge              local
aacf6f5e0eb4        docker_gwbridge     bridge              local
1f0d0e4ae3e7        host                host                local
2d36f1c8c80f        none                null                local

以下のコマンドを実行し、使用していない全てのリソース削除します。

  • リソース削除
    # docker system prune
WARNING! This will remove:
        - all stopped containers
        - all networks not used by at least one container
        - all dangling images
        - all dangling build cache
Are you sure you want to continue? [y/N] y
Deleted Networks:
docker_gwbridge

Deleted Images:
untagged: nginx@sha256:ad5552c786f128e389a0263104ae39f3d3c7895579d45ae716f528185b36bc6f
deleted: sha256:2073e0bcb60ee98548d313ead5eacbfe16d9054f8800a32bedd859922a99a6e1
deleted: sha256:a3136fbf38691346715cac8360bcdfca0fff812cede416469653670f04e2cab0
deleted: sha256:99360ffcb2da18fd9ede194efaf5d4b90e7aee99f45737e918113e6833dcf278
deleted: sha256:488dfecc21b1bc607e09368d2791cb784cf8c4ec5c05d2952b045b3e0f8cc01e
untagged: nginx@sha256:70821e443be75ea38bdf52a974fd2271babd5875b2b1964f05025981c75a6717
deleted: sha256:5ad3bd0e67a9c542210a21a3c72f56ef6387cf9b7f4c2506d2398d55a2593ed0
deleted: sha256:b69e2ed46519bc33e7c887967e4f61a2ee53aef165b70f75e208937fb42e7b4c
deleted: sha256:4cb7f732537bf0f65cd9f8f7b63bbe71abcf9d0df396f58621ef3be0b2487b27
deleted: sha256:556c5fb0d91b726083a8ce42e2faaed99f11bc68d3f70e2c7bbce87e7e0b3e10

Total reclaimed space: 253.4MB

ナレッジ

docker-commposeのバージョン

Docker Swarmを使用する場合に、docker-commposeで使用できるバージョンは3になります。

docker-commposeでビルドする場合の留意事項

docker-commposeでビルド(stack)する場合、イメージが必要になります。

Compose file version 3 referenceより

注:( バージョン3)Composeファイルを使用してSwarmモードでスタックをデプロイする場合、このオプションは無視され ます。このdocker stackコマンドは、ビルド済みのイメージのみを受け入れます。

そのため、Docker registryの環境が必要になります。

ローカルでDockerレジストリをセットアップする方法については、公式の以下URLが参考になります。

例として、以下の様にビルドを指定してデプロイを実行した場合、

version: '3'

services:
  app:
    build: ./src

以下のエラーメッセージが出力されて、デプロイをすることはできません。

failed to create service stackdemo_backend: Error response from daemon: rpc error: code = InvalidArgument desc = ContainerSpec: image reference must be provided

デプロイ時のエラー

例として2台構成のホストで、docker-commpose.ymlファイルのreplicasの値を2にしてデプロイした場合は、基本的に1ホストに対して1コンテナで分散されます。

もし、デプロイ時に片方のホストで2台のコンテナが起動した場合は、何らかのエラーが発生し、片方のホストでコンテナが起動できなかったことが考えられます。エラーはLinuxの場合、シスログから確認することができます。

おわりに

不確実性があり変化の速さが求めれられる現代のアプリケーション開発には、オーケストレーションツールは必須な技術です。

応用としてサーバレスの技術を使用し、CPUやメモリリソース等のしきい値等を設定して、しきい値を超えたらサーバをスケールアウトなどの運用も行うことができます。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした