【Azure DevOps】コンテナアプリケーションをWebApp for Containerにデプロイする

## Azure DevOps Organizationsを作成
Azureポータルから「Azure DevOps Organizations」リソースを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/1c024ad3-8fa2-da98-0bbd-33ca9de3c55a.png)

### 新規のOrganizationsを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/5e7e4b85-4e62-712f-d8ed-829dd886c879.png)

### プロジェクトを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/19e8b601-104e-0d4b-6934-7cd756c5449e.png)
※今回はシンプルなNuxtのSPAをリポジトリにPushしました

## コンテナー レジストリ(ACR)を作成
https://docs.microsoft.com/ja-jp/azure/container-registry/container-registry-get-started-portal?tabs=azure-cli
- 作成されたら管理者ユーザーを有効化しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/f3b179df-66d4-8733-5e03-121efbd2a018.png)


## DevOpsでコンテナをACRにPushするパイプラインを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/253b5875-5bca-4e5e-195b-1abe033b4d54.png)

Azure Repos Gitを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/5e070d07-5185-bdc7-e64e-339baf864deb.png)

Dockerビルド＋ACRへのPushのテンプレートを選択し、対象のサブスクリプションを指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/9be3fcaa-afd3-c67f-c09b-48afbec105b9.png)

先程作成したACRを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/13007986-1551-c2ab-27cc-6676ec6a3e33.png)

ベースのYamlファイルを生成してくれるのでNuxtアプリケーションのビルドコマンドを追記してSave and Run
```yaml
# Docker
# Build and push an image to Azure Container Registry
# https://docs.microsoft.com/azure/devops/pipelines/languages/docker
trigger:
  - master

resources:
  - repo: self

variables:
  # Container registry service connection established during pipeline creation
  dockerRegistryServiceConnection: "8abda5f8-xxxx-xxxx-xxxx-a6d3b853a87c"
  imageRepository: "demo"
  containerRegistry: "dvosdemo.azurecr.io"
  dockerfilePath: "$(Build.SourcesDirectory)/Dockerfile"
  tag: "latest"
  # Agent VM image name
  vmImageName: "ubuntu-latest"

pool:
  vmImage: $(vmImageName)

steps:
  - script: npm install --save nuxt
    displayName: "npm install"

  - script: npm run generate
    displayName: "npm generate"

  - task: Docker@2
    displayName: Build and push an image to container registry
    inputs:
      command: buildAndPush
      repository: $(imageRepository)
      dockerfile: $(dockerfilePath)
      containerRegistry: $(dockerRegistryServiceConnection)
      tags: |
        $(tag)

```

実行が成功するとACRにPushされたコンテナを確認できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/fed7134e-a4d0-b99c-d69c-0ede2346d731.png)


### サービスコネクションとは
dockerRegistryServiceConnectionはサービスコネクションと呼ばれるAzureリソースの認証情報を含んだ接続情報で、別のパイプラインから使用する等汎用的に利用できます。
今回の場合、対象のサブスクリプション指定した段階で作成されています。
コネクションの管理はDevOpsプロジェクトのService connectionsから確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/48abd165-86cf-032e-9226-de8cafb32519.png)

サービスコネクションのについてもう少し深堀すると、実態はサービスプリンシパルです。
今回のケースだと対象のACRのIAMに共同作成者として作成されたサービスプリンシパルが追加されています。
したがってサービスコネクションの作成には、対象テナントのAzureADで「アプリケーションを作成できる権限」とAzureサブスクリプション側では「ユーザーアクセス管理者」（サービスプリンシパルにロールを割り当てるための権限）を持っているアカウントで実施する必要があることに注意です。
サブスクリプションやリソースの接続時にエラーになった場合はこの辺りを確認してみてください。

### Azure Hosted Runnerを使う際の注意点
パイプライン実行時に以下のようなエラーに遭遇

`No hosted parallelism has been purchased or granted. To request a free parallelism grant, please fill out the following form https://aka.ms/azpipelines-parallelism-request`
原因：https://docs.microsoft.com/ja-jp/azure/devops/release-notes/2021/sprint-184-update
解決方法：
https://qiita.com/Hachiyou-Renge/items/2083f2ce9e8b38558805

## WebApp for Containerの作成
続いてデプロイ先のWebAppを作成します。
#### 基本設定
- Linuxコンテナーを選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/00b5a569-c3ab-1057-bcf0-5ed9966d6a11.png)

- 後々デプロイメントスロットを使いたいので P1v2を指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/64692b3b-4407-7559-ccc2-b58600129751.png)

#### Docker
- 事前に準備したACRのイメージを選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/5fb176c3-4ec3-c5e9-d565-276696d0d840.png)
※ACRで管理者ユーザーを有効化していないとエラーになるので注意

#### 動作確認
作成されたWebAppにアクセスし、アプリケーションが動作していればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/ef32699d-5e76-da64-d7dd-52be1a609fbf.png)

## デプロイ用のReleaseを作成
DevOpsのプロジェクトに戻り、PipelinesのReleasesを選択⇒New pipeline
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/810d30a7-a92c-8fe2-038c-c0e301c5b226.png)

#### Artifacts
ArtifactのSouce typeはBuildを選択し、最新のPipeline完了後に起動するように設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/a4a24405-784f-2610-6094-ec766e99a4ca.png)

トリガーを有効化
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/1d836a94-967e-8088-35df-35c9f08fe651.png)

#### Stage
***Agent Job***：Stageが実行される環境の設定
この環境に対してTaskを追加していく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/2bd195f7-6b3e-ade4-009b-c12136dc5bd7.png)

***Azure App Service deploy***
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/098e5209-1bb1-3fff-71be-e3a911c2b908.png)

***Azure App Service manage：WebAppの再起動***
上記deployの実行のみでは明示的なイメージの再起動とプルは行いません
そのため、無理やりですがTaskとして再起動を実施しています。
※アプリケーションの瞬断が発生するので気になる方は一度デプロイスロットにデプロイ⇒スロットを再起動⇒スワップで回避できます（[別記事](https://qiita.com/Yosuke_Sakaue/items/d2f8290f154302e9bfad)で紹介）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/5f668fb3-76c4-314c-9cdb-ec58d2b92d61.png)

## 動作確認
アプリケーションを修正してコミットするとPipeline⇒Releasesの順で実行され、WebAppが更新されれば完成です！

Pipelineのログ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/7adfd59d-04ea-4d4f-a2fa-209e6050aa10.png)

Releases 各TaskのログはLogsから確認可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/7eb22905-a7a0-7df4-c6b4-1b10eb051350.png)

WebAppも無事更新されました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/6f658b43-62f1-c821-639e-4b26b0e1a984.png)

以上