Container Apps 正常性プローブ実践：トラブルシューティング実例で学ぶ運用ノウハウ

# はじめに

Azure Container Apps をはじめとするコンテナ環境でのサービス運用は急速に普及しています。
しかし、これらの環境では従来のシステム運用とは異なる課題が浮上します。

特に「正常性プローブ（ヘルスチェック）」は、アプリケーションの稼働状態を継続的に監視し、問題が発生した際に自動的にリカバリを図るための重要な仕組みです。

本記事では、Container Apps における正常性プローブの基本と、実際のトラブルシューティング事例を通じ、現場で役立つノウハウを詳しく解説します。

なお、以下のサポートブログにも内容がまとまっているので、併せてご参照いただけると幸いです。

https://azure.github.io/jpazpaas/2023/11/28/Container-Apps-Troubleshooting-and-configuration-with-Health-Probes.html

# Container Apps 正常性プローブとは

Container Apps 正常性プローブとは、コンテナアプリケーションの状態を定期的に監視する仕組みを指し、アプリケーションが正常に動作しているか、外部リクエストに対応可能か、起動が完了しているかをチェックします。
問題があれば、再起動、トラフィックの遮断等の対応を自動的に行います。

## 各プローブの役割と特徴

各プローブについて目的と特徴、利用シーンの例を簡単にまとめます。

### Startup Probe

- 目的
  - コンテナの起動プロセスが完了したかを確認します。

- 特徴
  - 大量の初期化処理や外部リソースへの接続待ち等、アプリケーションの起動に時間がかかる場合、起動完了前にLivenessやReadinessが誤作動しないようにするために利用します。
  - Startup Probe はコンテナ起動時にのみ実行され、成功するまで他のプローブ（Liveness/Readiness）は無効化されます。

- 利用シーン例
  - 起動にかかる時間が不確定なアプリケーションで使用します。

### Liveness Probe

- 目的
  - コンテナが正常に動作しているか（例：ハング状態になっていないか等）を監視し、問題があれば再起動を試みます。

- 特徴
  - コンテナが起動後、定期的に実行されます。
  - 一定回数（`failureThreshold`）連続でチェックが失敗すると、コンテナを再起動します。

- 利用シーン例
  - アプリケーション内部でリソースの異常状態が発生した場合に、問題のあるコンテナを自動で再起動させ、システム全体の可用性を維持します。

### Readiness Probe

- 目的
  - コンテナが外部からのリクエストを処理できる状態になっているかを判断します。

- 特徴
  - コンテナ起動後、継続的に実行されるため、アプリケーションが一時的にリクエスト処理できない状態になった場合にも対応可能です。

- 利用シーン例
  - アプリケーションが起動直後や、外部サービスとの接続待ち等で一時的にリクエストを捌けない場合、不要なエラーリクエストを回避するために設定します。

各プローブを簡単に一枚絵にまとめると、以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/b14ac1d8-26b3-498e-9027-d6cd26ee4285.png)

なお、Container Apps 正常性プローブは Kubernetes 正常性プローブの上に構築されているため、Kubernetes の公式ドキュメントを読むと、知見が深まります。

https://kubernetes.io/ja/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

# サンプルシナリオ

それでは、実際のトラブルシューティングシナリオの一例を見てみます。

なお、実際のトラブルシューティングを体験したい場合、以下のリポジトリに手順が載っているので、以下を読み進める前にトライしてみてください。

https://github.com/simonjj/aca_enthusiast_workshop


<details><summary>解答例</summary>

Azure Portal で Container Apps の状態を確認すると、実行状態が「低下」していることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/7e7942b9-ee94-42dd-9a17-bbcade1ff98d.png)

トラブルシューティングのために、まずはシステムログを確認してみます。**Container Apps のシステムログは、`ContainerAppSystemLogs_CL` に出力されます。**

```sql:Log Analytics から確認
ContainerAppSystemLogs_CL
| where ContainerAppName_s = 'sickly-app'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/937f774d-283f-46b3-951e-9f796d98aabe.png)

すると、`Probe of Startup failed with timeout in 1 seconds` というログが出力されていることがわかります。これにより、Startup Probe に失敗していることがわかります。

そこで、正常性プローブの設定を確認してみます。

プローブのタイムアウト（秒）が既定の `1` になっていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/40329c71-b5e2-4d18-ba25-851143b20dbf.png)

そこで、`sickly-app` のコンテナイメージに指定されているアプリケーションを探索します。

```shell
docker run --rm -it --entrypoint /bin/sh simon.azurecr.io/sick_app:latest
```

イメージ内のファイルを確認します。

```shell
# ls -l
total 8
-rw-r--r-- 1 root root    6 Feb  8 22:31 requirements.txt
-rwxr-xr-x 1 root root 1071 Feb 11 00:38 sickly_app.py
```

`sickly_app.py` を確認します。

```shell
# cat sickly_app.py
```

すると、以下のように `startup_slow` エンドポイントは、5秒待機して起動する作りになっていることがわかります。起動の遅いアプリケーションを擬似的に表現しているようです。

```python:sickly_app.py
@app.route('/startup_slow')
def startup_slow():
    time.sleep(5)
    return "Startup Slow: OK", 200
```

よって、Startup Probe の `timeoutSeconds` を延ばします。今回は、余裕を持って `10` にします。

```terraform:./infra/main.bicep
resource probeProblemsApp 'Microsoft.App/containerApps@2024-02-02-preview' = {
  name: 'sickly-app'
  location: containerAppsLocation
  // ・・・
            {
              type: 'startup'
              httpGet: {
                path: '/startup_slow'
                port: 8080
                scheme: 'HTTP'
                httpHeaders: [
                  {
                    name: 'Custom-Header'
                    value: 'startup probe'
                  }
                ]
              }
              initialDelaySeconds: 3
              failureThreshold: 30
              periodSeconds: 10
              timeoutSeconds: 10
            }
  // ・・・
```

変更を反映すると、起動に成功していることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/0dff16a5-096a-4599-84ee-2124e8714d22.png)

試しに `/startup_fast` エンドポイントにアクセスしてみると、問題なく 200 番が返ることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/545d809b-436b-4461-bd64-3cd46e24add5.png)

起動の遅いアプリケーションの場合、Startup Probe の `timeoutSeconds` には余裕のある値をセットする必要がある、という内容のトラブルシューティングでした。

</summary>
</details>

# おわりに

本記事では、Container Apps における正常性プローブの基本概念から、Startup Probe、Liveness Probe、Readiness Probe の各プローブの役割と特徴、そして実際のトラブルシューティングシナリオについて解説してきました。

今回のトラブルシューティング事例を通じて、実際の運用現場での課題解決にお役立ちできれば幸いです。