[Docker] docker コンテナが終了できなくなったとき (無保証)


はじめに

ごくまれに、docker コンテナが終了できなくなり、何も操作できない状況に陥ることがあります。

  • docker-compose down → UnixHTTPConnectionPool(host='localhost', port=None): Read timed out. (read timeout=60) でエラーになる
  • docker stop xxxx → ダンマリ。
  • docker kill xxxx → ダンマリ。。
  • docker rm -f xxxx → ダンマリ。。。

こんな状態。。

あとは dockerd を再起動して解決とありますが、そう簡単に dockerd 再起動できない状況もあります。

ちなみに、コンテナに restart ポリシーを設定していると、dockerd 再起動や OS 再起動をしても停止できないままのコンテナが復帰してしまいます。

そもそも、docker inspect xxxx などをやってもダンマリなので、restart ポリシーを変更することもできません。

  • docker update --restart=no xxxx → ダンマリ。。。。

確認できた現象

今回は以下のような状態で、同現象が発生しました。

  • アプリケーション + fluentd などサイドカー付きの docker-compose 構成
  • fluentd など、サイドカーの一部が落ちた状態

サイドカーの一部が落ちていたのは、restart ポリシーの設定不備で dockerd 再起動時に片側だけ復帰していたため。

この状態で、まず docker-compose down が効かなくなります。

次に、 docker stop、docker kill 等を試みるわけですが、そうするとコンテナ内部で実行するコマンド(nginx や node など) が終了して、コンテナ情報の外枠だけ残るというおかしな状態になってしまいました。

$ docker stop xxxxxxxxxxxx

    ダンマリになるので Ctrl-C で終了

$ ps ax | grep nginx
=> コンテナ内で実行していたコマンドは終わっている

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  ...
    :
xxxxxxxxxxxx        my_nginx:latest     "sh /entrypoint.sh '…"  ...
=> コンテナ情報だけ残る

コンテナが残っているのに、何もコマンドを受け付けない状態になってしまいます。。

また、今回は restart ポリシーを設定していたため、dockerd を再起動してもコンテナが復帰してしまいます。

対処法1

docker ps -a で見て、終了してしまったサイドカーの相方が残っていた場合、これを docker start することで docker-compose down が効くようになりました。
ただ、これは必ず成功するわけではないようです。

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  ...
    :
xxxxxxxxxxxx        my_nginx:latest     "sh /entrypoint.sh '…"  ...   Up ddd hours
yyyyyyyyyyyy        fluentd:latest      "tini -- /bin/entryp…"  ...   Exited (0) ddd hours ago ★終了した相方

$ docker start yyyyyyyyyyyy

$ docker-compose down

対処法2 ※無保証

今回は restart ポリシーの設定不備と合わさって、dockerd 再起動でも復旧できなかったので、restart ポリシーを修正する方法を取ります。

docker update --restart=no xxxx は操作が効かないので、コンテナの実ファイルを見てみます。

コンテナの実体は以下のディレクトリにありました。(root でないと見れません)

# ls 
 -1 /var/lib/docker/containers/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-json.log
checkpoints
config.v2.json
hostconfig.json
hostname
hosts
mounts
resolv.conf
resolv.conf.hash

この中の hostconfig.json に restart ポリシーの設定があるようです。

# cat /var/lib/docker/containers/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/hostconfig.json | jq .
{
  "Binds": [],
  "ContainerIDFile": "",
  "LogConfig": {
    "Type": "json-file",
    "Config": {
      "max-file": "10",
      "max-size": "10m"
    }
  },
  "NetworkMode": "storage_default",
  "PortBindings": {},
  "RestartPolicy": {  ★コレ
    "Name": "always",
    "MaximumRetryCount": 0
  },
  :
}

これを強引に書き換えてみます。※無保証

"RestartPolicy":{"Name":"always","MaximumRetryCount":0}
    ↓
"RestartPolicy":{}

restart ポリシーの設定をクリアしたら、dockerd を再起動するとおかしくなっていたコンテナは削除できました。

$ sudo systemctl restart docker

おわりに

強引な方法で、とりあえず復旧することができました。

restart ポリシーの設定不備はともかく、コンテナ操作ができなくなってしまうのは怖いです。

コンテナ内部のコマンドが終了していても、外枠のコンテナ情報が残ってしまう辺りが謎なので、どういう仕組みなのか調べてみたいですね。

// EOF