Azure Container Apps を少し触ったメモ
先日、少し Azure Container Apps を触ってみました。その時のことを忘れないようにメモしておこうと思います。
Azure Container Apps とは
公式ドキュメントに詳細は譲りますが、サーバーレスで Docker イメージ化されたアプリをホストするための Azure のサービスで現時点では公開プレビューというステータスのサービスです。
試した内容
Azure Container Apps に Azure Container Registry に push したイメージのアプリをデプロイする。
Visual Studio 2022 のプレビュー版には、GitHub のリポジトリに紐づいているプロジェクトで発行をすると Azure Container Apps にデプロイするワークフローを出力してくれる機能があるので、それをベースにデプロイする方法を試してみました。あと、bicep で Azure Container Apps を作る方法も確認してみました。
Bicep で Azure Container Apps を作る
Azure Container Apps をデプロイするには最低で 3 つのリソースが必要です。コンテナイメージを置く場所も用意する場合は Azure Container Registry も必要なので 4 つになります。内訳は以下のようになります。
- Azure Log Analytics Workspace
- ログ出力先
- Azure Contaienr Apps Environment
- この中に Contaienr App をおいていくイメージ
- Azure Container Registry
- Docker イメージ置き場
- Azure Container App
- ここでアプリが動く。デプロイするイメージやメモリやCPUの設定や、スケールのルールもここに設定する。
まずは、Contaienr App をデプロイする前に上の 3 つのリソースをデプロイしないといけないので、その部分の bicep を作りました。以下のような感じです。
targetScope = 'resourceGroup'
param baseName string // リソースのベースの名前
param location string = resourceGroup().location
var resourceName = '${baseName}${uniqueString(resourceGroup().id)}'
// Log Analytics Workspace
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-06-01' = {
name: 'la-${resourceName}'
location: location
properties: {
sku: {
name: 'PerGB2018'
}
}
}
// Container Registry
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2021-09-01' = {
name: 'cr${resourceName}'
location: location
sku: {
name: 'Standard'
}
properties: {
adminUserEnabled: true
}
}
// Container Apps 環境
resource env 'Microsoft.Web/kubeEnvironments@2021-02-01' = {
name: 'ce-${resourceName}'
location: location
properties: {
type: 'managed'
internalLoadBalancerEnabled: false
appLogsConfiguration: {
// ログの出力先の設定
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalytics.properties.customerId
sharedKey: logAnalytics.listKeys().primarySharedKey
}
}
}
}
これを Azure CLI などで以下のようにデプロイします。
az group create --name rg-zenn --location "Canada Central"
az deployment group create --resource-group rg-zenn --template-file main.bicep --parameters baseName='kazukica'
次に Container App のデプロイもします。多分、環境のデプロイとアプリのデプロイは別タイミングでやることが多いと思うので別ファイルにしています。Container App 用のデフォルトのイメージをデプロイしたアプリを bicep で定義すると以下のような感じになります。
targetScope = 'resourceGroup'
param baseName string
param location string = resourceGroup().location
var resourceName = '${baseName}${uniqueString(resourceGroup().id)}'
resource env 'Microsoft.Web/kubeEnvironments@2021-02-01' existing = {
name: 'ce-${resourceName}'
}
resource app1 'Microsoft.Web/containerApps@2021-03-01' = {
name: 'app1'
kind: 'containerapp'
location: location
properties: {
kubeEnvironmentId: env.id
configuration: {
activeRevisionsMode: 'single'
ingress: {
external: true
targetPort: 80
}
}
template: {
containers: [
{
name: 'simple-hello-world-container'
image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
resources: {
cpu: '.25'
memory: '.5Gi'
}
}
]
scale: {
minReplicas: 1
maxReplicas: 3
}
}
}
}
これも、先ほどと同様に az コマンドでデプロイします。
az deployment group create --resource-group rg-zenn --template-file app.bicep --parameters baseName='kazukica'
アプリのデプロイ
アプリのデプロイは適当に .NET 6 の Web アプリを Docker のサポートにチェックを入れて作ったものをデプロイしてみました。作成時に Docker のサポートにチェックを入れ忘れても、作成後にプロジェクトの右クリックメニューの追加から Docker ファイルを追加することができます。
このプロジェクトを GitHub のリポジトリと紐づけた状態で Azure に発行を行うと発行のウィザードで Azure Container Apps が選択出ます。
そして、Container App の選択画面が出てくるので先ほど作った Container App を選択します。
コンテナ名は先ほどデフォルトのイメージをデプロイした simple-hello-world-container を選択します。
続けて Docker イメージを push するリポジトリも選択します。
そして、最後に GitHub Actions を選択すると発行のウィザードは完了です。
これで GitHub の方にワークフローで使う資格情報などがシークレットに自動的に登録されます。
APP1_SPN が Azure にデプロイをするために使われる資格情報で、下の2つが Azure Container Registry のユーザー名とパスワードになります。
生成される YAML は以下のようになっていますが、このままだとちょっと動きません。まだプレビューなので、こなれてない感じですが、正式版だとちゃんと動くようになると思います。
name: Build and deploy .NET application to Container App app1
on:
push:
branches:
- master
env:
CONTAINER_APP_CONTAINER_NAME: simple-hello-world-container
CONTAINER_APP_NAME: app1
CONTAINER_APP_RESOURCE_GROUP_NAME: rg-zenn
CONTAINER_REGISTRY_LOGIN_SERVER: crkazukicaragl6rolk7hnw.azurecr.io
DOCKER_FILE_PATH: ./Dockerfile
PROJECT_NAME_FOR_DOCKER: webapplication8
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout to the branch
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Log in to container registry
uses: docker/login-action@v1
with:
registry: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}
username: ${{ secrets.crkazukicaragl6rolk7hnw_USERNAME_FFFF }}
password: ${{ secrets.crkazukicaragl6rolk7hnw_PASSWORD_FFFF }}
- name: Build and push container image to registry
uses: docker/build-push-action@v2
with:
push: true
tags: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/${{ env.PROJECT_NAME_FOR_DOCKER }}:${{ github.sha }}
file: ${{ env.DOCKER_FILE_PATH }}
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.app1_SPN }}
- name: Deploy to containerapp
uses: azure/CLI@v1
with:
inlineScript: >
echo "Installing containerapp extension"
az extension add --source https://workerappscliextension.blob.core.windows.net/azure-cli-extension/containerapp-0.2.1-py2.py3-none-any.whl --yes
echo "Starting Deploying"
az containerapp update --name ${{ env.CONTAINER_APP_NAME }} --resource-group ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }} -i ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/${{ env.PROJECT_NAME_FOR_DOCKER }}:${{ github.sha }} --registry-login-server ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }} --registry-username ${{ secrets.REGISTRY_USERNAME }} --registry-password ${{ secrets.REGISTRY_PASSWORD }} --debug
- name: logout
run: >
az logout
上側の build のジョブで Azure Container Registry にイメージを push しているのですが、Docker ファイルへのパスが ./Dockerfile になっています。正確には ./プロジェクト名/Dockerfile になるので環境変数の DOCKER_FILE_PATH の修正をします。
そして下側の Azure Container App へのデプロイをしている deploy ジョブの az containerapp update の行で指定している --registry-username と --registry-password に指定されているシークレットのキーが間違っています。正確には GitHub Actions のシークレットの名前と合わせないといけないので build ジョブで使われているものと同じものを指定しないといけません。
この修正を行って GitHub の push するとアプリがビルドされて Azure Container Registry に登録されて、Container App にデプロイされます。
ただ、この方法だと CPU やメモリやスケールの設定を変更しようとするとポータルではまだサポートされていなさそうだし Contaienr App をデプロイした bicep をいじってデプロイすると、多分デプロイされているイメージまで上書きされちゃいそうなので、このデフォルトのスクリプトの deploy ジョブは以下のように置き換えてみました。
方針としては、ここで bicep を使って Container App に新しいイメージにデプロイしています。
以下のような bicep をソリューションの任意の場所に起きます。
targetScope = 'resourceGroup'
param projectNameForDocker string
param containerAppName string
param revision string
param containerLoginServer string
@secure()
param containerUserName string
@secure()
param containerPassword string
param baseName string
param location string = resourceGroup().location
var resourceName = '${baseName}${uniqueString(resourceGroup().id)}'
resource env 'Microsoft.Web/kubeEnvironments@2021-02-01' existing = {
name: 'ce-${resourceName}'
}
resource app1 'Microsoft.Web/containerApps@2021-03-01' = {
name: containerAppName
kind: 'containerapp'
location: location
properties: {
kubeEnvironmentId: env.id
configuration: {
secrets: [
{
name: 'acrpassword'
value: containerPassword
}
]
registries: [
{
server: containerLoginServer
username: containerUserName
passwordSecretRef: 'acrpassword'
}
]
ingress: {
external: true
targetPort: 80
}
}
template: {
revisionSuffix: revision
containers: [
{
name: containerAppName
image: '${containerLoginServer}/${projectNameForDocker}:${revision}'
resources: {
cpu: '.25'
memory: '.5Gi'
}
}
]
scale: {
minReplicas: 1
maxReplicas: 3
}
}
}
}
そして、この bicep を使ってデプロイするように GitHub Actions のワークフローを書き換えます。
name: Build and deploy .NET application to Container App app1
on:
push:
branches:
- master
env:
RESOURCE_BASE_NAME: kazukica
CONTAINER_APP_CONTAINER_NAME: simple-hello-world-container
CONTAINER_APP_NAME: app1
CONTAINER_APP_RESOURCE_GROUP_NAME: rg-zenn
CONTAINER_REGISTRY_LOGIN_SERVER: crkazukicaragl6rolk7hnw.azurecr.io
DOCKER_FILE_PATH: ./WebApplication8/Dockerfile
PROJECT_NAME_FOR_DOCKER: webapplication8
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout to the branch
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Log in to container registry
uses: docker/login-action@v1
with:
registry: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}
username: ${{ secrets.crkazukicaragl6rolk7hnw_USERNAME_FFFF }}
password: ${{ secrets.crkazukicaragl6rolk7hnw_PASSWORD_FFFF }}
- name: Build and push container image to registry
uses: docker/build-push-action@v2
with:
push: true
tags: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/${{ env.PROJECT_NAME_FOR_DOCKER }}:${{ github.sha }}
file: ${{ env.DOCKER_FILE_PATH }}
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout to the branch
uses: actions/checkout@v2
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.app1_SPN }}
- name: deploy
uses: azure/arm-deploy@v1
with:
subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION }}
resourceGroupName: ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }}
template: ./app.bicep
parameters: projectNameForDocker=${{ env.PROJECT_NAME_FOR_DOCKER }} containerAppName=${{ env.CONTAINER_APP_NAME }} revision=${{ github.sha }} containerLoginServer=${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }} containerUserName=${{ secrets.crkazukicaragl6rolk7hnw_USERNAME_FFFF }} containerPassword=${{ secrets.crkazukicaragl6rolk7hnw_PASSWORD_FFFF }} baseName=${{ env.RESOURCE_BASE_NAME }}
failOnStdErr: false
- name: logout
run: >
az logout
このほかにサービスプリンシパル(secrets.app1_SPN) の権限がデプロイするためにはちょっと足りないので足しておきます。今回の場合は app1 という名前のサービスプリンシパルが作られているのでリソースグループのアクセス制御から共同作成者の権限をつけておきます。
こうすると、メインのブランチに更新があるたびに、Container App にアプリがデプロイされるようになります。スケールとか変えたかったら bicep いじっただけでもこの形のパイプラインだとアプリも再デプロイなのがちょっと気になる今日この頃。
Discussion