いつの間にか復活している君

解いた人:とり

参照した問題・解説のサイト:いつの間にか復活している君

使用環境・ツール

  • docker
  • docker-compose

前提条件

  • ~/web-server/docker-compose.ymlがあり編集可能
    • わざわざ明記しているあたり、これを編集して問題を解決する必要がありそう
    • ⇨ ひっかけポイントだったらしいw そういうパターンもあるのね。
  • docker ps -aなどで確認するとコンテナが起動している

問題文でされた操作

  • docker-composeを使用してWEBサーバを構築した
  • 無事に起動し、WEBページも確認できたのですが、 再起動するとアクセスできなくなってしまった
    • 自動的に再起動するように記述してあるので不可解
  • トラブルシュートしているといつの間にかアクセスできるようになります

バグの内容

踏み台から $ curl 192.168.17.1 をしても応答がない

理想の終了状態

再起動しても踏み台から $ curl -I 192.168.17.1 をするとステータスコード200のレスポンスが返ってくる

考えられる検証、修正手順

  • docker build -t test:local . と Docker でビルドしてみて永遠と転送しているか確認
    • 大量のファイルを裏で Docker daemon が読み込んでいる
    • .dockerignore で、大量ファイルのあるディレクトリを除外しておき、docker-compose.json 内で別途マウント
    • 起動の時間によりそう

ref:docker-compose で一向にビルドがはじまらない、もしくは起動しない。はたまた忘れたころに起動する。

  • Webサーバーにアクセスできない時の確認ポイント(なさそう)
    • コンテナ内のWebサーバーがちゃんと起動して動いているか
      • 以下のようにして確認
      docker exec -it <起動したコンテナ名> bash
      curl http://localhost:8080/
      
      • エラーが返ってくる、レスポンスが帰ってこない場合はWebサーバーの起動がうまくいっていない
        • 今回の問題は時間が経てば直る問題なのでこれはなさそう
    • localhost以外ではアクセスできるか
      • localhostではなく、実IPアドレスでアクセスしたらどうか?
      • 以下のコマンドでコンテナに割り振られているネットワークアドレスがわかる
      docker inspect –format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}’ con_name
      curl http://172.17.0.2:8080/
      
      • これでうまくいった場合は、ポートなどの問題になる。
    • コンテナで特定のポートが公開されているか
      • ポートの公開を
      # Dockerfileファイル中に以下のような記述を追加し、8080番ポートを公開する
      EXPOSE 8080
      # composeファイル中にならこんな感じ
      expose:
      - '3306'
      - '8080'
      
      • yamlも修正可能なので、なくはないかもしれない。簡単すぎるが。
      • でも、時間が経てば直る問題なのでなさそう
    • 公開されたポートにつながるように設定できているか(ポートフォワード)
      • コンテナで公開されたポートにホストOSから「localhost:8081」のように接続するには、ホストOSの8081番ポートとコンテナの8080番ポートをつないであげる必要があります。
      • localhost:8081 -> コンテナ:8080
        • 「localhost:8081」に来たリクエストを「コンテナ:8080」に転送してあげるようにする
      docker run -p 8081:8080 –name <起動するコンテナ名>
      

Docker Compose restart の挙動

  • ホストOSを起動したタイミングであるアプリケーションを自動で立ち上げたい、 あるいは何らかの問題で落ちた時に、自動で再起動して欲しいというときにrestart使うらしい。
  • Docker 及び Compose では、 run/upの restart policy の設定することにより、 コンテナが停止した際の再起動にまつわる設定ができる。
オプション意味
no再起動しない (デフォルト)
on-failure[:max-retries]プロセスが 0 以外のステータスで終了した場合、 最大:max_retries の分だけ再起動を行う
always明示的に stop がされない限り、終了ステータスに関係なく常に再起動が行われる
unless-stopped最後にdocker daemon が起動していた際に ステータスが終了状態だった場合は再起動しない。それ以外はalwaysと同じ。

ちゃんと再起動の設定はしないといけない。

Q. 従属 コンテナのプロセスはそのまま? それとも再起動される?
A. そのまま

Q. コンテナ間の接続は再開される?
再起動後も接続は問題なさそう

ref: Docker Compose restart の挙動

Dockerデーモン、Dockerコンテナ、及びコンテナ内のサービスアプリの自動起動について

デフォルトは手動なのかな? 再起動の時には自動設定する必要があるっぽい。

Dockerデーモンの自動起動

ブート時に自動起動する

$ sudo systemctl enable docker
# 他のディストリビューションでは、次のように実行します
$ sudo chkconfig docker on

通常時の起動

$ sudo systemctl start docker
# 他のディストリビューションでは、次のように実行します
$ sudo service docker start

設定確認・状態確認は以下のコマンドで行います。

$ systemctl status docker

Dockerコンテナの自動起動

  • restartオプションを利用
    • Dockerが以上終了した場合に自動的に再起動させることが可能
    • さっきの上の表を参考
    • 「always」「unless-stopped」がコンテナの自動起動に利用可能
      • 「always」を指定した場合は、Dockerデーモン終了時のDockerコンテナの状態に関係なく自動起動されます
      • 「unless-stopped」は、Dockerデーモン終了時に停止状態(例えば「docker stop」コマンドにて停止)のコンテナは自動起動されません
  • Dockerホストのsystemdを利用する
    • 「docker start」と「docker stop」をsystemdに登録するだけ
    • systemdって起動するときに動いてくれるやつらしい

Dockerコンテナ内のサービスの自動起動

  • composeファイルに設定がちゃんと書いてあれば特に問題はなさそう

ref:

修正手順案詳細

  • $ curl 192.168.17.1docker ps -aを試してみる
  • 自動起動されてないようなら、systemctl status dockerで自動起動を調べる。
  • yamlのrestartオプションを確認して、もしオプションがうまく機能してなさそうなら設定してみる

解説

原因

デーモンの起動はできているが、dockerの自動起動が出来ていない

原因究明方法

初期状態を確認

$ curl 192.168.17.1
curl: (7) Failed to connect to 192.168.17.1 port 80: Connection refused

コンテナの様子を確認

user@docker:~$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                  PORTS                NAMES
4e7db3e7cc97        nginx:latest        "/docker-entrypoint.…"   3 minutes ago       Up Less than a second   0.0.0.0:80->80/tcp   web-server_nginx_1

もう一度curlを確認する

$ curl 192.168.17.1 -I
HTTP/1.1 200 OK
Server: nginx/1.19.6
Date: Sun, 07 Mar 2021 03:33:11 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 15 Dec 2020 13:59:38 GMT
Connection: keep-alive
ETag: "5fd8c14a-264"
Accept-Ranges: bytes

実はdockerコマンドを叩くとデーモンが起動するという罠があります.先ほどのdocker ps -aを見てみるとUp Less than a secondとあり,起動したてなのがわかります

さらにsystemctl status dockerで詳しく確認してみる。

ictsc@docker:~$ systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; disabled; vendor preset: enabled)
     Active: active (running) since Sun 2021-03-07 12:32:53 JST; 9min ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 2176 (dockerd)
      Tasks: 17
     Memory: 114.7M
     CGroup: /system.slice/docker.service
             ├─2176 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
             └─2362 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.18.0.2 -container-port 80
              
 
ictsc@docker:~$ systemctl is-enabled docker
disabled

↑ でdisabledになっているのが悪かった。

解決手順

解放は単純にenableするだけ。

systemctl enable docker

途中で上手くいっちゃうし、めっちゃ引っかかりそう。restartしてすぐ直るからググってもあんまり出てこなくてこういう問題は意外と厄介かも😅

その他リンク

時間上説明しなかったものたち。

Webが繋がらないという内容で調べたやつ

  • 汎用的に使えそうなやつ: https://web.plus-idea.net/on/docker-web-server-access-denied/
  • 全般的に使えそうなやつ: https://qiita.com/amuyikam/items/ef3f8e8e25c557f68f6a

Dockerデーモンが気になって調べたやつ

  • さわって理解する Docker 入門
    • Dockerデーモンは Linux のデーモンプロセスで、Docker Engine API が呼び出されるのを待ち受けています。Dockerデーモンは、呼び出された Docker Engine API に応じて、イメージのビルドやコンテナの起動などを行います。
  • Linux リテラシ - 第4回 デーモン
    • デーモンはユーザーが意識することがないような裏の部分で動いており、システムを維持したりユーザーにサービスを提供したりといったことを行っています