App Service for Linux における Sidecar パターンの Tips

# はじめに

この記事では、App Service for Linux において、サイドカーを導入して、下記の観点を確認します。

- ログはどう出力されるのか
- Web SSH できるのか
- 再起動はコンテナ単位で行われるのか
- 環境変数(アプリケーション設定)は反映されるのか
- ボリュームはマウントされるのか
- VNet 統合はサイドカーコンテナにも適用されるのか
- Managed ID は利用できるのか
- Dapr は利用できるのか

なお、あくまでも現時点で実際に動作させてみて分かったことベースでの記載となります。
将来的に動作が変わる可能性があることはご承知おきください。

=== 03/12 追記 ===

本家ブログ記事が出てます

https://azure.github.io/AppService/2025/03/06/Sidecars-Deep-Dive-Part1.html

===

# TL;DR

| No | 確認項目 | 結果 | 備考 |
|:-:|:-|:-|:-|
| 1 |サイドカーのログはどう出力されるのか | ▲ | 各コンテナからの出力がまざる。正直標準のApp Service ログをつかうのは厳しそう:innocent: |
| 2 |サイドカーに対して SSH 接続できるのか | 〇 | main コンテナを踏み台にして各サイドカーに SSH 接続可能。仕組みからできそうなことは推測はできるがDocは欲しいですね。 | 
| 3 |サイドカーに対して正常性チェック できるのか | ×　| main コンテナに対する http pingのみ。各コンテナに対する正常性プローブのような機能はない :innocent:|
| 4 |コンテナ単位で再起動できるか | × | 全てのコンテナのライフサイクルは同じ　|
| 5 |サイドカーに環境変数(アプリケーション設定)は反映されるのか  | 〇 | デフォルトでは設定されないが継承可能。これは Doc がないと困る:rage:　|
| 6 |ボリュームはマウントされるのか | 〇 | 通常の App Service と同様に利用可能:grinning:|
| 7 |VNet 統合はサイドカーコンテナにも適用されるのか   | 〇 | 通常の App Service と同様に利用可能:grinning:|
| 8 |Managed ID は利用できるのか | 〇 | 通常の App Service と同様に利用可能:grinning:|
| 9 |Dapr は利用できるのか | ▲ | 利用できるが、いろいろ工夫が必要 & Dapr 本来のパワー全てを発揮できなそう |


# 祝 🎉 Sidecars for Azure App Service for Linux GA 🍺

https://azure.github.io/AppService/2024/11/08/Global-Availability-Sidecars.html

## Samples

すぐに動かせるサンプルはすでにいくつか公開されています。

https://github.com/Azure-Samples/sidecar-samples/tree/main

- [A Step-by-Step Guide to Datadog Integration with Linux App Service via Sidecars](https://azure.github.io/AppService/2024/07/26/Using-Datadog-with-Sidecar.html)

- [Azure App Service Community Standup: Integrating Datadog with Linux App Service using Sidecars](https://azure.github.io/AppService/2024/08/08/App-Service-Community-Standup.html)

- [Leveraging Redis as a Sidecar for Linux App Service](https://azure.github.io/AppService/2024/07/19/Using-Redis-with-Sidecar.html)

- [Implementing Local RAG using Phi-3 ONNX Runtime and Sidecar Pattern on Linux App Service](https://azure.github.io/AppService/2024/09/03/Phi3-vector.html)

公式ドキュメントとしても以下のチュートリアルページがあります。

https://learn.microsoft.com/ja-jp/azure/app-service/tutorial-custom-container-sidecar

動かしてみるだけなら、上記の記事をトレースするだけなので、先に挙げた疑問点を掘り下げていきます。

それ Container Apps でやれるのでは ? という疑問がちらつきますが、せっかくなのでいろいろ試してみます。

# お題

Container Apps に寄せてみたいなと思ったので、Envoy と Dapr を使ってみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/b1febc38-9ecb-1293-0c40-f381659f2aef.png)

リバースプロキシとしてEnvoyコンテナを用意します。
App Serviceのリクエストを受け付けるコンテナとなるため、これを main コンテナとします。
アプリケーションバックエンドとしてNodeアプリを backend コンテナとします。
backend コンテナ用の dapr コンテナを用意して、ConfigStore として、App Configuration を用います。
また、App Service そのものに対しては、SystemManaged Identity を付与、VNet 統合を行い、ついでの BYOS もつけておきます。


# Q1.ログがどう出るのか

**A**. mainコンテナとサイドカーコンテナで混ざります。

各コンテナからの標準/エラー出力は `YYYY_MM_DD_<MACHINAME>_default_docker.log` にまとめられるようです。
同様に `AppServiceConsoleLogs` も同様です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/257ebab8-9b33-960d-4eb1-dd353a89bd9b.png)


下記、mainコンテナ(Envoy)の出力とバックエンドアプリ(Node,Hono)の出力が1つのファイルにマージされている様子です。正直言ってこれは結構つらいですね。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/d9c72141-b10f-4a4e-eeed-5d0687de1bed.png)


https://azure.github.io/jpazpaas/2023/07/27/AppServiceOnLinux-Log.html

Application Insights については未確認ですが、同じ AI に対して複数のデータソースからデータを入れるということで工夫は可能と考えています。分散トレースとかできそうな予感。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/app/distributed-trace-data

# Q2.Web SSH できるのか

**A**. サイドカーにも SSH 接続できます。ただしちょっとしたセットアップが必要。

https://qiita.com/georgeOsdDev@github/items/8c937e26d07fd9d23bb2

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/459bb84f-3ec9-8feb-91f8-ecefc24f356b.png)


Kudu からの Web SSH は `main` コンテナに対して行われます。
すなわち `main` コンテナに対しては標準的な sshd のセットアップを行っておけばいつも通り接続できます。

[SSH を有効にする](https://learn.microsoft.com/ja-jp/azure/app-service/configure-custom-container?tabs=debian&pivots=container-linux#enable-ssh)

サイドカーコンテナに対しては、`main` コンテナを踏み台としてそこから SSH することで接続可能です。
そのためには、サイドカーコンテナで sshd が listen するポートを 2222 と被らないようにする必要があります。
下記例では、サイドカーコンテナの sshd は 2223 ポートを利用するように構成してあり、Kudu から一度 `main` コンテナへ接続後に、ssh コマンドでサイドカーコンテナに接続した様子です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/009cd91f-00f6-9eb5-e1ed-6dcdc7e80b60.png)

# Q3. Haalth Check は利用できるのか

A. App Serviceのヘルスチェックは利用可能。
すなわち `main` コンテナに対する http ping のみ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/0cccdac2-6f78-aca9-73f0-8e32fcdf6f3a.png)

Container Apps における、[正常性プローブ](https://learn.microsoft.com/ja-jp/azure/container-apps/health-probes?tabs=arm-template)に該当する機能はいまのところない。

以下の通り、ポータルには Status という項目があるので将来に期待したいところ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/58ad169a-1df4-cd12-fb63-a98d989321c3.png)


**2025-02-28 追記**
Status 表示については
`<kudu>/api/sitecontainers/<containerName>` という Kudu APIを呼び出している

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/61147ace-61c8-4ea2-bee3-b8c3a7e01f7f.png)

```json
{
  "Name": "backend",
  "Status": "Running",
  "StartTime": "2025-02-28T00:20:54.7140206+00:00",
  "FinishTime": null,
  "TerminationReason": "None",
  "ExitCode": 0,
  "RunCount": 1,
  "ContainerId": "qiita2024-sidecar_backend_e80e4879",
  "Image": "toshidapublic.azurecr.io/backend:0.4-healthcheck",
  "ImageDigest": "sha256:910cb73f750cdbb268abd06f5ff8caaf09d9f5ee23565e29a11255b65e04a65d"
}
```


# Q4.コンテナ単位で再起動できるのか

**A**. コンテナ単位で再起動はできません。

各コンテナは一心同体のようで、どれかだけ一時的な停止や再起動といったことはできなそうです。
ポータルからリソースに対する停止、再起動操作は全てのコンテナに対して行われます。
なお、ポータルからのコンテナ構成更新時は以下の  API を呼び出しているようです。

https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/create-or-update-site-container?view=rest-appservice-2024-04-01

各コンテナの設定を変えたり、Web SSH 経由でプロセスKillしてコンテナを終了させた場合なども、
他のコンテナに対しては `SIGTERM` が送られることになり、すべてのコンテナが再起動されます。

例えば以下では `/crash` にリクエストがあった場合に、backendコンテナは終了するようにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/91243c16-f294-32d8-2adf-19676ad08460.png)

そのとき、main コンテナである envoy 側のログとして、`SIGTERM` が送られていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/e59897ff-949b-db6b-4fa6-d7c8df66a7a8.png)

# Q5. 環境変数(アプリケーション設定)は反映されるのか

**A**. デフォルトでは `main` コンテナ以外には設定されません。`properties.inheritAppSettingsAndConnectionStrings` を `true` にすると設定されます。

2024/11/20 時点では以下のように書かれていますが、entroypoint.sh で printenvした結果 main コンテナと backend コンテナでは設定されている環境変数に違いが確認できました。

> You configure environment variables for the containers like any App Service app, by configuring app settings. The app settings are accessible to all the containers in the app.

https://learn.microsoft.com/en-us/azure/app-service/tutorial-custom-container-sidecar#4-configure-environment-variables


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/0a05844e-96f9-e80a-39ac-5975e715000c.png)


確認用の `entrypoint.sh`は以下のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/d37b8587-b310-07be-7fd8-9655ad8d94df.png)

main 側
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/5a277e9f-45fa-d383-6be3-9430bae10afd.png)

backend 側
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/2be8ee73-45c4-810a-bc18-2abb3bb3ce50.png)

`APPSETTING_` prefix が付いたものおよび、`myEnvVar`がサイドカーには設定されていないですね。ただし、`IDENTITY_ENDPOINT` など一部は設定されているようです。

じゃあどうするのと色々APIを試していった結果、[Web Apps - Get Site Container API](https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/get-site-container?view=rest-appservice-2024-04-01#code-try-0)の応答に、`inheritAppSettingsAndConnectionStrings`というパラメータが `false` で設定されているのが見つかりました。Definition にも記載がないですが名前的にこれっぽいですね。
試しにこれを `true` にして [Create Or Update Site Container| Microsoft Learn](https://learn.microsoft.com/en-us/rest/api/appservice/web-apps/create-or-update-site-container?view=rest-appservice-2024-04-01)　を呼び出してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/9a2f3e24-892d-aa84-46fa-2ef877f30fda.png)

無事サイドカーコンテナでもAppSettingsに指定した値を環境変数として得ることができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/9aac83c4-4c53-167c-d138-74c3318de678.png)

ポータルから設定できなかったり、API定義があいまいで困りますね。GAとは。:innocent:


# Q6. ボリュームはマウントされるのか

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/7ce321d8-6a73-ec6d-a8c5-50ae74aee485.png)


## Q6-1. App Service Storage 

**A**. App Service Storage はサイドカーにもマウントされます。

`WEBSITES_ENABLE_APP_SERVICE_STORAGE` を `true` とすることで、各コンテナには永続的ストレージとして、`/home` がマウントされます。

以下のようにコンテナ間で同じファイルシステムにアクセス可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/26679032-cee0-cbac-c127-aed0ed386e9d.png)

[永続的な共有ストレージを使用する](https://learn.microsoft.com/ja-jp/azure/app-service/configure-custom-container?tabs=debian&pivots=container-linux#use-persistent-shared-storage)

## Q6-2. BYOS

**A**. BYOSはサイドカーにもマウントされます。

以下の通り。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/f0c4a9d8-6b81-11d1-e666-0ccdfbfb659c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/bdbbb142-b5e4-5b64-a16a-595724e60a90.png)


# Q7. VNet 統合はサイドカーコンテナにも適用されるのか

**A**. サイドカーも含めてワーカインスタンスが VNet 統合できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/9b14aef1-5e23-56f5-34a9-5ce0c3121317.png)


そもそも VNet 統合はインスタンスに対して適用されているものなので当然と言えば当然かもしれませんが、サイドカーコンテナにおいても `main` コンテナと同様に VNet 統合の効果を得られそうです。
以下、Private Endpoint を持つ別のアプリの DNS ルックアップの結果です。

`main` コンテナ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/2d9876fe-2ddd-b26a-aeaa-9f3ad79fba63.png)

サイドカーコンテナ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/bf0acdd6-6483-3f6d-6118-ca6667515c7d.png)

# Q8. Managed ID は利用できるのか

A. サイドカーでも利用できます。

サイドカーからも `IDENTITY_ENDPOINT` に対してアクセス可能です。
[マネージド ID - Azure App Service](https://learn.microsoft.com/ja-jp/azure/app-service/overview-managed-identity?tabs=portal%2Chttp#rest-endpoint-reference)

以下、サイドカーコンテナ内での動作確認の様子です。
AppConfigurationに対して DefaultCredential(=マネージドID)でアクセスしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/b9d3a458-3f2f-93bd-6928-83f149240260.png)

[マネージド ID を使用して App Configuration にアクセスする](https://learn.microsoft.com/ja-jp/azure/azure-app-configuration/howto-integrate-azure-managed-service-identity?pivots=framework-dotnet)
[App Configuration client library for JavaScript](https://learn.microsoft.com/en-us/javascript/api/overview/azure/app-configuration-readme?view=azure-node-latest)


# Q9. Dapr は利用できるのか

A. 利用できますが、トリッキーな気がします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/36fa276c-60b5-13d2-9ebb-cc71eaab86a8.png)

10 秒ごとに cron bindingが動作している様子
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/adfbf2d0-e27c-217c-dfe5-0574b1bac03a.png)

ConfigStoreへのアクセスの様子
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4914/54ce920c-e64c-0ab6-8c87-6f2e09aabd82.png)


長くなりそうなので別記事で詳細を書く予定。要点としては

- `dapr run` で開始できないので、[self-hosted mode](https://docs.dapr.io/operations/hosting/self-hosted/self-hosted-no-docker) で動かす必要がある
- ゆえにもろもろ制限がでてきそう。
- mDNSも動作しないはずなので、AutoDiscovery的なことはできないはず。
- Building Blockとして処理を抽象化するというメリットは得られそう。
- ManagedIDにも対応している。
- 先にDaprが動いていないとdaprClientがうまく動かない？？
- 何よりローカルでのデバッグがむずかしい。これは私がdaprに慣れていないという部分もあるかもしれないが。。。

12/09 書いた

https://qiita.com/georgeOsdDev@github/items/209c2cc76a7bdf734fb4