Azure App Serviceに環境変数が設定されなくて困った。と思ったら原因が違った話

# はじめに
自作のdenoアプリのコンテナをAzure App Serviceにデプロイしたときに、環境変数が設定されないと思ったら、単にアプリ側で環境変数を読み込むようにしていなかった話です。

以下は試行錯誤のメモですが、結論は上記なのであまり読む意味はないかもしれないです。


# 事の発端
Qiita APIを使用して、特定のユーザがLGTMした記事一覧を取得するWebアプリ（deno）を作っていました。
ローカルの開発環境で正常にレスポンスが返却されることを確認し、Azure Web Appsにデプロイしたところ・・・

```
{"message":"Unauthorized","type":"unauthorized"}
```
こんなレスポンスが返ってきてしまいました。
どうやらQiita APIの認証が正しくされていないようです。

私の作ったアプリでは、環境変数`API_KEY`にQiita APIのアクセストークンを設定しているので、環境変数がうまく読み込めていないことが推測されます。

Azureポータルを確認すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227999/dc182dc2-27a4-48dd-e057-8900c0b4f7f2.png)

確かに`API_KEY`は設定されています。


おかしいな？と思い、Kuduコンソールからログを見てみると、こんな感じのログが出ていました（値はマスクしています）。

```:LogFiles/yyyy_mm_dd_XXX_docker.log（抜粋）
docker run -d -p 6740:5000 --name XXX -e WEBSITE_CORS_ALLOWED_ORIGINS=XXX -e WEBSITE_CORS_SUPPORT_CREDENTIALS=XXX -e WEBSITES_ENABLE_APP_SERVICE_STORAGE=XXX -e WEBSITES_PORT=5000 -e WEBSITE_SITE_NAME=XXX -e WEBSITE_AUTH_ENABLED=XXX -e WEBSITE_ROLE_INSTANCE_ID=XXX -e WEBSITE_HOSTNAME=XXX -e WEBSITE_INSTANCE_ID=XXX -e HTTP_LOGGING_ENABLED=XXX XXX  
```

docker runの時に`-e API_KEY=XXX`がついていない！他のはあるのに！
ここが原因だろうと推測し、焦点を当てて調べました。

ドキュメントには以下の記載があります。
[Things You Should Know: Web Apps and Linux | Microsoft Docs](https://docs.microsoft.com/ja-jp/archive/blogs/waws/things-you-should-know-web-apps-and-linux#SetEnvVar)
> App Settings are injected into your app as environment variables at runtime.
Applies to Azure App Service on Linux Applies to Web App for Containers
If you need to set an environment variable for your application, simply add an App Setting in the Azure portal. When your app runs, we will inject the app setting into the process as an environment variable automatically.

感覚的にはこれは正しく、実際他のアプリでは普通に環境変数を読み込めています。


次に、以下のIssueを見つけました。

* [Web App with custom docker image in azure container registry - environment variables · Issue #8423 · MicrosoftDocs/azure-docs](https://github.com/MicrosoftDocs/azure-docs/issues/8423)

> When I tail the log stream of my container, I can see the actual command that is ran in order to spin the container up. While it does contain the following ENV_VARS, the ones I set as application settings are still missing.

結構昔のIssueですが、同じような現象が起こっている人がいるっぽいです。
これはAzureのバグか・・・？
だとするとお手上げです。

DockerfileのENVに設定したり、.envをPushしてしまえば回避はできそうですが、アクセストークンを公開するのは当然やりたくありません。

なんとかして、環境変数を入れ込むことできないかなぁ・・・


# 考えた苦肉の策
Azureポータル上からDockerコンテナ起動時のエントリーポイントを上書きし、「環境変数設定＋アプリ実行コマンド」をdocker run時に実行するようにしました。

具体的には、以下の「スタートアップ コマンド」に、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227999/96dac74b-fce8-4990-5cc4-3eb94c9b8fdb.png)

以下を設定しました。

```
sh -c "export API_KEY=XXX && deno run --allow-net --allow-read index.ts"
```
※もういらないだろうと思い、ポータルから設定した環境変数は消しました


再びKuduコンソールからログを確認すると、

```:LogFiles/yyyy_mm_dd_XXX_docker.log（抜粋）
docker run -d -p 8761:5000 --name XXX -e WEBSITE_CORS_ALLOWED_ORIGINS=XXX -e WEBSITE_CORS_SUPPORT_CREDENTIALS=XXX -e WEBSITES_ENABLE_APP_SERVICE_STORAGE=XXX -e WEBSITES_PORT=5000 -e WEBSITE_SITE_NAME=XXX-e WEBSITE_AUTH_ENABLED=XXX -e WEBSITE_ROLE_INSTANCE_ID=XXX -e WEBSITE_HOSTNAME=XXX -e WEBSITE_INSTANCE_ID=XXX -e HTTP_LOGGING_ENABLED=XXX XXX sh -c "export API_KEY=0090f2939950cb952d569adee4a15caddae4d807 && deno run --allow-net --allow-read index.ts" 
```

確かにコマンドは渡っていそうです。


<br>
しかし、レスポンスは相変わらずUnauthorized。

これでも無理なのはおかしい！！


<br>
・・・もしかして、アプリ側の問題なのでは？


# 示された道筋
現状のコードは以下の通りです。



```ts:index.ts（抜粋）
import { config } from "https://deno.land/x/dotenv/mod.ts";

// .env読み込み
let env = config();

// 変数利用
headers: {
  Authorization: `Bearer ${env.API_KEY}`,
},
```

待てよ・・・
Node.jsと違って`process.env`で読み込んでいるわけじゃないから、このコードだと`.env`ファイルからしか読み込まないんじゃ・・・？

環境変数を直で読み込む方法を調べると、

[github.com/denoland/deno/releases/latest/download/lib.deno.d.ts - deno doc](https://doc.deno.land/https/github.com/denoland/deno/releases/latest/download/lib.deno.d.ts#Deno.env)

> const Deno.env: { get(key: string): string | undefined, set(key: string, value: string): void, delete(key: string): void, toObject(): { index: string: string } }

`Deno.env.get`というのが該当しそう。

ついでに、


[Deno](https://deno.land/manual/getting_started/permissions#permissions-list)
> --allow-env Allow environment access for things like getting and setting of environment variables.


なんか`--allow-env`ってオプションあるわ・・・


というわけで、「スタートアップ コマンド」を以下のように変更し、

```:--allow-envを追加
sh -c "export API_KEY=XXX && deno run --allow-net --allow-read --allow-env index.ts"
```

ソースコードを以下のように変更しPushすると・・・

```ts:index.ts（抜粋）
import { config } from "https://deno.land/x/dotenv/mod.ts";

// 環境変数読み込み
let env = config();
if (Deno.env.get("API_KEY")) {
  env.API_KEY = Deno.env.get("API_KEY")!;
}

// 変数利用
headers: {
  Authorization: `Bearer ${env.API_KEY}`,
},
```

動・・・かない！動かない！
相変わらずUnauthorizedです。



・・・いや、こうなってくると、そもそもポータルから設定した環境変数は実はちゃんと存在していて、単に読み込めていなかった説があるのでは・・・？



# 本当の原因
「スタートアップ コマンド」を削除し、Azureポータルからもう一度`API_KEY`を設定し再ビルドすると、何事もなかったかのように動きました。

つまり、「開発環境では.envから環境変数を読み込むためにconfigモジュールを使っていたが、本番環境では環境変数を直で読み込むために`Deno.env.get()`を使う必要があった」

というのが本当の原因と言えそうです。


ただし、謎も二つ残ります。

* なぜAzureポータルから環境変数を設定しても、ログの`docker run`に`-e`で渡らないのか（それでなぜ動くのか）。
* なぜ「スタートアップ コマンド」に環境変数を渡してもなぜ動かないのか

でもまあ、今回は動いたのでよしとします。


# おわりに
早とちりはよくないですね。

ちなみに、`https://deno.land/x/dotenv/load.ts`を使用すれば.envに記述した環境変数も`Deno.env.get()`で取得できたみたいです。はじめに試した時に、VS Code上で「`Deno`モジュールが解決できないよ」的なエラーが（何故か）出ていたため、使えないと思ってスルーしちゃっていました。



無事構築できた手順の記事はこちらです。
↓↓↓↓
[Deno in Dockerなアプリ開発](https://qiita.com/LeftLetter/items/f6f7b09faadba7daa21a)