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

本番環境にも使える高可用性かつスケーラブルな Docker Swarm + Consul クラスタを構築

More than 3 years have passed since last update.

注意

UPDATED: 2017/02/07
この記事で説明しているクラスタは古い手法です。

  • 本稿の内容で構築したクラスタでは docker service などの Swarm mode で導入されたコマンドが動作しません。
  • Docker 1.12 以降、 Swarm mode に DNS, LB が組み込まれており、外部のディスカバリサービス (Consul などの KVS) に依存しなくなりました。

Swarm mode は標準コマンド docker swarm でセットアップ可能なため、 docker-machine ssh でクラスタを構築できそうです。近日中に記事として公開予定です。

書きました → Swarm mode クラスタを構築して動かしてみる | Qiita

TL;DR

コマンド見れば分かる人向けの完成品はこちら → hidekuro/swarm-cluster-sample

  • High-Availability & Scalable
  • 作業端末からの docker, docker-machine コマンドで、すっきりスマートに構築する。
  • docker.com のホステッド・ディスカバリ・サービスに頼らない。

下図のようなクラスタをローカル VM で作るお話です。

cluster.png

本番でも通じる構成です。

docker-machine が対応するパブリッククラウドであれば、 create 時にオプションを足せばいける…?(未実施)

はじめに

公式にあるチュートリアルやガイド文書は、 スッキリしない印象でした。

  • swarm の準備が「SSH で入って、このコマンドを叩いて…」と泥臭い作業がある。
  • join-token を利用している例は docker.com のホステッドサービスに依存する。
  • manager 自身も agent として(アプリが動くリソースとして)クラスタに参加している。

そこで、なるべく Official な感じを守りつつ、スッキリ立てる方法を模索して実践しました。
完成予想図は冒頭の画像の通りになります。

手順

大まかな流れは次の通り。

  1. ディスカバリサービスとして consul クラスタを構築
  2. プライマリ&レプリカ swarm manager を構築
  3. アプリが動くリソースとなる swarm agent を構築

0. 必要環境

  • docker
  • docker-machine
  • VirtualBox
  • お使いの PC のメモリ 8GB くらい
    • 512MB の VM を12台、合計 6GB ほど使います。
    • キツい場合、記事中の --virtualbox-memory 512 の値を 256 くらいに下げても多分いけます。

ホスト OS は Win, macOS, Linux のどれでもいけると思います。
(ダメだったら教えて下さい)

1. Consul クラスタの作成

Swarm には、クラスタメンバーの情報を保管するためのディスカバリサービスが必要です。

公式チュートリアル中にある swarm join-token を使う方法は docker.com がホスティングしているディスカバリサービスを利用していて、ここがダウンすると、構築した Swarm クラスタも使えなくなります。
(めったにないとは思いますが、有名なサービスは得てして DDoS 攻撃の標的になりますし…)

そこで、 VPC の内側に高可用性 Consul クラスタを構築します。

1.1. マシンの準備

各ゾーンに1台ずつそれぞれ consul0, consul1, consul2 の名前で作成します。

for i in 0 1 2; do
  docker-machine create \
    -d virtualbox \
    --virtualbox-memory 512 \
    --virtualbox-hostonly-cidr 10.20.$i.1/24 \
    --engine-label zone=zone$i \
    --engine-label role=consul \
    consul$i
done

まだ Consul は動いていません。

--virtualbox-hostonly-cidr 10.20.$i.1/24 の指定で、ゾーンに見立てたプライベートネットワークを3つ作り、その中に立てています。

  • 10.20.0.1/24 ... zone0
  • 10.20.1.1/24 ... zone1
  • 10.20.2.1/24 ... zone2

1.2. consul クラスタの開始

それぞれの VM で Consul Server を動かし、3台構成の高可用性クラスタを構築します。

詳細は Qiita | 公式の consul イメージで高可用性 Consul クラスタを試す で説明していますので、ここでは作業内容だけ書きます。

for i in 0 1 2; do
  docker $(docker-machine config consul$i) run \
    -d \
    --name consul$i \
    --restart always \
    -p 8300-8302:8300-8302/tcp \
    -p 8301-8302:8301-8302/udp \
    -p 8400:8400/tcp \
    -p 8500:8500/tcp \
    -p 8600:8600/tcp \
    -p 8600:8600/udp \
    consul agent \
      -server \
      -node consul$i \
      -ui \
      -client 0.0.0.0 \
      -advertise $(docker-machine ip consul$i) \
      -retry-join $(docker-machine ip consul0) \
      -bootstrap-expect 3
done

下記のような URL にアクセスすると同じ画面が見えるはずです。

  • http://$(docker-machine ip consul0):8500/ui
  • http://$(docker-machine ip consul1):8500/ui
  • http://$(docker-machine ip consul2):8500/ui

Consul クラスタメンバーはいずれも同位です。
「リーダーとフォロワー」の関係はあるものの、リーダーが潰れると、代わりに誰かがリーダーとなって動き続けます。

2. Swarm クラスタの作成

Consul が準備できたら、それをディスカバリサービスとして Swarm クラスタを構築します。

Swarm クラスタは manager と agent で構成されます。

種別 役割
manager Swarm クラスタの指揮者。コンテナを実行する agent を選出するスケジューラ機能、コンテナ間連携のためのディスカバリサービス機能など。
agent 実際にコンテナが実行されるワーカー。

多分このイメージ図を見たほうが早い。
https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/

今回は manager を3台と、各 manager に join する agent を2台ずつ、合計9台の Swarm クラスタを形成します。

2.1. manager の作成

各ゾーンに1台ずつそれぞれ manager0, manager1, manager2 の名前で作成します。
各 manager は、同じゾーンにいる consul をディスカバリサービスに指定しています。

for i in 0 1 2; do
  docker-machine create \
    -d virtualbox \
    --virtualbox-memory 512 \
    --virtualbox-hostonly-cidr 10.20.$i.1/24 \
    --engine-opt cluster-store=consul://$(docker-machine ip consul$i):8500 \
    --engine-label zone=zone$i \
    --engine-label role=manager \
    --swarm-master \
    --swarm-discovery consul://$(docker-machine ip consul$i):8500 \
    --swarm-strategy spread \
    --swarm-opt replication \
    manager$i
done

docker-machine の swarm 系オプションにより、作成後まもなく swarm manager として利用できます。
0, 1, 2 の順で作成される都合上、 manager0 が primary 、 manager1, manager2 は replica となるでしょう。

別々の consul をディスカバリサービスにしているのにクラスタになれるのは、 consul 側がクラスタリングによって1つの大きな consul になっているからです。

各オプションの詳細は後述。

2.2. agent の作成

各ゾーンに2台ずつ、合計6台作成し、ゾーンごとの manager に join させます。

for i in 0 1 2; do # $i ... zone number
  for n in 0 1; do # $n ... machine number in zone 
    docker-machine create \
      -d virtualbox \
      --engine-opt cluster-store=consul://$(docker-machine ip consul$i):8500 \
      --engine-label zone=zone$i \
      --engine-label role=agent \
      --virtualbox-memory 512 \
      --virtualbox-hostonly-cidr 10.20.$i.1/24 \
      --swarm \
      --swarm-discovery consul://$(docker-machine ip consul$i):8500 \
      agent$i-$n
  done
done

join 先はゾーンごとにいるそれぞれの manager ですが、 manager 同士がレプリケーション構成になっているので、1つの大きなクラスタになれます。

Swarm クラスタまわりのオプション解説

docker-machine create--swarm** 系オプションは、作成した Docker Engine ホストに Swarm mode 関連の設定を行い、 swarm イメージを実行してくれます。

  • Swarm 専用の特別なマシンというわけではなく、あくまで Docker Engine ホストである
  • swarm イメージのコンテナを実行して Swarm 機能を提供している

この2点はおさえておきましょう。

Docker Engine 関係

--engine-opt cluster-store

Docker のマルチホスト・オーバーレイネットワークのために必要な、ディスカバリサービスの指定です。
consul://$(docker-machine ip consul$i):8500 でゾーンごとの consul を指定しています。

これがないと docker network や docker-compose.yml の networks: が使えません。

--engine-label

Docker Engine ホストに任意のラベルを付けて、あとで docker servicedocker-compose を使う時に、ノードの選定ヒントに利用できるようにしています。

今回の例では付ける必要はありませんが、マシンを立てるときはラベルを付ける習慣をつけておくと、後々役立ちます。

manager, agent 共通

--swarm-discovery

Swarm manager, agent がクラスタメンバーの情報を保管・取得するのに使用するディスカバリサービスの指定です。
ここでも consul://$(docker-machine ip consul$i):8500 でゾーンごとの consul を指定しています。

manager

--swarm-master

マシンを Swarm manager として構成します。

--swarm-strategy spread

Swarm manager のスケジューラが、コンテナを実行する時にどの agent を選ぶかの戦略を指定します。
(省略した場合のデフォルトは spread)

strategy 説明
spread 均等分散。負荷が少ないマシンを選ぶ。マシンのダウン時に失われるコンテナ数が最小。
pinback 詰め込み型。なるべくマシンのリソースを使い切ってから次のマシンを選ぶ。ダウン時に失われるコンテナが多いが、できるだけ少ないマシンに負荷が集中するようになる。
random ランダム。特に計算をせずに無作為にマシンを選ぶ。

参考 : Docker Swarm strategies和訳

--swarm-opt replication

レプリケーションを有効にし、 manager 同士が自動フェイルオーバーするようにします。
これにより、どの manager に対しても同じように docker, docker-compose で指示することができ、障害発生時にもサービスを継続できます。

agent

--swarm

Swarm agent としてクラスタに参加します。

古いチュートリアルでは manager に --swarm --swarm-master のように同時付与していたため、 manager 自身もワーカーとしてクラスタに参加してしまっていました。

というのも、以前は manager にしたいだけのマシンにも --swarm を付与しなければならない仕様だったためです。
この問題は docker/machine Issue#2302 で議論を経て解決され、現在は次の通り分離できるようになっています。

  • manager には --swarm-master をつけて manager 専任として振る舞う。
  • agent には --swarm をつけてワーカーとして振る舞う。

ただし、やろうと思えば旧来と同じく --swarm --swarm-master のようにして manager 自身が agent としても振る舞うようにすることができます。(マシンの数を節約したい…とか)

このクラスタについて

もう1回、図を見てみましょう。

cluster.png

docker-machine ls でみるとこんな感じです。

$ docker-machine ls
NAME       ACTIVE   DRIVER       STATE     URL                      SWARM               DOCKER    ERRORS
consul0    -        virtualbox   Running   tcp://10.20.0.100:2376                       v1.12.5
consul1    -        virtualbox   Running   tcp://10.20.1.100:2376                       v1.12.5
consul2    -        virtualbox   Running   tcp://10.20.2.100:2376                       v1.12.5
manager0   -        virtualbox   Running   tcp://10.20.0.101:2376   manager0 (master)   v1.12.5
manager1   -        virtualbox   Running   tcp://10.20.1.101:2376   manager1 (master)   v1.12.5
manager2   -        virtualbox   Running   tcp://10.20.2.101:2376   manager2 (master)   v1.12.5
agent0-0   -        virtualbox   Running   tcp://10.20.0.102:2376   manager0            v1.12.5
agent0-1   -        virtualbox   Running   tcp://10.20.0.103:2376   manager0            v1.12.5
agent1-0   -        virtualbox   Running   tcp://10.20.1.102:2376   manager1            v1.12.5
agent1-1   -        virtualbox   Running   tcp://10.20.1.103:2376   manager1            v1.12.5
agent2-0   -        virtualbox   Running   tcp://10.20.2.102:2376   manager2            v1.12.5
agent2-1   -        virtualbox   Running   tcp://10.20.2.103:2376   manager2            v1.12.5

これについての要点を見ていきます。

マシンの配置

  • 1ゾーンあたりに1つの consul + Swarm manager と、複数の Swarm agent がいます。
  • クラスタ全体のリソースを足したくなったら、 agent を増やして行けばいいでしょう。(スケーラブル!)
  • 特定のゾーンを切り離したいときは、そのゾーンの agent を外部公開用のロードバランサーから外し、 manager と consul を Stop させればOKです。

サービスの公開

各ゾーンの agent を外部公開用のロードバランサー(別途作る)に参加させればいいでしょう。
多くの場合、 AWS ALB/ELB や GCE LB などパブリッククラウドのマネージドバランサーを使うと思いますので、ここでは追求しません。

ゾーンの死活

  • ゾーン内の Swarm manager, agent のすべては、同一ゾーンにある consul に依存しています。
  • consul が死んだらそのゾーンは死んだも同然ですので、ただちに同一ゾーンの manager も Stop させるべきです。
  • agent はあくまで join した manager に所属するため、例えば manager1 が死んだら agent1-0, agent1-1 もクラスタから外れます。

要は ゾーン内の manager と consul は一蓮托生 にしておきましょう。
(そもそも consul が Swarm クラスタのサービスディスカバリ専用なので、同じマシンでもいいのかも…?)

クラスタとして振る舞えている仕組み

  • 各 manager がレプリケーション構成にあるため、どこの manager から join した agent でも、結果的に同じ Swarm クラスタに所属できています。
  • 各 consul はクラスタ構成にあるため、 manager は自分と同じゾーンにある consul を参照するだけで、別ゾーンにいる agent の情報も参照することができています。

解決できていない課題

Swarm manager, agent にプライベートレジストリを設定していない

この例では、プライベートレジストリを指定していません。
docker service や docker-compose.yml の build: において、 Dockerfile をビルドした独自イメージを使うにはプライベートレジストリが必要です。

なので、理想を言えば
docker-registry.png

こんなプライベートレジストリを立てるか、 AWS ECR や GCP GKE のリポジトリを用意しましょう。

そして Swarm manager & agent を作成する時の docker-machine create オプションに --engine-insecure-registry=$registry_lb_ip:5000 とかやっておくべきでしょう。

consul が死んだ時に手動で manager を落とす必要がある

ここまでで述べてきたとおり、ゾーン内の consul が死んだらそのゾーンが機能しなくなるため、ただちに切り離す必要がありますが、ここが自動化できていません。

Consul が持つ機能をうまく使えば、障害を検知して自動で manager を切り離すことができそうですが…(チラッ

おわりに

このクラスタを十分に活かすには、デプロイするアプリのサービス構成自体も、スケーラブルなクラスタ利用を前提とした構造にする必要があります。

そのへんは AWS ECS とか GCP GKE 関連の優れた記事にお任せしたいと思います。

参考リンク


以上です。

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
ユーザーは見つかりませんでした