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は警告を出さない(たぶん)ので気づきにくかったです。