0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GHCRのDockerイメージをAzure Container Appsに低コストでデプロイする

0
Posted at

はじめに

Docker化したWebアプリを、できるだけ固定費を抑えてAzureにデプロイしたときの手順メモです。

今回は次の構成にしました。

ローカル
  -> docker build
  -> GitHub Container Registry(GHCR)へpush
  -> Azure Container Appsでpullして公開

Azure Container Appsを選んだ理由は、コンテナイメージをそのまま動かせることと、Consumption構成で min replicas = 0 にできることです。アクセスがないときは0台まで落とせるので、MVPや検証用途ではかなり扱いやすいです。

この記事ではアプリケーションの中身には触れず、デプロイ工程だけを書きます。

前提

ローカル環境:

  • Windows + PowerShell
  • Docker Desktop
  • Azure CLI
  • Git

利用するもの:

  • Azure Container Apps
  • GitHub Container Registry, ghcr.io
  • Dockerイメージ

Azure CLIのログインと拡張機能の準備:

az login
az extension add --name containerapp --upgrade
az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights

変数を用意する

作業しやすいようにPowerShell変数を置いておきます。

$RG="rg-your-app"
$LOCATION="japaneast"
$ENV_NAME="your-app-env"
$APP_NAME="your-app"
$GHCR_OWNER="your-github-user-or-org"
$IMAGE="ghcr.io/$GHCR_OWNER/your-app:latest"

$LOCATION は好きなリージョンでOKです。日本向けなら japaneastjapanwest あたりが選択肢になります。

GHCRにログインする

GitHub Container Registryにpushするため、GitHubのPersonal Access Tokenを用意します。

必要な権限の目安:

  • pushする場合: write:packages
  • private imageをAzureからpullする場合: read:packages

トークンをファイルに保存している場合は、次のようにログインできます。

Get-Content .\ghcr.txt | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin

成功すると次のように出ます。

Login Succeeded

Dockerイメージをbuildしてpushする

リポジトリ直下に Dockerfile がある前提です。

docker build -t $IMAGE .
docker push $IMAGE

初回は依存関係のインストールも走るので時間がかかります。

Container Apps環境を作る

まずリソースグループを作ります。

az group create `
  --name $RG `
  --location $LOCATION

次にContainer Apps Environmentを作ります。

低コスト優先なので、ここではログ保存先を none にしています。

az containerapp env create `
  --name $ENV_NAME `
  --resource-group $RG `
  --location $LOCATION `
  --logs-destination none

ログをAzure上でちゃんと見たい場合は、Log Analyticsを使う構成にした方がよいです。ただし検証用途では、ログ周りも課金ポイントになり得るので今回は切っています。

Container Appを作る

GHCRのイメージがpublicの場合

GHCR packageをpublicにしている場合、registry認証なしでpullできます。

az containerapp create `
  --name $APP_NAME `
  --resource-group $RG `
  --environment $ENV_NAME `
  --image $IMAGE `
  --ingress external `
  --target-port 10000 `
  --min-replicas 0 `
  --max-replicas 1 `
  --cpu 1.0 `
  --memory 2Gi `
  --env-vars `
    PORT=10000

--target-port はコンテナが待ち受けているポートに合わせます。
たとえばアプリが 10000 で起動するなら --target-port 10000 です。

GHCRのイメージがprivateの場合

private packageのまま使う場合は、Azure Container AppsにGHCRの認証情報を渡します。

$REGISTRY_SERVER="ghcr.io"
$REGISTRY_USERNAME="YOUR_GITHUB_USERNAME"
$REGISTRY_PASSWORD=Get-Content ".\ghcr.txt" -Raw
$REGISTRY_PASSWORD=$REGISTRY_PASSWORD.Trim()

Trim() は地味に大事です。トークンファイル末尾の改行が混ざると認証に失敗することがあります。

private imageの場合の作成コマンド:

az containerapp create `
  --name $APP_NAME `
  --resource-group $RG `
  --environment $ENV_NAME `
  --image $IMAGE `
  --registry-server $REGISTRY_SERVER `
  --registry-username $REGISTRY_USERNAME `
  --registry-password $REGISTRY_PASSWORD `
  --ingress external `
  --target-port 10000 `
  --min-replicas 0 `
  --max-replicas 1 `
  --cpu 1.0 `
  --memory 2Gi `
  --env-vars `
    PORT=10000

環境変数とシークレットを設定する

APIキーなどを直接環境変数に入れたくない場合は、Container Appsのsecretを使います。

例:

$MY_SECRET="your-secret-value"

az containerapp secret set `
  --name $APP_NAME `
  --resource-group $RG `
  --secrets my-secret="$MY_SECRET"

secretを環境変数として参照します。

az containerapp update `
  --name $APP_NAME `
  --resource-group $RG `
  --set-env-vars MY_SECRET=secretref:my-secret

通常の環境変数ならそのまま指定できます。

az containerapp update `
  --name $APP_NAME `
  --resource-group $RG `
  --set-env-vars APP_ENV=production

URLを確認する

作成できたら、公開URLを取得します。

$APP_URL = az containerapp show `
  --name $APP_NAME `
  --resource-group $RG `
  --query properties.configuration.ingress.fqdn `
  --output tsv

"https://$APP_URL"

ヘルスチェック用のエンドポイントがある場合は確認します。

Invoke-RestMethod "https://$APP_URL/health"

{"status":"ok"} のようなレスポンスが返れば、アプリは起動しています。

更新デプロイ

コードを変更したら、新しいタグでイメージをpushして、Container Appのimageを差し替えます。

未コミット変更も含めてわかりやすいタグにしたい場合:

$TAG="deploy-$(Get-Date -Format yyyyMMddHHmm)"
$IMAGE="ghcr.io/$GHCR_OWNER/your-app:$TAG"

docker build -t $IMAGE .
docker push $IMAGE

az containerapp update `
  --name $APP_NAME `
  --resource-group $RG `
  --image $IMAGE

コミット単位で管理したい場合:

$TAG=(git rev-parse --short HEAD)
$IMAGE="ghcr.io/$GHCR_OWNER/your-app:$TAG"

latest だけで運用すると、どのバージョンが動いているかわかりにくくなるので、検証でもタグを切る方が安心です。

scale-to-zero設定を確認する

低コスト運用で大事なのは min replicas = 0 です。

az containerapp show `
  --name $APP_NAME `
  --resource-group $RG `
  --query "{min:properties.template.scale.minReplicas,max:properties.template.scale.maxReplicas,cpu:properties.template.containers[0].resources.cpu,memory:properties.template.containers[0].resources.memory}"

期待値:

{
  "cpu": 1.0,
  "max": 1,
  "memory": "2Gi",
  "min": 0
}

min = 0 だとアクセスがないときにコンテナが停止します。
その代わり、久しぶりのアクセスではcold startで初回表示が遅くなることがあります。

検証イベント中だけ常時起動したい場合:

az containerapp update `
  --name $APP_NAME `
  --resource-group $RG `
  --min-replicas 1 `
  --max-replicas 1

終わったら戻します。

az containerapp update `
  --name $APP_NAME `
  --resource-group $RG `
  --min-replicas 0 `
  --max-replicas 1

失敗したところ

private GHCR imageでUNAUTHORIZEDになる

private packageを認証なしでpullしようとすると、次のようなエラーになります。

UNAUTHORIZED: authentication required

この場合は、次のどちらかで対応します。

  • GHCR packageをpublicにする
  • --registry-server, --registry-username, --registry-password を付ける

privateのまま使うなら、PATに read:packages が必要です。

createに失敗したContainer Appが残る

az containerapp create が途中で失敗すると、ProvisioningStateが Failed のリソースが残ることがあります。

その状態では registry set などが通らない場合があるので、一度削除して作り直すのが早いです。

az containerapp delete `
  --name $APP_NAME `
  --resource-group $RG `
  --yes

Budget Alertを設定する

低コスト構成でも、公開URLにアクセスが集まると費用が増える可能性があります。
Azure PortalからBudget Alertを作っておくと安心です。今回はCLIではなくPortal UIで設定しました。

手順:

  1. Azure Portalで コストの管理と請求 を開く
  2. Cost Management を開く
  3. 予算 を開く
  4. 追加 または 作成 を押す
  5. 対象スコープを選ぶ
  6. 予算名、金額、期間、通知先を設定する

設定例:

Scope: リソースグループ
Budget amount: 10 USD / month
Reset: Monthly
Alert:
  50%
  80%
  100%
Recipients:
  自分のメールアドレス

Budget Alertは課金を自動停止する機能ではなく、通知するためのものです。
止めたい場合は、手動で max replicas を下げるか、Container Appを停止・削除します。

緊急でアクセスを止めたい場合の例:

az containerapp update `
  --name $APP_NAME `
  --resource-group $RG `
  --min-replicas 0 `
  --max-replicas 0

もし max-replicas 0 が使えない場合は、ingressを無効化するか、リソースを削除する運用に切り替えます。

後片付け

検証が終わって完全に消す場合は、リソースグループごと削除します。

az group delete --name $RG

GHCRのpackageや外部DBなど、Azure外のリソースは別途削除が必要です。

まとめ

Azure Container Appsを使うと、Docker化したWebアプリを比較的少ない手順で公開できます。

低コストに寄せるなら、特に次を意識するとよさそうです。

  • Consumption構成を使う
  • min replicas = 0
  • max replicas = 1
  • Log Analyticsは必要になるまで使わない
  • Budget Alertを入れる
  • Docker imageはタグを切って更新する

小さく公開して反応を見るMVP用途なら、この構成はかなり扱いやすいと感じました。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?