Dockerを使ってSwarmを立ち上げてみた

ダウンロード

Dockerを使ってSwarmを立ち上げてみた話

Swarmを作成する

Swarmを立ち上げるまでの話を簡単にまとめてみました。

使用したDocker version

1.13.0

Swarm内のロードバランサー

Swarm内には Ingress network というロードバランサーがあります。

Ingress networkはnodeが増えたり、減ったりした場合でも、nodeの変化に応じてロードバランシングすることができます。

例えばSwarm内にnodeA(10.5.0.2), nodeB(10.5.0.3)があるとして、10.5.0.2のport 80にアクセスが来た場合、10.5.0.3にロードバランシングすることができます。これらのIPはホストのIPと同じでportはpublishされているので外部からアクセスすることができます。

また、Ingress networkは、Swarmを構築した時点で自動で作成されます。

ちなみに、manager nodeは、(N-1)/2のmanagerの障害に耐えることができます。ドキュメントによると7台のmanager nodesを用意することが推奨されているようです。
https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/

Swarmを作成する

Swarmを作成するにはmanager nodeで以下のようにします

docker swarm init --advertise-addr

worker nodeでは以下のようにします

dockeer swarm join --token

これだけで簡単にSwarmを作成することができます。

サービスを起動する

サービスを起動するには以下のようにします。

docker service create --replicas 2 -p 80:80 --name myapp --network my-network myapp:latest

これでmyappサービスをレプリカ2でport 80をpublishして起動させることができます。

以上でSwarmの作成とサービスの立ち上げが完了しました。とても簡単です。

service discoveryを使用する

Swarmの作成は簡単にできましたが、サービス間通信をしたい場合に必要になるservice discoveryについて紹介します。

よくサービス間でサービス名を解決したい場合があります。

WebアプリケーションでHTTPSを使いため、WebアプリケーションのサービスとNginxのサービスを立ち上げて、Nginxをリバースプロキシとして使いたい場合を考えてみます。

Webアプリケーションのサービス名は myapp、 Nginxのサービス名は proxy とします。
Webアプリケーションはport 9000で動作していて、Nginxは外部のHTTPSのport 443を受け取ってport 9000にリバースプロキシします。

myapp(9000) ```

この時Nginxをリバースプロキシとして使いたいので、以下のような設定をします。
```language-scala
upstream my-backend {
server myapp:9000;
}

myappという名前のホストとVIPが自動的に登録され、リクエストは正しく上流のWebアプリケーションに転送されます。

このように、Swarm内ではservice discoveryが動いているので、サービス間で通信したい場合に便利です。

このservice discoveryを使用するには、新規にoverray networkを作成する必要があります。
Attach services to an overlay network

docker network create --driver overlay --subnet 10.0.9.0/24 --opt encrypted my-network

のようにoverlay networkを作成します。詳しいオプションはドキュメントを参照してください。

ハマりポイント

サービスを起動する順番

上記で述べたNginxの設定のようにサービス名に依存しているサービスを立ち上げる場合、立ち上げる順番に気をつける必要があります。

上記の例だと、myapp を立ち上げる前に proxy を立ち上げてしまうと、myapp がまだservice discoveryに登録されていないので、 proxy サービス起動時に名前解決されずにエラーで起動できません。先に myapp サービスを立ち上げてから proxy サービスを立ち上げる必要があります。

このようにサービス名に依存したサービスがある場合は、サービスを立ち上げる順番に気をつける必要があります。

port

service discoveryを使用するには、Port 7946 TCP/UDP とPort 4789 UDP がnode間で疎通できている必要があります。

たまに、node間でポートが開いているのにservice discoveryが正しく動かないことがあります。この場合はnetstat -antupなどでポートがlistenしているか確認します。7946, 4789 UDP が見つからなければdocker daemonをリスタートすると大抵直るかと思います。この原因についてはなくわかっていないので、誰か教えてくれると嬉しいです。
このportがlistenされていなくてもSwarmは警告を出さない(たぶん)ので気づきにくかったです。