Azure Web App for Containers で Azure Container Registry と連携したお手軽 CI/CD を試してみた

## 背景と目的

Git プッシュをトリガーに CI/CD という名の自動化が動くわけですが、CI の部分は Azure Pipelines などでアプリをビルドしたりテストしたり Docker ビルドしたりして、最後は Azure Container Registry にプッシュするところまでをやっている前提があったとします。もちろん、Azure Pipelines で CD までやる事はできるのですが、今回は CD の部分を Azure Container Registry にプッシュされたのをトリガーに Azure Web App for Containers のコンテナイメージが更新される仕組みを試してみました。

## 前提条件

コマンドの実施環境は、Mac + Azure CLI です。

```bash:bash
$ sw_vers
ProductName:    macOS
ProductVersion: 12.2
BuildVersion:   21D49

$ az version
{
  "azure-cli": "2.32.0",
  "azure-cli-core": "2.32.0",
  "azure-cli-telemetry": "1.0.6",
  "extensions": {}
}
```

## 検証用の Azure Container Registry と Azure Web App を作る

```bash:bash
# 環境変数をセットします
region=japanwest
prefix=mnrcicd1

# リソースグループを作成します
az group create \
  --name ${prefix}-rg \
  --location $region

# Azure Container Registry を作成します
az acr create \
  --name ${prefix}acr \
  --resource-group ${prefix}-rg \
  --sku Basic \
  --admin-enabled true

# 作業用ディレクトリを作成して移動します
mkdir ${prefix} && cd ${prefix}

# Dockerfile を作成します
cat <<EOF > Dockerfile
FROM ubuntu/nginx
EOF

# Azure Container Registry でビルドしてイメージを登録します
az acr build \
  --resource-group ${prefix}-rg \
  --registry ${prefix}acr \
  --image ${prefix} \
  .

# App Service Plan を作成します
az appservice plan create \
  --name ${prefix}plan \
  --resource-group ${prefix}-rg \
  --sku FREE \
  --is-linux

# Azure Web App for Containers を作成します
az webapp create \
  --name ${prefix}app \
  --resource-group ${prefix}-rg \
  --plan ${prefix}plan \
  --deployment-container-image-name ${prefix}acr.azurecr.io/${prefix}:latest \
  --docker-registry-server-user ${prefix}acr \
  --docker-registry-server-password $(az acr credential show \
  --resource-group ${prefix}-rg \
  --name ${prefix}acr \
  --query passwords[0].value \
  --output tsv)

# Web App にアクセスして nginx のデフォルトページが表示される事を確認します
open https://${prefix}app.azurewebsites.net
```

## Azure Container Registry にプッシュされたら Azure Web App を自動更新する設定

```bash:bash
# Web App のデプロイセンターにある継続デプロイ設定をオンにします
az webapp deployment container config \
  --name ${prefix}app \
  --resource-group ${prefix}-rg \
  --enable-cd true

# Azure Container Registry に Webhook を作成します
az acr webhook create \
  --name ${prefix}webhook \
  --resource-group ${prefix}-rg \
  --registry ${prefix}acr \
  --scope ${prefix} \
  --actions push \
  --uri $(az webapp deployment container show-cd-url \
  --name ${prefix}app \
  --resource-group ${prefix}-rg \
  --query CI_CD_URL \
  --output tsv)
```

## Docker イメージを更新して 想定した CD が実現するか試す

```bash:bash
# Dockerfile を更新します
cat <<EOF > Dockerfile
FROM ubuntu/nginx

RUN date > /var/www/html/index.html
EOF

# Azure Container Registry でビルドしてイメージを更新します
az acr build \
  --resource-group ${prefix}-rg \
  --registry ${prefix}acr \
  --image ${prefix} \
  .

# Webhook イベントが発生したことを確認します
az acr webhook list-events \
  --name ${prefix}webhook \
  --registry ${prefix}acr \
  --resource-group ${prefix}-rg \
  --output table

# Web App にアクセスしてビルドした時の日時が表示される事を確認します
open https://${prefix}app.azurewebsites.net
```

## (おまけ) Azure ポータルの App Service にある開発ツール SSH から接続できるようにする設定

```bash:bash
# Dockerfile を更新します
cat <<"EOF" > Dockerfile
FROM ubuntu/nginx

RUN date > /var/www/html/index.html

ENV SSH_PASSWD "root:Docker!"
RUN apt-get update \
        && apt-get install -y --no-install-recommends dialog \
        && apt-get update \
  && apt-get install -y --no-install-recommends openssh-server \
  && echo "$SSH_PASSWD" | chpasswd
COPY sshd_config /etc/ssh/
COPY init.sh /usr/local/bin/
RUN chmod u+x /usr/local/bin/init.sh

EXPOSE 80 2222
ENTRYPOINT ["init.sh"]
EOF

# sshd_config を作成します
cat <<"EOF" > sshd_config
Port 2222
ListenAddress 0.0.0.0
LoginGraceTime 180
X11Forwarding yes
Ciphers aes128-cbc,3des-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr
MACs hmac-sha1,hmac-sha1-96
StrictModes yes
SyslogFacility DAEMON
PasswordAuthentication yes
PermitEmptyPasswords no
PermitRootLogin yes
EOF

# init.sh を作成します
cat <<"EOF" > init.sh
#!/bin/bash
set -e

# App Service のアプリケーション設定で設定した環境変数をコンテナ内で参照できるようにする
eval $(printenv | sed -n "s/^\([^=]\+\)=\(.*\)$/export \1=\2/p" | sed 's/"/\\\"/g' | sed '/=/s//="/' | sed 's/$/"/' >> /etc/profile)

service ssh start

nginx -g "daemon off;"
EOF

# Azure Container Registry でビルドしてイメージを更新します
az acr build \
  --resource-group ${prefix}-rg \
  --registry ${prefix}acr \
  --image ${prefix} \
  .

# Azure ポータル上で SSH できた場合、CLI 経由でも SSH できるか確認します
az webapp ssh \
  --name ${prefix}app \
  --resource-group ${prefix}-rg
```

## 参考

```bash:bash
# リソースグループを削除します
az group delete \
  --name ${prefix}-rg
```

下記は、参考サイトです。

<https://docs.microsoft.com/ja-jp/azure/app-service/deploy-ci-cd-custom-container?tabs=acr&pivots=container-linux>

<https://docs.microsoft.com/ja-jp/azure/app-service/tutorial-custom-container?pivots=container-linux#connect-to-the-container-using-ssh>

<https://hub.docker.com/layers/ubuntu/nginx/latest/images/sha256-b860aea03039564d6423a4cfb22035395956984392852e49c129769129424b02?context=explore>