Web App for Containers vNet統合経由でプライベートエンドポイント先のACRからイメージPullする

Web App for Containersで、vNet(vNet統合)を経由したACRからのpullを試しました。
[App Service Team Blog](https://azure.github.io/AppService/2021/07/03/Linux-container-from-ACR-with-private-endpoint.html) に手順が公開されていますが、Azure Portalからの実現方法やデプロイメントスロットを使った場合の注意点を残します。

# 構成
* 以下のような構成で試しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/eabbe854-fbd2-d133-1257-40ad5b87066c.png)

# vNet作成
* 以下のリソースを作成します。作成手順は割愛します。
    * vNet
        * vm-subnet
        * private-endpoint-subnet
        * vnet-integration-subnet

# ACR作成
* ACRへのアクセスはプライベートエンドポイント経由で行います。プライベートエンドポイントはSKU Premiumが必要なので、Premiumで作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/db08e204-202c-df85-dfc8-ffb9dbd5ed76.png)

* ネットワーク設定は最初はパブリックアクセスで作成します。あとで変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/f0de9269-4df2-cd71-80d8-db97b16e4103.png)

* 作成されたら管理者ユーザーを有効化しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/e47dc7a9-32a1-190f-42b2-be8226631c61.png)

# サンプルアプリケーション準備
## VM作成
* 検証用のVMを作成します。作成先Subnetはvm-subnetとし、OSはUbuntuとします。

## サンプルイメージをACRにPush
* 検証用VMにログインしサンプルアプリをACRにPushします。

```
# echo '<h1>ACR Test v1</h1>' > index.html
# echo 'FROM nginx:latest' > Dockerfile
# echo 'COPY index.html /usr/share/nginx/html' >> Dockerfile
# az login
# az account list --output table --all
# az account set --subscription [Subscrption ID]
# az acr build --registry [Container Registry Name] --image nginx-test:v1 .
```

* Azure PortalからリポジトリにイメージがPushされていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/6e6a5508-346e-2d84-9f10-cf42d8089562.png)

# Web App for Containers作成
* Linuxコンテナーを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/83f57cb6-cb03-27de-66f8-f6b689fef81b.png)

* デプロイメントスロットを使いたいので P1v2 でいきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/d6b69eab-cfc7-1487-a35e-860f4ac4482f.png)

* コンテナー設定画面では事前に準備したACRのイメージを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/0c76d502-265d-91f3-c446-ae9e5bc6c356.png)

* ネットワーク関連はあとで設定する為ここでは無効にしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/35044801-0eff-e9bb-2d8d-aa7c13a77bd3.png)

* Application Insightsは必要に応じて設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/958f3138-3d1b-5c6a-654f-18e498544a12.png)

* 作成されたらWebブラウザからURLにアクセスします。以下の画面が表示されればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/e881736a-f386-7f38-3e4f-e75c4664c16e.png)

# Web App for Containers設定
## PrivateEndpoint設定
* 特定のvNetからしかアクセスできないよう設定します。
* Web Appから[ネットワーク]→[プライベートエンドポイント]の順に選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/7d2b9a95-8abc-bb7e-8f10-1751747c6b63.png)

* [追加]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/4e536e39-baa9-2fb9-c8d0-5e56c021919e.png)

* サブネットは事前に作成したプライベートエンドポイントのサブネットを指定します。vNet内からプライベートIPで名前解決させたいため、プライベートDNSゾーンと統合します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/233eabef-e7a8-77ae-86ea-e02b92947797.png)

## vNet統合
* vNetを経由してACRからPullするために、vNet統合を設定します。
* Web Appから[ネットワーク]→[VNET統合]の順に選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/0c9031d4-d77d-2be0-ed97-eb4b838d77ec.png)

* [vNetの追加]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/09de377c-1389-16f0-8365-08a296419b24.png)

* 事前に作成したvNet統合用のサブネットを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/701c145b-476e-4ebb-5e3a-371c738f0076.png)

## ManagedID設定
* ACRへの権限をWeb Appに与える為マネージドIDを設定します。
* Web Appから[ID]を選択し、システム割り当て済みマネージドIDを[オン]にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/4564879a-04b9-e884-24e0-b3aa003547df.png)

## アプリケーション設定
* Web Appから[構成]→[新しいアプリケーション設定]の順に選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/9776b51f-8f73-e70f-9606-4c6a3eaddd6d.png)

* [WEBSITE_PULL_IMAGE_OVER_VNET]に[true]を設定して追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/16748dc5-29d2-4f26-e374-4a26b182585e.png)

* Azure CLIから以下コマンドを実行します。この設定を入れることでACRの管理者ユーザーを無効にすることができます。

```
az resource update --resource-group [Resource Group Name] --name [Web App Name]/config/web --set properties.acrUseManagedIdentityCreds=true --resource-type 'Microsoft.Web/sites/config'
```

# ACR設定
## Private Endpoint作成
* 特定のvNetからしかアクセスできないよう設定します。

* コンテナーレジストリーから[ネットワーク]→[プライベートアクセス]→[プライベートエンドポイント接続を作成します]の順に選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/f981b385-39ae-517e-048a-2a9be3288c1a.png)

* エンドポイント名等を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/9af3c763-5f91-cce8-94ab-cc88b23164fc.png)

* 対象のサブリソースは[registry]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/9fe1d911-8b65-9a93-a826-a5d20c500262.png)

* 事前に作成したプライベートエンドポイントサブネットを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/ca559193-906e-eadd-906c-4aa933d2f64e.png)

* vNet内からプライベートIPで名前解決させたいため、プライベートDNSゾーンと統合します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/67ee170e-f0dc-1d74-1b59-2a8153f3d3a4.png)

* ACRの[ネットワーク]→[パブリックアクセス]の順に選択し、パブリックアクセスを無効にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/7164ab44-dc81-d3a3-1bcf-9c8e8028ae51.png)

    * 無効にするとPortalからリポジトリへのアクセスもできなくなってしまうので、自PCからのアクセスのみ有効にしておいたほうが使いやすいです。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/7e299df9-9161-149f-8d2d-9b0d6bf0cf0e.png)

* ACRの管理者ユーザーを無効にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/9dc40a67-e5a3-3f9b-9daf-6c093348746a.png)

## RBAC設定
* コンテナーレジストリーから[IAM]→[ロールの割り当ての追加]の順に選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/dc1da472-de0c-e48c-0899-fd5d22c9f3f0.png)

* [AcrPull]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/092eb2c1-b972-fdc1-cd73-69e6cffca46f.png)

* [マネージドID]→[メンバーを選択する]の順に選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/d44b3380-cde0-f7d0-415e-71c662d1b712.png)

* マネージドIDで[App Service]を選択すると、先ほどマネージドID設定したApp Serviceが出てくるので選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/43e755b6-31fd-f2aa-3bcb-c36123807f00.png)

# 検証
* 検証用VMから再度ACRにpushします。

```
# echo '<h1>ACR Test v2</h1>' > index.html
# az acr build --registry [Container Registry Name] --image nginx-test:v1 .
```

* App Serviceを再起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180335/7f154e37-a95b-7514-4f93-8d6192328f02.png)

* 検証用VMから確認し、v2に変わっていればOKです。（App Serviceをプライベートエンドポイント経由のみにしているため、vNet内からしかアクセスできなくなっています）

```
# curl https://[Web App Name].azurewebsites.net
<h1>ACR Test v2</h1>
```

# デプロイメントスロット設定
* デプロイメントスロットでは [スワップされない設定](https://docs.microsoft.com/ja-jp/azure/app-service/deploy-staging-slots) があります。
* 以下設定をデプロイメントスロット側にも実施することで、デプロイメントスロットでACRからPullすることができます。
    * マネージドID
    * VNET統合
    * プライベートエンドポイント
    * アプリケーション設定
* VNET統合サブネットはApp Serviceが分かれるとサブネットも分ける必要がありますが、デプロイメントスロットは同じApp Serviceなので、VNET統合サブネットは共存することが可能です。

以上