.NET CLIを使ってApp Runnerへデプロイする

2021.10.15

いわさです。

.NET CLIの.NETツールにAWS .NET Deployment Toolというものがあります。
先日このツールがアップデートされてApp Runnerへのデプロイが出来るようになりました。

サイレント実行オプションも用意されているので、CI/CDパイプラインからのデプロイも出来ます。
今回はローカルからデプロイし、作成されるリソースなどを観察してみました。

インストール

dotnet tool install -g aws.deploy.cliでインストールできます。
5秒くらいでした。

iwasa.takahito@hoge ~ % dotnet tool install -g aws.deploy.cli


.NET 6.0 へようこそ!
---------------------
SDK バージョン: 6.0.100-rc.1.21463.6

テレメトリ
---------
.NET ツールは、エクスペリエンスの向上のために利用状況データを収集します。データは Microsoft によって収集され、コミュニティと共有されます。テレメトリをオプトアウトするには、好みのシェルを使用して、DOTNET_CLI_TELEMETRY_OPTOUT 環境変数を '1' または 'true' に設定できます。

.NET CLI ツールのテレメトリの詳細をご覧ください: https://aka.ms/dotnet-cli-telemetry

----------------
ASP.NET Core の HTTPS 開発証明書をインストールしました。
証明書を信頼するには、'dotnet dev-certs https --trust' (Windows および macOS のみ) を実行します。
HTTPS の詳細については、https://aka.ms/dotnet-https を参照してください
----------------
最初のアプリを作成するには、https://aka.ms/dotnet-hello-world を参照してください
最新情報については、https://aka.ms/dotnet-whats-new を参照してください
ドキュメントを探索するには、https://aka.ms/dotnet-docs を参照してください
GitHub で問題の報告とソースの検索を行うには、https://github.com/dotnet/core を参照してください
'dotnet --help' を使用して使用可能なコマンドを確認するか、https://aka.ms/dotnet-cli にアクセスしてください
--------------------------------------------------------------------------------------
次のコマンドを使用してツールを呼び出せます。dotnet-aws
ツール 'aws.deploy.cli' (バージョン '0.26.4') が正常にインストールされました。
iwasa.takahito@hoge ~ %

デプロイ

サンプルプロジェクト作成

まずは、ASP.NET Core MVCのテンプレートからサンプルプロジェクトを作成して、ローカル実行してみます。

dotnet new mvcでサンプルプロジェクトの生成し、dotnet runで実行します。

iwasa.takahito@hoge sample-dotnettool % dotnet new mvc
テンプレート "ASP.NET Core Web App (Model-View-Controller)" が正常に作成されました。
このテンプレートには、Microsoft 以外のパーティのテクノロジが含まれています。詳しくは、https://aka.ms/aspnetcore/6.0-third-party-notices をご覧ください。

作成後の操作を処理しています...
/Users/iwasa.takahito/work/sample-dotnettool/sample-dotnettool.csproj で ' dotnet restore ' を実行しています...
  復元対象のプロジェクトを決定しています...
  /Users/iwasa.takahito/work/sample-dotnettool/sample-dotnettool.csproj を復元しました (154 ms)。
正常に復元されました。

iwasa.takahito@hoge sample-dotnettool % dotnet run
ビルドしています...
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7246
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5097
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/iwasa.takahito/work/sample-dotnettool

HTTPでリスニング中のhttp://localhost:5097にアクセスしてみましょう。

2つコマンドを実行するだけで、簡単にASP.NETのWebサイトを表示することが出来ました。

AWSへデプロイ

では、.NETツールを使って、AWSへデプロイしてみましょう。
認証情報はAWS CLIのプロファイルを利用するので、ローカル環境へのAWSプロファイルは設定済みであることが前提です。

プロジェクトファイルが存在するディレクトリで、dotnet aws deployを実行するとデプロイ出来ます。
プロファイルを指定する場合は--profileを付与します。
ただし、本日時点ではMFAが必要なIAMは利用出来ないようでした。

iwasa.takahito@hoge sample-dotnettool % dotnet aws deploy --profile hoge
AWS .NET deployment tool for deploying .NET Core applications to AWS.
Project Home: https://github.com/aws/aws-dotnet-deploy

Configuring AWS Credentials from Profile hoge.
Configuring AWS region using AWS SDK region search to ap-northeast-1.

Name the AWS stack to deploy your application to
(A stack is a collection of AWS resources that you can manage as a single unit.)
--------------------------------------------------------------------------------
Enter the name of the new stack (default sample-dotnettool): 

Recommended Deployment Option
-----------------------------
1: ASP.NET Core App to Amazon ECS using Fargate
This ASP.NET Core application will be deployed to Amazon Elastic Container Service (Amazon ECS) with compute power managed by AWS Fargate compute engine. If your project does not contain a Dockerfile, it will be automatically generated. Recommended if you want to deploy your application as a container image on Linux.

Additional Deployment Options
------------------------------
2: ASP.NET Core App to AWS App Runner
This ASP.NET Core application will be built as a container image and deployed to AWS App Runner. If your project does not contain a Dockerfile, it will be automatically generated. Recommended if you want to deploy your application as a container image on a fully managed environment.

Choose deployment option (recommended default: 1)
2

Current settings (select number to change its value)
----------------------------------------------------
1. Service Name: sample-dotnettool-service
2. Port: 80
3. Application IAM Role: *** Create new ***
4. CPU: 1024
5. Memory: 2048

Enter 'more' to display Advanced settings. 
Or press 'Enter' to deploy:

Generating Dockerfile...

Building the docker image...

途中対話が発生します。
名称やデプロイ先の環境情報を入力します。

CI/CDパイプラインの場合は--silentオプションを使うことで対話無しで実行出来ます。
その場合は事前に構成ファイルを用意し、--applyオプションで指定する必要があります。

sample-dotnettool: deploying...
sample-dotnettool: creating CloudFormation changeset...
  0/5 |18:27:24 | REVIEW_IN_PROGRESS   | AWS::CloudFormation::Stack | sample-dotnettool User Initiated
  0/5 |18:27:30 | CREATE_IN_PROGRESS   | AWS::CloudFormation::Stack | sample-dotnettool User Initiated
  0/5 |18:27:51 | CREATE_IN_PROGRESS   | AWS::CDK::Metadata      | CDKMetadata/Default (CDKMetadata) 
  0/5 |18:27:51 | CREATE_IN_PROGRESS   | AWS::IAM::Role          | Recipe/ServiceAccessRole (RecipeServiceAccessRole3815C527) 
  0/5 |18:27:52 | CREATE_IN_PROGRESS   | AWS::IAM::Role          | Recipe/TaskRole (RecipeTaskRoleA3C555E6) 
  0/5 |18:27:52 | CREATE_IN_PROGRESS   | AWS::IAM::Role          | Recipe/TaskRole (RecipeTaskRoleA3C555E6) Resource creation Initiated
  0/5 |18:27:52 | CREATE_IN_PROGRESS   | AWS::IAM::Role          | Recipe/ServiceAccessRole (RecipeServiceAccessRole3815C527) Resource creation Initiated
  0/5 |18:27:53 | CREATE_IN_PROGRESS   | AWS::CDK::Metadata      | CDKMetadata/Default (CDKMetadata) Resource creation Initiated
  1/5 |18:27:53 | CREATE_COMPLETE      | AWS::CDK::Metadata      | CDKMetadata/Default (CDKMetadata) 
  2/5 |18:28:15 | CREATE_COMPLETE      | AWS::IAM::Role          | Recipe/TaskRole (RecipeTaskRoleA3C555E6) 
  3/5 |18:28:16 | CREATE_COMPLETE      | AWS::IAM::Role          | Recipe/ServiceAccessRole (RecipeServiceAccessRole3815C527) 
  3/5 |18:28:18 | CREATE_IN_PROGRESS   | AWS::AppRunner::Service | Recipe/AppRunnerService (RecipeAppRunnerServiceDA9A12DF) 
  3/5 |18:28:23 | CREATE_IN_PROGRESS   | AWS::AppRunner::Service | Recipe/AppRunnerService (RecipeAppRunnerServiceDA9A12DF) Resource creation Initiated
3/5 Currently in progress: sample-dotnettool, RecipeAppRunnerServiceDA9A12DF
  4/5 |18:32:27 | CREATE_COMPLETE      | AWS::AppRunner::Service | Recipe/AppRunnerService (RecipeAppRunnerServiceDA9A12DF) 
  5/5 |18:32:31 | CREATE_COMPLETE      | AWS::CloudFormation::Stack | sample-dotnettool 

 ✅  sample-dotnettool

Outputs:
sample-dotnettool.RecipeEndpointURL20D2E3A7 = https://fqyshrnnps.ap-northeast-1.awsapprunner.com/
arn:aws:cloudformation:ap-northeast-1:123456789012:stack/sample-dotnettool/1b37fbb0-2d9a-11ec-b8f6-0a8d2531c4f5

Stack ARN:


Resources
---------
Application Endpoint:
    Id: arn:aws:apprunner:ap-northeast-1:123456789012:service/sample-dotnettool-service/90188c8815194d6796b8cbe12c4b3fb1
    Type: AWS::AppRunner::Service
    Endpoint: https://fqyshrnnps.ap-northeast-1.awsapprunner.com/
iwasa.takahito@hoge sample-dotnettool %

デプロイが完了すると、エンドポイントが表示されます。
アクセスしてみましょう。

デプロイされたアプリケーションを確認することが出来ました。

生成されるリソースなど

WebアプリケーションはDockerイメージとしてECRへプッシュされます。
そして、App Runnerを含めたスタックはCDKでデプロイされているようです。

また、.NET CLIのテンプレートから作成されたプロジェクトにはDockerfileはないのですが、dotnet aws deployコマンドを使うと自動生成されていました。

Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["sample-dotnettool.csproj", ""]
RUN dotnet restore "sample-dotnettool.csproj"
COPY . .
WORKDIR "/src/"
RUN dotnet build "sample-dotnettool.csproj" -c Release -o /app/build

FROM build AS publish
RUN apt-get update -yq \
    && apt-get install curl gnupg -yq \
    && curl -sL https://deb.nodesource.com/setup_10.x | bash \
    && apt-get install nodejs -yq
RUN dotnet publish "sample-dotnettool.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "sample-dotnettool.dll"]%

後始末

.NET CLIで作成したAWSスタックは、.NET CLIで削除も可能です。
dotnet aws delete-deploymentコマンドを使用します。

iwasa.takahito@hoge sample-dotnettool % dotnet aws list-deployments --profile hoge
AWS .NET deployment tool for deploying .NET Core applications to AWS.
Project Home: https://github.com/aws/aws-dotnet-deploy

Configuring AWS Credentials from Profile hoge.
Configuring AWS region using AWS SDK region search to ap-northeast-1.

Cloud Applications:
-------------------
sample-dotnettool
iwasa.takahito@hoge sample-dotnettool % dotnet aws delete-deployment sample-dotnettool --profile hoge
AWS .NET deployment tool for deploying .NET Core applications to AWS.
Project Home: https://github.com/aws/aws-dotnet-deploy

Configuring AWS Credentials from Profile hoge.
Configuring AWS region using AWS SDK region search to ap-northeast-1.
Are you sure you want to delete sample-dotnettool?: y/n (default n)
y
sample-dotnettool: deleting...
10/15/2021 19:16:08 | DELETE_IN_PROGRESS   | AWS::CDK::Metadata                       | CDKMetadata                             
10/15/2021 19:16:08 | DELETE_IN_PROGRESS   | AWS::AppRunner::Service                  | RecipeAppRunnerServiceDA9A12DF          
10/15/2021 19:16:09 | DELETE_COMPLETE      | AWS::CDK::Metadata                       | CDKMetadata                             
10/15/2021 19:16:21 | DELETE_COMPLETE      | AWS::AppRunner::Service                  | RecipeAppRunnerServiceDA9A12DF          
sample-dotnettool: deleted

エラー

コマンド実行時に失敗するパターンがいくつかありましたので掲載します。

プロジェクトファイルがない

Visual Studioから作成した場合はルートディレクトリにソリューションファイルがあり、その配下にプロジェクトディレクトリが存在する構成がある場合があります。
ソリューションディレクトリでコマンドを実行した場合は、プロジェクトファイルが見つからずにエラーとなります。

iwasa.takahito@hoge hoge-asp31 % dotnet aws deploy
AWS .NET deployment tool for deploying .NET Core applications to AWS.
Project Home: https://github.com/aws/aws-dotnet-deploy

Configuring AWS Credentials using AWS SDK credential search.
Configuring AWS region using AWS SDK region search to ap-northeast-1.

This directory contains a solution file, but the tool requires a project file. Please run the tool from the directory that contains a .csproj/.fsproj or provide a path to the .csproj/.fsproj via --project-path flag.
iwasa.takahito@hoge hoge-asp31 % ls
hoge-asp31    hoge-asp31.sln

dockerが起動されていない

App Runnerへデプロイする場合は、docker buildから開始されます。
dockerが起動されていない場合はエラーとなります。

iwasa.takahito@hoge hoge-asp31 % dotnet aws deploy --profile hoge
AWS .NET deployment tool for deploying .NET Core applications to AWS.
Project Home: https://github.com/aws/aws-dotnet-deploy

Configuring AWS Credentials from Profile hoge.
Configuring AWS region using AWS SDK region search to ap-northeast-1.

Name the AWS stack to deploy your application to
(A stack is a collection of AWS resources that you can manage as a single unit.)
--------------------------------------------------------------------------------
Enter the name of the new stack (default hoge-asp31): 

Recommended Deployment Option
-----------------------------
1: ASP.NET Core App to AWS Elastic Beanstalk on Linux
This ASP.NET Core application will be built and deployed to AWS Elastic Beanstalk on Linux. Recommended if you do not want to deploy your application as a container image.

Additional Deployment Options
------------------------------
2: ASP.NET Core App to Amazon ECS using Fargate
This ASP.NET Core application will be deployed to Amazon Elastic Container Service (Amazon ECS) with compute power managed by AWS Fargate compute engine. If your project does not contain a Dockerfile, it will be automatically generated. Recommended if you want to deploy your application as a container image on Linux.

3: ASP.NET Core App to AWS App Runner
This ASP.NET Core application will be built as a container image and deployed to AWS App Runner. If your project does not contain a Dockerfile, it will be automatically generated. Recommended if you want to deploy your application as a container image on a fully managed environment.

Choose deployment option (recommended default: 1)
3

The selected deployment option requires Docker, which was not detected. Please install and start the appropriate version of Docker for you OS: https://docs.docker.com/engine/install/

MFAが設定されたプロファイルを使用している

MFAが設定されたスイッチロールプロファイルを普段使うのですが、不明なエラーが発生しました。
いずれ修正されそうですが、AWS Toolkit for Visual Studioの場合はMFA対応まで少し時間がかかったような気がするので、気長に待ったほうが良いかもしれません。

iwasa.takahito@hoge sample-dotnettool % dotnet aws deploy
AWS .NET deployment tool for deploying .NET Core applications to AWS.
Project Home: https://github.com/aws/aws-dotnet-deploy

Configuring AWS Credentials using AWS SDK credential search.
Configuring AWS region using AWS SDK region search to ap-northeast-1.
Unhandled exception.  This is a bug.  Please copy the stack trace below and file a bug at https://github.com/aws/aws-dotnet-deploy. 
.NET Core Solution Stack doesn't exist.
   at AWS.Deploy.Orchestration.Data.AWSResourceQueryer.GetLatestElasticBeanstalkPlatformArn() in /codebuild/output/src954127964/src/codestar-connections.us-west-2.amazonaws.com/git-http/393431854674/us-west-2/eb780f07-2f46-42e0-9c15-df6f00fe3c1c/aws/aws-dotnet-deploy/src/AWS.Deploy.Orchestration/Data/AWSResourceQueryer.cs:line 342
   at AWS.Deploy.Orchestration.Orchestrator.GetReplacements() in /codebuild/output/src954127964/src/codestar-connections.us-west-2.amazonaws.com/git-http/393431854674/us-west-2/eb780f07-2f46-42e0-9c15-df6f00fe3c1c/aws/aws-dotnet-deploy/src/AWS.Deploy.Orchestration/Orchestrator.cs:line 124
   at AWS.Deploy.Orchestration.Orchestrator.GenerateDeploymentRecommendations() in /codebuild/output/src954127964/src/codestar-connections.us-west-2.amazonaws.com/git-http/393431854674/us-west-2/eb780f07-2f46-42e0-9c15-df6f00fe3c1c/aws/aws-dotnet-deploy/src/AWS.Deploy.Orchestration/Orchestrator.cs:line 88
   at AWS.Deploy.CLI.Commands.DeployCommand.GenerateDeploymentRecommendations(Orchestrator orchestrator, String deploymentProjectPath) in /codebuild/output/src954127964/src/codestar-connections.us-west-2.amazonaws.com/git-http/393431854674/us-west-2/eb780f07-2f46-42e0-9c15-df6f00fe3c1c/aws/aws-dotnet-deploy/src/AWS.Deploy.CLI/Commands/DeployCommand.cs:line 261
   at AWS.Deploy.CLI.Commands.DeployCommand.InitializeDeployment(String stackName, UserDeploymentSettings userDeploymentSettings, String deploymentProjectPath) in /codebuild/output/src954127964/src/codestar-connections.us-west-2.amazonaws.com/git-http/393431854674/us-west-2/eb780f07-2f46-42e0-9c15-df6f00fe3c1c/aws/aws-dotnet-deploy/src/AWS.Deploy.CLI/Commands/DeployCommand.cs:line 161
   at AWS.Deploy.CLI.Commands.DeployCommand.ExecuteAsync(String stackName, String deploymentProjectPath, UserDeploymentSettings userDeploymentSettings) in /codebuild/output/src954127964/src/codestar-connections.us-west-2.amazonaws.com/git-http/393431854674/us-west-2/eb780f07-2f46-42e0-9c15-df6f00fe3c1c/aws/aws-dotnet-deploy/src/AWS.Deploy.CLI/Commands/DeployCommand.cs:line 98
   at AWS.Deploy.CLI.Commands.CommandFactory.<BuildDeployCommand>b__37_0(DeployCommandHandlerInput input) in /codebuild/output/src954127964/src/codestar-connections.us-west-2.amazonaws.com/git-http/393431854674/us-west-2/eb780f07-2f46-42e0-9c15-df6f00fe3c1c/aws/aws-dotnet-deploy/src/AWS.Deploy.CLI/Commands/CommandFactory.cs:line 226

まとめ

Visual Studioなどに依存していないのでCLI単体でライトに使えるのは良いですね。
汎用的なコマンドでデプロイ実行出来るので、GitHub Actionsをはじめ様々なCI/CD環境に組み込むことが出来そうです。