Azure Container Apps/GitHub Actionsを使ったコンテナアプリのブルーグリーンデプロイメント


このブログエントリは、MicrosoftのGlobal Blackbelt for cloud native applicationsであるDennis ZielkeのブログImplementing continuous blue/green deployments on Azure Container Apps by using GitHub Actionsについて、Dennisの承諾を得て日本語に翻訳しています。


Microsoft Azureは、GitHub ActionsやAzure Monitorに加えて、新しいServerless Application Platformである「Container Apps」をリリースしました。そこで私は、KubernetesとAzure上でBlue/Greenの継続的デプロイを行うというシナリオを再検討し、新しい技術スタックを使ってそれを実装する方法を紹介します。もし、Container Appsを使う機会がないけれと自分で試してみたいと思っているのであれば、お勧めの記事です。

ここでは、以下の機能を試します:

システムの概要

この記事の目的は、ブルー/グリーンデプロイメントを実施し、GitHub Actionsを使用した場合に、Azure Container Appsでのダウンタイムのない継続的デプロイメントがどれだけ簡単かを確認することです。もちろん、他のCI/CDツールチェーンを使用することもできますが、ロジックのほとんどがシェルスクリプトで実装されているため、プロセスを移行する方法を簡単に見つけることができるでしょう。

Our application will implement blue/green deployments using the builtin features of Container Apps

アプリの概要

私は、素因数分解の計算を分散して実装するデモアプリケーションを作成しました。このアプリケーションは、キャッシングとサービス間の呼び出しにDaprを利用し、バックエンドとフロントエンドのサービスで構成されています。このアプリケーションのコード、スクリプト、セットアップ方法の説明は、Dennis ZielkeのGitHubリポジトリにあります。このリポジトリをフォークして、ご自身のAzure環境でシナリオを試してみることをお勧めします。

The builtin features of Dapr, Keda and Envoy simplify a lot of the operational concerns during the upgrades.

以下で、その仕組みをご紹介したいと思います。

パイプラインの構成とインフラの構築

まず最初にしなければならないのは、GitHub Actionsのパイプラインを設定するために、リポジトリをforkすることです。GitHubとAzureが信頼関係の機能をアップグレードしたことをご存知でしょうか。GitHub リポジトリのパイプラインに GitHubのトークンとAzure ADのトークンを交換する権限を与えれば、クライアントのSecretを共有しなくても Azureリソースを操作できるようになるということです。これは大きな進歩です。

私のリポジトリにあるパイプラインは、アプリの登録を作成し、Azureサブスクリプション内の専用リソースグループにContributorパーミッションを付与していることを前提としています。

# デプロイメント名
DEPLOYMENT_NAME="dzca11cgithub" 
# リソースグループ名
RESOURCE_GROUP=$DEPLOYMENT_NAME 
# Azure リージョン名(japaneastは未対応)
LOCATION="eastus" 

# AzureのサブスクリプションID
AZURE_SUBSCRIPTION_ID=$(az account show --query id -o tsv) 

# GitHubのユーザ名
GHUSER="denniszielke"
# GitHubのリポジトリ名
GHREPO="blue-green-with-containerapps"

# テナントID
AZURE_TENANT_ID=$(az account show --query tenantId -o tsv)

# リソースグループの作成
az group create -n $RESOURCE_GROUP -l $LOCATION -o none

# spの作成
AZURE_CLIENTID=$(az ad sp create-for-rbac --name "$DEPLOYMENT_NAME" --role contributor --scopes "/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP" -o json | jq -r '.appId')

ここで、GitHub リポジトリと Azure AD テナントとのフェデレーションを許可する必要があります。Azure Portalを開き「Azure Active Directory」→「App registrations」→「上記で設定したDEPLOYMENT_NAME」→「Certificates & secrets」→「Federated credentials」に移動し、mainブランチでトリガーされるパイプラインが、アプリ登録のセキュリティコンテキスト内でトークンを交換することを許可します。

Make sure that your repo and branch can exchange tokens

次に、以下のシークレットをgithubリポジトリに追加する必要があります。Azure ADとのフェデレーションの機能によって「Client Secret」が不要になったことに注目しましょう。

Create these GitHub Secrets in your forked repo

これで、GitHub パイプラインがどこにデプロイすればよいかがわかるようになりました。

注意しておきたいのは、Pipeleneで実装されたトークン交換の実行には1分かかることと、現時点ではazure cliのベータ版が必要なことです。 これが完了したら、GitHub Actuionsのdeploy-infrastructure パイプラインを手動で起動して、Container Appsを含むAzureリソースを作成できます。

Use the pipeline to create your azure resources

サンプルアプリのデプロイ

次に、ソースコードを変更するか、deploy-full-blue-green パイプラインを手動でトリガーすることで、アプリケーションの最初のデプロイを実行します。

これでアプリケーションのblueリビジョンが動作するようになりました。ここで、デプロイメントプロセスを構成する300 行のシェルスクリプトを見てみましょう。もしGitHub パイプラインを使いたくない場合は、deploy.sh スクリプトに、次のパラメータを指定してローカルマシンから同じ処理を実行できます。

bash ./deploy.sh $RESOURCE_GROUP $IMAGE_TAG $CONTAINER_REPOSITORY

ブルーグリーンデプロイメントの原則とは、以前のリビジョン(このリビジョンをbuleとする)を置き換える代わりに、新しいバージョン(このリビジョンをgreenとする)を既存のバージョンの隣に立ち上げるものの、実際のユーザーにはすぐに公開しないことを意味しています。greenが正常に動作することを検証できた場合、ダウンタイムなしにルーティング設定を変更して、このリビジョンを正常系(本番系)に昇格させます。もしgreenリビジョンで何か問題が発生した場合、ユーザーは中断に気づくことなく、元に戻すことができます。

Azure Container Appsをつかうと、複数のリビジョンを同時にデプロイすることができ、どのリビジョンがどの相対的な量のトラフィックを受信しているかをAPI経由で制御できるため、多くのケースで必要になる非機能要件はすでにプラットフォームの一部となっています。

最初のデプロイメントでは、リビジョンモードがmultipleに設定されていることを確認する必要があります。これは、アクティブでトラフィックを受信しているリビジョンの数を制御できることを意味します。いくつかのシナリオでは、プラットフォームが異なるリビジョン間を自動的に切り替えることに意味がありますが、私たちは本番トラフィックをさらに細かく制御したいと考えています。複数のリビジョンを使用すると、各リビジョン専用の FQDNが得られ、お客様に気づかれることなく新しいリビジョンのウォームアップと検証を非公開で行うことができます。

The revision mode gives us manual control over traffic splits and routing

もしリビジョンが期待通りに動作していないと判断した場合、リビジョンを無効にして、次のリリースで修正できます。コンテナアプリごとに非常に多くのリビジョンを作成できるため、すべてのデプロイでこの概念を使用することはまったく問題ありません。

新しいバージョンを検証した後は、本番用のトラフィックとして、新しいgreen向けのトラフィックを徐々に増やしていくことができます。

While we are running a traffic split of 50/50 our users will be seeing both versions in production

シェルスクリプトをご覧になったことがあると思いますが、アクティブなリビジョンが2つ以上ないことや、バックエンドサービスにパブリックIPを使用していることなど、いくつかのポイントがあります。通常バックエンドサービスを外部公開する必要はありませんが、GitHub のパイプラインからVNET へのプライベートなアクセスはできないので、今回はデモをスムーズに行うためにこのような構成にしています。

また、Container Appsには、スケーリングルールを使ってアプリのレプリカを適切な数にする機能があります。この例では、各レプリカが1秒間に10件以上の同時リクエストを受けないようにします。またトラフィックが全く無い場合は、レプリカの数を0にしてコストを削減することもできますが、ダウンタイムなしにロールバックする機能に影響が出るため、今回は1つのレプリカにしかスケールダウンできないようにしています。

[{
  "name": "httpscalingrule",
  "type": "http",
  "metadata": {
     "concurrentRequests": "10"
  }
}]

フロントエンドとバックエンドのコンテナどちらも、プラットフォームの一部であるDaprサイドカーを利用しています。主な利点は、コードをAzure SDKに依存させることなく、Azure Redis・Application Insights・KeyVaultなどのAzureマネージドサービスを利用できることです。これにより、Azureを使わずにローカルでアプリケーションをテストしたり、他のクラウドやサービスでコンテナを実行したりすることが容易になります。フロントエンドやバックエンドとAzureプラットフォームの間のすべてのやり取りは、Daprサイドカーを介して行われます。私たちがすべきことは、Daprを有効にし、URLがDaprサイドカーのポート(今回は3500)を参照していることを確認することだけです。

Enabling Dapr brings a lot of benefits to our scenario

また、Daprサイドカーを使用して、フロントエンドとバックエンド間のサービス間通信を実装しています。両方のアプリには専用のdapr-app-idがあり、これを使ってフロントエンドコンテナからバックエンドAPIに次のURLを使って呼び出すことができます。

http://localhost:3500/v1.0/invoke/js-calc-backend/method/DoSomeThing

Daprサイドカーを有効にすることによるもう一つの素晴らしい効果は、各サービスとDaprが通信しているazureリソースとの間のすべてについて、分散型トレース情報を受け取ることができることにあります。

The application maps show the interactions between all dapr enabled services and resources

また、デプロイメントスクリプトの一番最後に、デプロイが成功するたびにリリースアノテーションを作成し、Application Insightsダッシュボードでパフォーマンス指標やエラーデータを簡単に比較できるようにしています。

The marker documents each release and allows us to compare performance and errors between releases

まとめ

このサンプルは、新しいAzure Container Appsが、比較的シンプルなコンセプトに基づいた非常に強力なプラットフォームであることを示していると思います。もしあなたが、ダウンタイムなしで継続的にアプリケーションをアップグレードする必要があるものの、Kubernetes上で同様のことを実現するためのインフラ管理や学習コストなどで躊躇していたケースでは、とてもエキサイティングな選択肢の1つになるかもしれません。

改善のためのフィードバックやレポへのプルリクエストをお待ちしています。

以上