AWS App2Container のパイプラインセットアップ機能で Azure DevOps がサポートされました

2022.07.04

いわさです。

AWS では、.NETやJavaのワークロードをコンテナ環境へ移行する支援ツールとして AWS App2Container というツールが提供されています。
この App2Container では、実行中ワークロードを解析しコンテナイメージを作成、デプロイすることが出来るのですが、追加の機能としてワークロードのデプロイパイプラインも構築することが出来ます。

これまでは CodeCommit や CodePipeline などをターゲットに作成することが出来ましたが、今回のアップデートで Azure DevOps がサポートされました。

対象OS

この記事では以下をベースに仮想マシン上で .NETワークロード をホスティングし、 App2Container でコンテナ化を実行しました。

ただし、最初 Amazon Linux 2 で実行したところ、パイプライン作成処理で失敗しました。

$ sudo app2container generate pipeline --application-id dotnet-generic-995b0ee7
Failed Generating pipeline resource templates for application dotnet-generic-995b0ee7

⚠️  Unsupported application OS, App2Container only supports windows server 2019, ubuntu 18 and ubuntu 20 with Azure DevOps
Error: Unsupported application OS, App2Container only supports windows server 2019, ubuntu 18 and ubuntu 20 with Azure DevOps

ドキュメントには明記されていませんが、上記メッセージに従うならば Azure DevOps の場合だと Windows Server 2019, Ubuntu 18, Ubuntu 20 が対象のようです。
そこで、この記事では前述の記事の手順をベースに Ubuntu 20 にて実行しています。

事前に、Azure DevOps や関連AWSサービスをセットアップしておく必要がある

AWS Toolkit for Azure DevOps をインストール

事前に、Azure DevOps へサインインした状態で Marketplace より AWS Toolkit for Azure DevOps をインストールしておきます。

プロジェクトを作成し認証情報登録

パイプラインを作成するプロジェクトを事前作成しておきます。 そして、パイプラインからAWSへデプロイ出来るように、Azure DevOps の Service connections へ IAM 情報を登録しておきます。

さらに、Azure DevOps へ App2Container でデプロイするためのPAT(Personal Access Tokens)を作成し、AWS Secrets Managerへ格納します。
App2ContainerがSecrets Managerから取得する仕様となっています。

App2Container実行

先程の記事をベースに Ubuntu 20 への .NET6、App2Container、Docker、AWS CLIなどをセットアップし、app2container initまで済ませておきます。
Ubuntu への .NET6 インストールは以下を参考にしています。

ubuntu@ip-172-31-12-21:~$ dotnet --version
6.0.301
ubuntu@ip-172-31-12-21:~$ sudo app2container --version
app2container version 1.17
ubuntu@ip-172-31-12-21:~$ docker --version
Docker version 20.10.12, build 20.10.12-0ubuntu2~20.04.1
ubuntu@ip-172-31-12-21:~/iwasatest$ aws --version
aws-cli/1.18.69 Python/3.8.10 Linux/5.13.0-1029-aws botocore/1.16.19

dotnet newでサンプルアプリを作成し、コンテナ化まで進め、デプロイ先はApp Runnerにしておきます。

ubuntu@ip-172-31-12-21:~$ dotnet new webapp --name iwasatest

Welcome to .NET 6.0!

:

ubuntu@ip-172-31-12-21:~/iwasatest$ dotnet publish -c Release --self-contained true -r linux-x64

:

ubuntu@ip-172-31-12-21:~/iwasatest$ dotnet /home/ubuntu/iwasatest/bin/Release/net6.0/linux-x64/iwasatest.dll &
[1] 5749
ubuntu@ip-172-31-12-21:~/iwasatest$ curl --insecure https://localhost:5001/
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />

:

生成されたCloudFormationテンプレートを先にデプロイしておきます。
これをすませておかないと、pipeline generateした際にエラーとなります。

ubuntu@ip-172-31-12-21:~/iwasatest$ sudo aws cloudformation deploy --template-file /root/app2container/dotnet-generic-28d92cb8/AppRunnerDeployment/apprunner.yml --capabilities CAPABILITY_IAM --stack-name a2c-dotnet-generic-28d92cb8-AppRunner

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - a2c-dotnet-generic-28d92cb8-AppRunner

生成されたpipeline.jsonの以下の部分を変更し、Azure DevOps構築用に設定します。

~/app2container/dotnet-generic-28d92cb8/pipeline.json

{
        "a2CTemplateVersion": "1.0",
        "sourceInfo": {
                "CodeCommit": {
                        "enabled": false,
                        "repositoryName": "a2c-dotnet-generic-28d92cb8-apprunner",
                        "branch": "master"
                },
                "ExistingGitRepo": {
                        "enabled": false,
                        "repositoryUri": "",
                        "branch": "",
                        "sshKeyArn": ""
                },
                "AzureRepo": {
                        "enabled": true,
                        "repositoryName": "a2c-dotnet-generic-28d92cb8",
                        "branch": "main"
                }
        },
        "imageInfo": {
                "image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/dotnet-generic-28d92cb8:latest"
        },
        "releaseInfo": {
                "AppRunner": {
                        "prod": {
                                "serviceName": "a2c-dotnet-generic-28d92cb8",
                                "enabled": true
                        }
                }
        },
        "resourceTags": [
                {
                        "key": "example-key",
                        "value": "example-value"
                }
        ],
        "pipelineInfo": {
                "CodePipeline": {
                        "enabled": false
                },
                "Jenkins": {
                        "enabled": false,
                        "jenkinsServerUrl": "",
                        "nodeLabels": [],
                        "apiTokenArn": "",
                        "repoSshCredentialId": "",
                        "awsCredentialId": ""
                },
                "AzureDevOps": {
                        "enabled": true,
                        "organizationName": "tak1wa",
                        "projectName": "hogeApp2Container",
                        "serviceCredName": "20220704app2container",
                        "agentPoolName": "Azure Pipelines",
                        "personalAccessTokenArn": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:hoge0704app2container-hXGEBw"
                }
        }
}

その後、generate pipelineします。

ubuntu@ip-172-31-12-21:~/iwasatest$ sudo app2container generate pipeline --application-id dotnet-generic-28d92cb8
✔ Discovered existing Azure repository
✔ Discovered existing Azure branch
✔ Generated pre-requisite installation scripts
✔ Generated pipeline definition files
✔ Committed artifacts to Microsoft Azure DevOps repository
👍 Pipeline resource template generation successful for application dotnet-generic-28d92cb8

💡 You're all set to use pipeline definition files in /root/app2container/dotnet-generic-28d92cb8/Artifacts/Pipeline/AzureDevOps to create your Azure DevOps pipeline.

Next Steps:
1. Edit the pipeline definition files as necessary.
2. Created a new Azure git repository at https://dev.azure.com/tak1wa/hogeApp2Container/_git/a2c-dotnet-generic-28d92cb8
3. Go to your Microsoft Azure DevOps web console https://dev.azure.com/tak1wa/hogeApp2Container/_build and click on "New Pipeline".
4. For Repositories select "Azure Repos Git" and select the repo with name a2c-dotnet-generic-28d92cb8
5. For "Configure your pipeline" step choose "Existing Azure Pipelines YAML file"
6. In the options for "branch" select main and for "path" select /pipeline.yaml
7. Click "continue" and then click "Run"

パイプライン作成

パイプライン作成が完了したら、Azure DevOps プロジェクトを見てみましょう。
実はまだパイプラインは作成されていません。

まず、リポジトリは新しく作成されます。

リポジトリにはDockerFileとパイプラインに必要な構成ファイルなどが格納されています。

そして、パイプラインは自分で作成する必要があり、まだ作成されていません(!!)
ただし、リポジトリに格納されている構成ファイルを選択するだけで良いです。

設定してRunを実行すると新しいイメージがプッシュされます。

生成時点でのパイプラインの主要ファイルをいくつか抜粋すると以下のようになっています。

pipeline.yaml

trigger:
  - main

pool:
  name: Azure Pipelines
  vmImage: ubuntu-18.04

stages:
  - template: pre-requisites.yaml
  - template: image-build.yaml

image-build.yaml

stages:
  - stage: Build
    jobs:
      - job: Build
        steps:
          - task: AWSShellScript@1
            displayName: 'Authenticate with ECR'
            inputs:
              awsCredentials: '20220704app2container'
              scriptType: 'inline'
              inlineScript: 'aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/dotnet-generic-28d92cb8:latest'

          - task: Docker@0
            displayName: 'Build an image'
            inputs:
              containerRegistryType: 'Container Registry'
              dockerFile: Dockerfile
              imageName: 'dotnet-generic-28d92cb8'
              additionalImageTags: 'latest'

          - task: AmazonWebServices.aws-vsts-tools.ECRPushImage.ECRPushImage@1
            displayName: 'Push an image to ECR'
            inputs:
              awsCredentials: '20220704app2container'
              regionName: 'ap-northeast-1'
              imageSource: imageid
              sourceImageId: 'dotnet-generic-28d92cb8'
              repositoryName: 'dotnet-generic-28d92cb8'
              pushTag: 'latest'
              autoCreateRepository: true

DockerFile

FROM 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/dotnet-generic-28d92cb8:latest

# Follow the below example to update files
# COPY ["generic_config_file", "/root/app2container/dotnet-generic-28d92cb8/Artifacts/generic_config_file"]

そうです。
パイプライン生成時点では、先程App2Containerでデプロイしたフェーズで作成されたECRイメージからイメージをビルドし直してプッシュしているだけです。

とはいえ、ここをベースにソースコードを加えたり、ミドルウェア設定を追加したり、パイプラインを育てていく開始地点とすることが出来るかなという感じはしますね。

さいごに

本日は App2Container で Azure DevOps パイプラインを作成する新機能を試してみました。

今回触ってわかったのが、App2ContainerのパイプラインはECS、EKS、App Runnerなどのデプロイオプションのひとつではなくて、追加の設定機能だということです。
既存の実行環境をコンテナワークロードへデプロイするだけでなく、開発・運用をどのように行っていくかまでサポートされる機能ということで、App2Container思ったより深い対応しているなと思いました。