ROMANCE DAWN for the new world

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

Azure Pipelines で Azure Web Apps for Containers のパイプラインを構築する

以前の記事で、Azure Pipelines を使って Azure Web Apps にデプロイする内容を記載しました。
gooner.hateblo.jp
今回は、Azure Web Apps for Containers 向けのパイプラインを構築します。Azure Web Apps との違いは少ないので、相違点のみを記載します。

パイプラインの全体設計

以前の記事と同様に、パイプラインは、自動デプロイされる開発環境向け(Commit Stage)と承認デプロイされる本番環境向け(Production Stage)を作ります。YAML を Build と Release を分けて、可変部をパラメータで切り替えできるテンプレートを作ることで再利用性を向上させます。

ビルド用パイプライン

ビルド用の build-pipelines.yml です。

parameters:
  imageName: ''
  dockerRegistryServiceConnection: ''
  imageRepository: ''
  dockerfilePath: ''
  tag: ''
  buildConfiguration: ''
  projects: ''
  testProjects: ''
  dotnetSdkVersion: ''

jobs:
- job: Build
  pool:
    vmImage: ${{parameters.imageName}}
  steps:
  - task: DotNetCoreCLI@2
    displayName: 'Install .NET Core SDK $(dotnetSdkVersion)'
    inputs:
      packageType: 'sdk'
      version: $(dotnetSdkVersion)
  - task: DotNetCoreCLI@2
    displayName: 'Build'
    inputs:
      command: 'build'
      projects: ${{parameters.projects}}
      arguments: '--configuration ${{parameters.buildConfiguration}}'
  - task: DotNetCoreCLI@2
    displayName: 'Test'
    inputs:
      command: 'test'
      projects: ${{parameters.testProjects}}
      arguments: '--configuration ${{parameters.buildConfiguration}}'
  - task: Docker@2
    displayName: 'Build and push an image to container registry'
    inputs:
      command: buildAndPush
      repository: ${{parameters.imageRepository}}
      dockerfile: ${{parameters.dockerfilePath}}
      containerRegistry: ${{parameters.dockerRegistryServiceConnection}}
      tags: |
        $(tag)

Azure Web Apps との違いは、Docker task の Docker@2 を使って、Docker build と Azure Container Registry への Push を行っている部分のみです。docs.microsoft.com

リリース用パイプライン

リリース用の release-pipelines.yml です。

  
parameters:
  imageName: ''
  azureSubscription: ''
  webAppsName: ''
  containerRegistry: ''
  imageRepository: ''
  tag: ''
  environment: ''
  webAppsSlotName: 'production'

jobs:
- deployment: Deploy_Azure_WebApps
  displayName: 'Release'
  pool:
    vmImage: ${{parameters.imageName}}
  environment: ${{parameters.environment}}
  strategy:
    runOnce:
      deploy:
        steps:
        - task: AzureWebAppContainer@1
          displayName: 'Deploy to Azure Web Apps for Container'
          inputs:
            azureSubscription: ${{parameters.azureSubscription}}
            appName: ${{parameters.webAppsName}}
            containers: ${{parameters.containerRegistry}}/${{parameters.imageRepository}}:${{parameters.tag}}
            slotName: ${{parameters.webAppsSlotName}}

Azure Web Apps と違って、Azure Web App for Container task の AzureWebAppContainer@1 を使っています。
docs.microsoft.com
スワップは、Azure Web Apps 向けのパイプラインをそのまま使えます。

開発環境向けパイプライン

開発環境向けの azure-pipelines.yml です。

trigger:
- main

variables:
- group: variable-group-commit
- name: imageName
  value: 'ubuntu-latest'
- name: azureSubscription
  value: 'AzureSponsorships'
- name: dockerRegistryServiceConnection
  value: 'ACR'
- name: imageRepository
  value: 'item-service'
- name: dockerfilePath
  value: '$(Build.SourcesDirectory)/item-service/Dockerfile'
- name: tag
  value: '$(Build.BuildId)'
- name: containerRegistry
  value: 'gooner.azurecr.io'
- name: environment
  value: 'Commit-Stage'
- name: buildConfiguration
  value: 'Release'
- name: projects
  value: '**/item-service.csproj'
- name: testProjects
  value: '**/item-service.Tests.csproj'
- name: dotnetSdkVersion
  value: '5.0.x'

stages:
- stage: Build
  jobs:
  - template: pipelines/build-pipelines.yml
    parameters:
      imageName: $(imageName)
      dockerRegistryServiceConnection: $(dockerRegistryServiceConnection)
      imageRepository: $(imageRepository)
      dockerfilePath: $(dockerfilePath)
      tag: $(tag)
      buildConfiguration: $(buildConfiguration)
      projects: $(projects)
      testProjects: $(testProjects)
      dotnetSdkVersion: $(dotnetSdkVersion)

- stage: Release
  dependsOn:
  - Build
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  jobs:
  - template: pipelines/release-pipelines.yml
    parameters:
      imageName: $(imageName)
      azureSubscription: $(azureSubscription)
      webAppsName: $(webAppsName)
      containerRegistry: $(containerRegistry)
      imageRepository: $(imageRepository)
      tag: $(tag)
      environment: $(environment)

Azure Web Apps との違いは、ACR のリポジトリ名や Dockerfile の場所を指定している部分です。Docker Image のタグは、パイプラインの BuildId を使っています。ACR の Service Connection は、あらかじめ作成しておきましょう。
本番環境向けパイプラインは、リリース前の承認と Deployment Slot を使ったスワップが追加されるくらいで、大きな違いはありません。

まとめ

リポジトリへのマージがトリガーとなり、ビルドとリリースのパイプラインが実行され、Azure Web Apps for Containers へのデプロイまでが自動で実行されます。

f:id:TonyTonyKun:20210228121514p:plain

こちらから、パイプライン YAML の全体を確認できます。
github.com

余談

公式ドキュメントで Azure Web Apps for Containers の CI/CD を調べると、ACR Webhook の記事が見つかります。
docs.microsoft.com
この Webhook は Docker Image のタグが固定なので、はっきり言って使えません。どうやらコンテナを再起動するだけの Webhook みたいです。
latest タグで固定した CI/CD はやりたくないので、結局 Azure Pipelines YAML を書くことになります。これは便利そうだと思って試したときの残念な感じが辛かった・・・

Azure App Service Migration Tool を試してみた

最近、ASP.NET アプリケーション向けの Azure App Service 移行ツールがあることを知ったので、簡単に使い方を調べてみました。

f:id:TonyTonyKun:20210117200823p:plain

Azure App Service Migration Tool

Azure App Service Migration Tool とは、App Service への移行に向けた Web アプリケーションの事前評価と移行作業を実施できるツールで、2つの機能を提供しています。

  • Web アプリケーションの URL へのスキャンによる評価
  • Migration Assistant による App Service への移行

appmigration.microsoft.com

移行する Web アプリケーションの準備

Azure App Service Migration Tool を試すことが目的なので、移行対象の Web アプリケーションは Visual Studio のプロジェクトテンプレートを使います。.NET Framework 4.7.2 の ASP.NET MVC を選択しました。

このツールを使うためには、Web アプリケーションを Windows Server の IIS でホストされた環境を用意する必要あるため、Azure Virtual Machines を作ることにしました。
ARM Template が用意されているので、これを使ってデプロイすれば、IIS や DNS name が設定された仮想マシンを一発で構築できます。
github.com
Virtual Machines を構築したら、Visual Studio から Web アプリケーションをデプロイします。じつは VS から VM にアプリ発行したのは初めてかも。

f:id:TonyTonyKun:20210117195215p:plain

以上で、事前準備は完了です。

Web アプリケーションの評価

Azure App Service Migration Tool に Azure VM の URL を入力して Assess ボタンを押すと、Web アプリケーションをスキャンして、移行に適しているかどうかを評価します。

f:id:TonyTonyKun:20210117195426p:plain

サーバーで実行されているフレームワーク、ホスティング情報、Web サーバーを含むテクノロジに関する情報が表示されます。
評価の結果、この Web アプリケーションが App Service と完全に互換性があることが分かります。

Web アプリケーションの移行

Azure App Service Migration Tool から Migration Assistant をダウンロードし、Web アプリケーションのサーバーにインストールします。
インストールした Migration Assistant を実行することで、移行に向けた詳細な評価を実施後、評価レポートにエラーがなければ、App Service にデプロイできます。

最初に、移行するWeb アプリケーションのサイトを選択します。

f:id:TonyTonyKun:20210117195718p:plain

次に、移行に向けた評価レポートが表示されます。評価結果を JSON ファイルに保存することもできます。

f:id:TonyTonyKun:20210117195733p:plain

Azure へのログインを求められるので、Device Code を使ってログインします。

f:id:TonyTonyKun:20210117204116p:plain

このツールを使って App Service に移行するためには、Azure Migrate のプロジェクトを作成する必要があります。
ツールのリンクから Azure Portal を開いて、Azure Migrate を作ります。

f:id:TonyTonyKun:20210117195747p:plain

Azure Migrate を作成できたら、ツールで選択して次へ進みます。

f:id:TonyTonyKun:20210117200438p:plain

移行先の App Service の情報を入力し、Migrate ボタンを押すとデプロイされます。

f:id:TonyTonyKun:20210117200621p:plain

f:id:TonyTonyKun:20210117195819p:plain

f:id:TonyTonyKun:20210117195831p:plain

移行が完了したので、App Service の URL にアクセスしてみます。

f:id:TonyTonyKun:20210117195906p:plain

まとめ

App Service Migration Tool を使って、ASP.NET アプリケーションを移行してみました。
実案件のアプリケーションでは、今回のようにスムーズには行かないと思いますが、移行に向けた互換性を事前に確認する手段としては有効かなと感じました。
このほかに、データベースの移行も検討しなてくはなりません。同様の移行ツールに Azure Database Migration Service もあるので、検討してみるとよいかもしれません。

Azure Synapse Analytics を使って売上分析プラットフォームを作ってみた

Azure Synapse Analytics は、データのインジェスト→分析→可視化のための開発やモニタリングを統合して管理できるデータ分析プラットフォームです。
先日少し試してみましたが、ポテンシャルの高さを感じる良いサービスです。
gooner.hateblo.jp
今回は、Azure Synapse Analytics を使って売上分析プラットフォームを作ってみます。

売上分析プラットフォームのアーキテクチャ

売上分析プラットフォームでは、各店舗の POS システムから売上データを収集し、全店舗のデータをまとめた横断的な売上分析を行う想定シナリオです。

  • 各店舗の売上データは、日次単位で XML 形式のファイルがアップロードされる
  • 各店舗の顧客マスターは、バラバラのローカルコードが使われているため、標準顧客マスターのコードをマッピングする
  • 全店舗の売上データを集めて、顧客ごとの売上状況を分析する

次のようなアーキテクチャで、売上分析プラットフォームを構築します。

f:id:TonyTonyKun:20210105171758p:plain

データの準備

売上データ

Blob Storage にアップロードする XML のデータは、mockaroo というサイトを使って、売上データっぽいスキーマを作ります。

f:id:TonyTonyKun:20210104172316p:plain

作成した XML は、以下のようなスキーマです。1つの XML ファイルに 1000 件の売上データを作ります。顧客マスターのローカルコード(customer_code)には、A0001/A0002/A0003 という3つのコードをランダムにセットしています。

<?xml version='1.0' encoding='UTF-8'?>
<dataset>
    <record>
        <id>1</id>
        <order_date>2021-01-01T00:00:00Z</order_date>
        <customer_code>A0001</customer_code>
        <product_code>KE-774</product_code>
        <unit_price>414.17</unit_price>
        <quantity>2</quantity>
    </record>
    <record>
        <id>2</id>
        <order_date>2021-01-01T00:00:00Z</order_date>
        <customer_code>A0002</customer_code>
        <product_code>MF-050</product_code>
        <unit_price>395.07</unit_price>
        <quantity>3</quantity>
    </record>
</dataset>

顧客マスターのマッピングデータ

SQL Database に、顧客マスターをマッピングするための3つのテーブルを作ります。

  • 顧客マスター(Customer)
  • 標準顧客マスター(StandardCustomer)
  • 顧客マッピング(CustomerMapping)

f:id:TonyTonyKun:20210104173454p:plain

顧客マスターには、店舗を判別する Store 列(e.g. store-a, store-b)を作り、Store + CustomerCode で UNIQUE Key としています。
売上データのローカルコードと突き合わせて、標準コードに変換するための View も作ります。

f:id:TonyTonyKun:20210104173629p:plain

リソースの作成

売上分析プラットフォームで使う Azure リソースを作成し、Azure Synapse Studio で作成する成果物を GitHub で管理できるように設定します。

  • Azure Synapse Analytics(ADLS / Dedicated SQL Pool)
  • Blob Storage
  • SQL Database(DbName:Sales)

docs.microsoft.com
Synapse Analytics で管理される ADLS と Dedicated SQL Pool は、デフォルトで Managed Service Identity(MSI)の認証が設定されているので、外部サービスに対しても追加で設定しておきます。
Azure Portal から Access control(IAM) で、Blob Storage に Storage Blob Data Contributor を設定します。MSI の名前は、ワークスペース名で登録されています。

f:id:TonyTonyKun:20210110132419p:plain

同様に SQL Database にも SQL DB Contributor を設定することに加えて、Active Directory admin で Azure AD の管理者を登録する必要があります。

f:id:TonyTonyKun:20210110133205p:plain

Ingest Layer

Ingest Layer は、収集したデータから DataLake を作る責務を持ちます。
Copy Data を使って、Blob Storage の XML を Parquet に変換して ADLS にコピーするパイプラインを作成します。

f:id:TonyTonyKun:20210106190053p:plain

詳細は、こちらの記事を参照してください。
gooner.hateblo.jp
gooner.hateblo.jp

Batch Layer

Batch Layer は、DataLake から DWH を作る責務を持ちます。
Mapping Data Flow を使って、ADLS の Parquet から Dedicated SQL Pool に売上データを取り込むパイプラインを作成します。
売上データを取り込む過程で、SQL Database の標準顧客マスターと突き合わせて、各店舗のローカルコードを標準コードに変換します。

f:id:TonyTonyKun:20210104162356p:plain

詳細は、こちらの記事を参照してください。
gooner.hateblo.jp

Serving Layer

Serving Layer は、DWH から Data Mart を作る責務を持ちます。
Mapping Data Flow を使って、Dedicated SQL Pool の売上データから SQL Database に顧客別売上データを取り込むパイプラインを作成します。

f:id:TonyTonyKun:20210105151148p:plain

詳細は、こちらの記事を参照してください。
gooner.hateblo.jp

まとめ

Azure Synapse Analytics を使って売上分析プラットフォームを作ってみました。
Spark Pool の Notebook でコードを書いてパイプラインを作るつもりでしたが、Dedicated SQL Pool 向けのコネクタが Append に対応していませんでした。
このレベルのシナリオであれば、Copy Data と Mapping Data Flow で構築できることが分かったので、これはこれでいいのですが、次回は Spark Pool を使ったシナリオを掘り下げていきたいです。

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