Docker の HEALTHCHECK の動作確認（HEALTH を CHECK する）

<h2>How to run Docker's HEALTHCHECK</h2>

> Dockerfile をいじらずに `HEALTHCHECK` のテストが動くか確認したい。つまりヘルスチェック自体の動作確認をしたいのです。

- [「Docker とは」の検索結果](https://www.google.com/search?q=site:qiita.com+docker%E3%81%A8%E3%81%AF&tbs=qdr:y) @ Google

## TL;DR

> `health-interval` と `health-start-period` を１秒（`1s`）に指定して `docker run` し、`docker ps` で `Status` を `grep` します。
>
> ```bash
> docker run -d --rm \
>   --health-start-period=1s \
>   --health-interval=1s \
>   my_image:my_tag my_command && \
> sleep 5 && \
> docker ps \
>   --filter ancestor=my_image:my_tag \
>   --format '{{json .Status}}' | grep healthy
> ```

Docker の `HEALTHCHECK` 動作は、コンテナを起動しないと確認できません。起動していれば `docker ps` の `STATUS` 項目で確認できます。

そのため「作成した Dockerfile のヘルスチェックが動いているか」の確認をしたい場合は、`docker run` のオプションで `HEALTHCHECK` の「開始」と「インターバル」を設定しながら実行した後、`docker ps` で確認します。

```shell-session:Override_Option_And_Run_Then_Check_PS
$ docker run -d --rm --health-start-period=1s --health-interval=1s my_image:my_tag my_command

$ docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                            PORTS                    NAMES
3fdd3da5660c        my_image:my_tag         "my_command"         2 minutes ago       Up 2 minutes (health: healthy)   0.0.0.0:4040->4040/tcp   randomname
```

- `--health-start-period=1s` （開始、1秒以上）
- `--health-interval=1s` （インターバル、1秒以上）

[「`docker` `how` `to` `run` `healthcheck`」とググって](https://www.google.com/search?q=docker+how+to+run+healthcheck)も **`HEALTHCHECK` の設定の仕方ばかり**で、動作確認の方法がタイトルからわかるものがありませんでした。わかれば、どうってことないのですが自分のググラビリティとして。もっと簡単に確認できる方法があればコメントで教えてくださーい。

## TS;DR（Are You Healthy?）

### Dockle でチェックしたら不健康と言われた

[PHP8（JIT 付き）のコンテナを作成した](https://qiita.com/KEINOS/items/ca0f130c48e407fc5790)ので、イメージがセキュアか最低限のチェックとして **Docker のセキュリティ診断ツール「[Dockle](https://qiita.com/tomoyamachi/items/bb6ac5788bb734c91282)」で作成した Docker イメージを診断させた**のです。

すると、「`HEALTHCHECK` ないよ」と `WARN` されました。ヽ( `Д´)ﾉ ｳﾜｧｧｧﾝ!!

```shell-session:dockleコマンドの診断結果
$ # CIS-DI-0005 は .dockleignore で意図的にスキップ
$ dockle php8:localbuild
PASS	- CIS-DI-0001: Create a user for the container
IGNORE	- CIS-DI-0005: Enable Content trust for Docker
WARN	- CIS-DI-0006: Add HEALTHCHECK instruction to the container image
	* not found HEALTHCHECK statement
PASS	- CIS-DI-0007: Do not use update instructions alone in the Dockerfile
PASS	- CIS-DI-0008: Remove setuid and setgid permissions in the images
PASS	- CIS-DI-0009: Use COPY instead of ADD in Dockerfile
PASS	- CIS-DI-0010: Do not store secrets in ENVIRONMENT variables
PASS	- CIS-DI-0010: Do not store secret files
PASS	- DKL-DI-0001: Avoid sudo command
PASS	- DKL-DI-0002: Avoid sensitive directory mounting
PASS	- DKL-DI-0003: Avoid apt-get/apk/dist-upgrade
PASS	- DKL-DI-0004: Use apk add with --no-cache
PASS	- DKL-DI-0005: Clear apt-get caches
PASS	- DKL-DI-0006: Avoid latest tag
PASS	- DKL-LI-0001: Avoid empty password
PASS	- DKL-LI-0002: Be unique UID
PASS	- DKL-LI-0002: Be unique GROUP
```

健康診断は大事です。泣いてもしかたないので、Dockerfile に `HEALTHCHECK` を以下のように指定しました。

```dockerfile:Dockerfile
...（略）...

HEALTHCHECK \
  --start-period=10m \
  --interval=60m \
  --timeout=10s \
  --retries=1 \
  CMD [ "php -r 'echo phpversion();'" ]

...（略）...
```

開始時間とインターバル（`start-period` と `interval`）が長いのは、マシンがショボいためしばらく経過して、安定してからヘルスチェックさせたかったからです。

`dockle` のテストはパスしたのでコンテナを作成して作業をしていたところ、「もういいでしょう」とおもむろに `docker ps` を実行したところ `STATUS` が `Up XX minutes (unhealthy)` となっていました。不健康ですって。

ビックリしたのもつかの間、そもそも `HEALTHCHECK` で指定したテストの仕方が間違ってたのでした。。。（実行エラーを起こしていました）

最初は `--start-period=0s` と Dockerfile で指定したのですが `docker ps` のステータスが `Up 10 minutes (health: starting)` と一向に始まる気配がありません。

「なんか・・・確認のたび Dockerfile をいじるの面倒だな・・・普通に確認コマンドないのかな」

考える前に手が出る、検索猿人の悪い癖がでました。

結局のところ、イメージの状態で `HEALTHCHECK` の動作テストは行えず、一旦コンテナを立ち上げないといけないことがわかりました。

`docker inspect` でも確認できるのですが `docker ps` で確認する方が簡単でした。

最終的に動作する Dockerfile の `HEALTHCHECK` は以下の通りになりました。

```dockerfile:Dockerfile
...（略）...

HEALTHCHECK \
  --start-period=10m \
  --interval=60m \
  --timeout=10s \
  --retries=1 \
  CMD [ 'php -r "echo phpversion();"' ]

...（略）...
```
```diff:差分
- CMD [ "php -r 'echo phpversion();'" ]
+ CMD [ 'php -r "echo phpversion();"' ]
```

## 参考文献

- [HEALTHCHECK](https://docs.docker.com/engine/reference/builder/#healthcheck) @ Docker 公式