ROMANCE DAWN for the new world

Microsoft Azure を中心とした技術情報を書いています。

Azure Container Apps の Revision Label を使って Staging の URL を固定する

Azure Container Apps の Revision は、Web Apps の Deployment Slot とは異なり、新しい Docker Image をデプロイするたびに Revision が追加されます。
Revision Label を使うことで、Staging の URL を固定できるかどうか試してみました。
docs.microsoft.com

Container Apps をデプロイする

前回の記事と同様の手順で、Bicep で Container Apps をデプロイします。
gooner.hateblo.jp

Staging へのデプロイを想定し、新しいバージョンをデプロイしました。dapr-frontend--v2 という Revision が追加されました。

新しい Revision には、Container Apps とは別の Revison URL が割り当てられるので、リリース前のテストができます。

この Revision 毎に割り当てられる URL を固定させるため、Revison Label に staging をセットします。

Revision URL とは別に、Label URL が割り当てられます。


Revision を Swap する

Revision の traffic パーセンテージを Swap します。

$ az containerapp ingress traffic set -n dapr-frontend -g <ResourceGroup Name> \
     --revision-weight dapr-frontend--v1=0 latest=100

Swap が完了したら、Revison Label を dapr-frontend--v2 から dapr-frontend--v1 に付け替えます。

最後に、旧バージョンの Revision をシャットダウンします。

$ az containerapp revision deactivate -n dapr-frontend -g <ResourceGroup Name> --revision dapr-frontend--v1

あとは、この繰り返しで。

まとめ

Azure Container Apps の Revision Label を使って Staging の URL を固定してみました。
ひと手間かかりますが、Web Apps の Deployment Slot に近い運用を実現できそうです。

本当は、Azure CLI で Revision Label を追加削除したかったのですが、挙動が怪しかったので Azure Portal を使いました。
具体的には、traffic パーセンテージが 0% の Revison に対して、Revison Label を追加できません。

$ az containerapp revision label add -n dapr-frontend -g <ResourceGroup Name> --label staging --revision dapr-frontend--v2
Please specify a revision name with an associated traffic weight.

GitHub の Issues に報告したところ、次のリリースで修正されるようです。
github.com

// 追記:2022/06/15
Azure CLI の Ver.0.3.6 で修正が完了しました。--no-prompt オプションを指定することで、Revision Label を削除追加せずとも、強制的に付け替えできます。

// Revision Label(staging) を新バージョンにセット
az containerapp revision label add -n dapr-frontend -g <ResourceGroup Name> --label staging --revision dapr-frontend--v2

// スワップ
az containerapp ingress traffic set -n dapr-frontend -g <ResourceGroup Name> --revision-weight dapr-frontend--v1=0 latest=100

// Revision Label(staging) を付け替え
az containerapp revision label add -n dapr-frontend -g <ResourceGroup Name> --label staging --revision dapr-frontend--v1 --no-prompt

Azure Container Apps で Blue-Green Deployments を試してみた

Microsoft Build 2022 で Azure Container Apps が GA されました。東日本リージョンでも使えるようになりましたので、Blue-Green Deployments を試してみました。

Azure Container Apps とは

Azure Container Apps は、複数のコンテナアプリで構成されるシステム向けのサービスです。これまでは Web Apps for Containers か AKS の2択でしたが、新たに Container Apps が追加されたことになります。
docs.microsoft.com

Container Apps は Kubernetes を基盤に構成されています。下記のような Environment / Container App / Revision / Replica の構成要素を理解しておけば OK です。

Microsoft Docs から引用

Container Apps Environment を作成する

Azure Portal では App Service Plan にあたる Environment だけを作成できないため、Bicep を使って Environment を作成します。
environment.bicep では、Environment、LogAnalytics、Application Insights のリソースを定義します。

param environmentName string
param logAnalyticsWorkspaceName string = 'logs-${environmentName}'
param appInsightsName string = 'appins-${environmentName}'
param location string = resourceGroup().location

resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2020-08-01' = {
  name: logAnalyticsWorkspaceName
  location: location
  properties: any({
    retentionInDays: 30
    features: {
      searchVersion: 1
      legacy: 0
      enableLogAccessUsingOnlyResourcePermissions: true
    }
    sku: {
      name: 'PerGB2018'
    }
  })
}

resource appInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: appInsightsName
  location: location
  kind: 'web'
  properties: { 
    Application_Type: 'web'
    WorkspaceResourceId:logAnalyticsWorkspace.id
  }
}

resource environment 'Microsoft.App/managedEnvironments@2022-03-01' = {
  name: environmentName
  location: location
  properties: {
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: logAnalyticsWorkspace.properties.customerId
        sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey
      }
    }
    daprAIInstrumentationKey: appInsights.properties.InstrumentationKey
    zoneRedundant: false
  }
}

output location string = location
output environmentId string = environment.id

main.bicep では、Resource Group 名にプレフィックスをつけて Environment 名を定義します。

param environmentName string = 'env-${resourceGroup().name}'
param location string = resourceGroup().location

module environment 'environment.bicep' = {
  name: 'container-app-environment'
  params: {
    environmentName: environmentName
    location: location
  }
}

Azure CLI を使って、デプロイします。

$ az group create -n <ResourceGroup Name> -l japaneast
$ az deployment group create -f ./deploy/env/main.bicep -g <ResourceGroup Name>

作られたリソースは、こんな感じです。


Container Apps をデプロイする

Container Apps についても、Azure Portal では細かい構成を指定できないので、Bicep を使って作成します。
あらかじめ ASP.NET Core Web アプリケーションの Docker Image を作っておいたので、apps.bicep でデプロイします。

param containerAppName string
param location string = resourceGroup().location
param environmentId string
param containerImage string
param revisionSuffix string
param oldRevisionSuffix string
param isExternalIngress bool

@allowed([
  'multiple'
  'single'
])
param revisionMode string = 'single'

resource containerApp 'Microsoft.App/containerApps@2022-03-01' = {
  name: containerAppName
  location: location
  properties: {
    managedEnvironmentId: environmentId
    configuration: {
      activeRevisionsMode: revisionMode
      ingress: {
        external: isExternalIngress
        targetPort: 80
        transport: 'auto'
        allowInsecure: false
        traffic: ((contains(revisionSuffix, oldRevisionSuffix)) ? [
          {
            weight: 100
            latestRevision: true
          }
        ] : [
          {
            weight: 0
            latestRevision: true
          }
          {
            weight: 100
            revisionName: '${containerAppName}--${oldRevisionSuffix}'
          }
        ])
      }
      dapr:{
        enabled:false
      }
    }
    template: {
      revisionSuffix: revisionSuffix
      containers: [
        {
          image: containerImage
          name: containerAppName
          resources: {
            cpu: '0.25'
            memory: '0.5Gi'
          }
        }
      ]
      scale: {
        minReplicas: 1
        maxReplicas: 10
        rules: [
          {
            name: 'http-scaling-rule'
            http: {
              metadata: {
                concurrentRequests: '10'
              }
            }
          }
        ]
      }
    }
  }
}

output fqdn string = containerApp.properties.configuration.ingress.fqdn

main.bicep では、Blue-Green Deployments を行うため、revisions-mode に multiple を指定します。
新旧 RevisionSuffix に v1 を指定することで、デプロイしたアプリケーションの traffic を 100% にします。

param environmentName string = 'env-${resourceGroup().name}'
param containerAppName string = 'dapr-frontend'
param location string = resourceGroup().location
param containerImage string = 'thara0402/dapr-frontend:0.1.0'
param revisionSuffix string = 'v1'
param oldRevisionSuffix string = 'v1'
param isExternalIngress bool = true
param revisionMode string = 'multiple'

resource environment 'Microsoft.App/managedEnvironments@2022-03-01' existing = {
  name: environmentName
}

module apps 'apps.bicep' = {
  name: 'container-apps'
  params: {
    containerAppName: containerAppName
    location: location
    environmentId: environment.id
    containerImage: containerImage
    revisionSuffix: revisionSuffix
    oldRevisionSuffix: oldRevisionSuffix
    revisionMode: revisionMode
    isExternalIngress: isExternalIngress
  }
}

Azure CLI を使って、デプロイします。

$ az deployment group create -f ./deploy/app/main.bicep -g <ResourceGroup Name>

デプロイすると、dapr-frontend--v1 という Revision が作成されました。

dapr-frontend.bravewave-d4e6d1bd.japaneast.azurecontainerapps.io という FQDN が自動生成されました。
ASP.NET Core Web アプリケーションがブラウザで表示されることを確認できます。


Blue-Green Deployments を行う

Staging へのデプロイを想定し、新しいバージョンをデプロイします。
main.bicep では、containerImage のタグを 0.2.0、revisionSuffix のバージョンを v2 に更新することで、先ほどデプロイした Revision( dapr-frontend--v1)へのトラフィックを 100% のまま、新しい Revision をデプロイします。

param containerImage string = 'thara0402/dapr-frontend:0.2.0'
param revisionSuffix string = 'v2'

デプロイすると、dapr-frontend--v2 という Revision が追加されました。

traffic が「0」の新しい Revision には、ユーザーに公開される FQDN とは異なる FQDN が割り当てられるので、リリース前のテストができます。
dapr-frontend--v2.bravewave-d4e6d1bd.japaneast.azurecontainerapps.io/ という Revision が含まれた FQDN が自動生成されました。

リリース前のテストが完了したので、Azure CLI を使って Swap します。
拡張モジュールをインストールし、名前空間を登録します。Preview のときは Microsoft.Web 名前空間でしたが、Microsoft.App 名前空間に移行されています。

$ az extension add --name containerapp --upgrade
$ az provider register --namespace Microsoft.App
$ az containerapp ingress traffic set -n dapr-frontend -g <ResourceGroup Name> \
     --revision-weight dapr-frontend--v1=0 latest=100

traffic のパーセンテージが入れ替わったことを確認できます。

ユーザーに公開される FQDN にアクセスすると、V2 に更新された ASP.NET Core Web アプリケーションが表示されます。

最後に、旧バージョンの Revision をシャットダウンします。アクティブのままだと、課金対象となってしまいます。

$ az containerapp revision deactivate -n dapr-frontend -g <ResourceGroup Name> --revision dapr-frontend--v1

新バージョンの Revision のみになったことを確認できます。


まとめ

Azure Container Apps で Blue-Green Deployments を試してみました。トラフィック制御の比率を変えることで AB テストやカナリアリリースもできます。
Envoy によるトラフィック制御以外にも、KEDA によるスケーリングや Dapr によるサイドカーなどの面白い機能があるので、引き続き試していきたいと思います。

今回のソースコードは、こちらのリポジトリで公開しています。
github.com

Microsoft Defender for Storage でストレージアカウントを保護する

Microsoft Defender for Storage は、ストレージアカウントに対する脅威を検出するサービスです。
ストレージで永続化するデータのセキュリティ対策として、Defender for Storage は使ったことがなかったので試してみました。
docs.microsoft.com

Defender for Storage とは

Defender for Storage は、Microsoft Defender for Cloud(旧 Azure Security Center)のうち、リソースに対する脅威を検出するカテゴリーに分類されます。

Storage 以外にも、次のようなリソース向けのサービスが提供されています。

  • Defender for Servers
  • Defender for App Service
  • Defender for SQL
  • Defender for Containers
  • Defender for Key Vault
  • Defender for Resource Manager
  • Defender for DNS

Defender for Storage で検知できる脅威には、ストレージへの異常なアクセスやマルウェアファイルがアップロードなどがあります。
検知できるストレージの種類は、次の3つです。

  • Blob Storage
  • Azure Data Lake Storage Gen2
  • Azure Files

検知できるアラートの一覧については、公式ドキュメントを参照してください。
docs.microsoft.com

Defender for Storage を有効化する

Defender for Cloud の environment settings から、基本的にはサブスクリプション単位で有効化することが推奨されています。

Defender で保護できるリソース一覧が表示されるので、Storage を有効化します。

Storage の Security でも、Defender が有効化されたことを確認できます。


Defender for Storage のアラートを検証する

実際にテスト用のアラートを発生させて、Defender for Storage を検証してみます。

今回は、EICAR テストファイル(アンチウイルスソフトウェアのテスト用ファイル)を Blob Storage にアップロードすることで発生させるアラートを試してみます。

しばらく待っていると、Storage の Security にセキュリティのアラートが表示されます。

Defender for Cloud の Secirity Alert にも、アラートの詳細が表示されます。

検知されたマルウェアが含まれている疑いがあるファイルは、Logic Apps を利用して削除するワークフローを組むこともできます。
techcommunity.microsoft.com

まとめ

Defender for Storage を有効化して、テスト用のアラートを発生させてみました。
ストレージで永続化するデータを外部の脅威から防御するとして、アプリケーションの要件によっては導入を検討してみてもよさそうだと思いました。

Defender for App Service を試してみた記事は、こちらを参照してください。
gooner.hateblo.jp