Edited at

docker swarm restarting node on AWS

More than 1 year has passed since last update.


目的


  • awsなどで特に、メンテナンスのために勝手にdocker swarmのノードが再起動されることがあるのでその時の挙動について確認したい。


環境


  • AWSでt1.smallを2つ使い、1master/1workerで動かす

  • 全体をシャットダウンはせず、どちらかのノードが再起動した場合の挙動を確認する


結果


masterの再起動(docker-machine stop/start)


  • 1masterなので当然だが、クラスタ全体が動作しなくなる

  • stop/startで再起動したため、ip addressが変更され、docker-machine regenerate-certsすることになった。

  • regenerate-certs後は特に問題なくクラスタが利用できるようになった。またシャットダウン時に定義されていたサービスも全て元に戻った


masterの再起動(docker-machine restart)


  • 再起動自体はすぐに終了するが、masterがdockerコマンドに反応しなくなった。

mgo-stage-m     *        amazonec2    Running   tcp://ADDR:2376           Unknown   Unable to query docker version: Get https://ADDR:2376/v1.15/version: dial tcp ADDR:2376: getsockopt: operation timed out


  • やがてtimeout状態になったが10秒ほどで復旧し、サービスも元の状態に戻った


    • raftに参加しているノードがなくなったので、state machineをsnapshot+logから復旧したりするからだろうか。




2 masterの再起動(docker-machine restart)


  • raftのせいで復旧が遅い疑惑があったので、複数マスターのある状態で再起動を試す

  • 結果として、workerをpromoteした場合でもやはりしばらくtimeout状態が続く上に、2つのノードがrunningになった後でもサービスは復旧しなかった。(rpc timeout)

  • こういうログが延々とで続けているため、おそらくleaderになるためのquorumが取れていない。2ノードなのがよくないのだろう。

Feb  6 04:21:03 mgo-stage-m dockerd[777]: time="2017-02-06T04:21:03.967920435Z" level=info msg="62ebaabf99cd5c24 [logterm: 5, index: 9327] sent vote request to 7df4e98a03f59f91 at term 151"

Feb 6 04:21:06 mgo-stage-m dockerd[777]: time="2017-02-06T04:21:06.244817897Z" level=error msg="agent: session failed" error="session initiation timed out" module="node/agent"


3 masterの再起動(docker-machine restart)


  • 2 masterで復旧しなくなったので、3 master (0 worker)での挙動も確認した。

  • 3 masterの場合、leaderが死んでも迅速にleaderは別のノードに受け継がれ、1分弱で再起動したノードもdocker node ls上でactiveになり接続もできるようになった。


workerの再起動


  • 時々dockerの起動確認で以下のようなエラーがしばらく出続けた以外は問題なくサービス全体が復旧した

    Error running SSH command: ssh command error:

command : netstat -tln
err : exit status 255
output :


まとめ


  • 2マスターのdocker swarmは再起動によって復旧不能な状態になることがある。quorumの教科書で習うように、マスターは奇数にする。

  • modeがglobalなサービスの場合、アクセスがあったnodeに立ち上がっているサービスに接続されると考えていたが、globalであっても内部的なロードバランスによって接続しに行ったのと別ノードのサービスに接続されることがある模様。


    • EDIT: docker service createにおいて、-p PORT:EXPORT ではなく、--publish mode=host,published=PORT,target=EXPORT を使うことでhostモードでコンテナを立ち上げれば各ノードに来たコネクションはそのノードのglobalサービスが受けるようにできる。同時にclientのraw ipがわかるのでありがたい。