Webアプリケーションのデプロイを簡単にする新サービスAWS App Runnerがリリース!AWS Copilotでデプロイ&CI/CDパイプライン構築してみた

2021.05.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンサル部のとばち(@toda_kk)です。

Webアプリケーションのデプロイを劇的に簡単にする、AWS App Runnerというサービスがリリースされました!

すでに本ブログDevIOでも、いくつか記事が上がっています。

どういったサービスなのか、機能の紹介や基本的な使い方については上記をご参照いただきたいと思います。

App Runnerを利用する方法として、マネジメントコンソールやAWS CLIの他に、ECSデプロイツールの1つであるAWS Copilotがサポートされています。

今回は、Copilotを用いたApp Runnerのサービスデプロイについて、何ができるのか少し深掘りしてみます。

すでにワークショップやサンプルが提供されている

リリース当日ではありますが、すでにワークショップが提供されています。

また、それとは別にサンプルプロジェクトも提供されています。こちらは、AWS CLIを使ってApp Runnerを起動するようです。

自身で用意したDockerfileを使うこともできますが、せっかくなので今回は公式から提供されているサンプルイメージを利用してみます。

Copilotを使ってApp Runnerを実行してみる

Copilotの基本的な概念や使い方については、以前発表した内容をご参照いただけると嬉しいです。

今回は下記の名前でサービスをデプロイします。

  • Application名: sample
  • Environment名: test
  • Service名: hello-app-runner
$ copilot init
Welcome to the Copilot CLI! We're going to walk you through some questions
to help you get set up with a containerized application on AWS. An application is a collection of
containerized services that operate together.

Application name: sample
Workload type: Request-Driven Web Service
Service name: hello-app-runner
Image: public.ecr.aws/aws-containers/hello-app-runner:latest
Port: 80

✔ Deployed hello-app-runner, you can access it at https://itfbwnfpcv.ap-northeast-1.awsapprunner.com.

デプロイが完了すると、パブリックにアクセス可能なエンドポイントが表示されます。

作成されるリソース

App RunnerではVPCやサブネットといったネットワークのリソースは必要ありませんが、CopilotでEnvironmentを作成する際はVPCが作成されます。また、App Runnerは(少なくとも表面上は)ECSを使うわけではないので不要なのですが、同じようにCopilotの仕様としてECSクラスターが作成されます。

App Runnerを確認すると、{Application名}-{Environment名}-{Service名}という命名規則でサービスが起動していることがわかります。

App Runnerサービス詳細

一方、ECSを確認するとクラスターが作成されてはいるのですが、サービスやタスクは起動していません。

ECSクラスター

設定された値の確認

App Runnerでは、CPUやメモリのサイズを指定したり、Auto Scalingの同時実行数などを設定できます。

App Runnerサービスの設定

また、アプリケーションログが出力されており、自動的にCloudWatch Logsにも送信されるようになっています。

App Runnerログ

CloudFormationテンプレートの出力

Copilotを実行するとCloudFormationスタックが作成され、各リソースが作成されることになります。copilot svc packageコマンドを実行すると、適用されるCloudFormationテンプレートを確認できます。一部のみ抜粋して記載します。

Resources:
  AccessRole:
    Metadata:
      'aws:copilot:description': 'An IAM Role for App Runner to use on your behalf to pull your image from ECR'
    Type: AWS::IAM::Role
    Condition: NeedsAccessRole
    Properties:
      AssumeRolePolicyDocument:
        Version: '2008-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - build.apprunner.amazonaws.com
            Action: sts:AssumeRole

      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess

  InstanceRole:
    Metadata:
      'aws:copilot:description': 'An IAM role to control permissions for the containers in your service'
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: tasks.apprunner.amazonaws.com
            Action: 'sts:AssumeRole'

  Service:
    Metadata:
      'aws:copilot:description': 'An App Runner service to run and manage your containers'
    Type: AWS::AppRunner::Service
    Properties:
      ServiceName: !Sub '${AppName}-${EnvName}-${WorkloadName}'
      SourceConfiguration:
        AuthenticationConfiguration: !If
          - NeedsAccessRole
          - AccessRoleArn: !GetAtt AccessRole.Arn
          - !Ref AWS::NoValue
        AutoDeploymentsEnabled: false
        ImageRepository:
          ImageIdentifier: !Ref ContainerImage
          ImageRepositoryType: !Ref ImageRepositoryType
          ImageConfiguration:
            Port: !Ref ContainerPort
            RuntimeEnvironmentVariables:
              - Name: COPILOT_APPLICATION_NAME
                Value: !Ref AppName
              - Name: COPILOT_ENVIRONMENT_NAME
                Value: !Ref EnvName
              - Name: COPILOT_SERVICE_NAME
                Value: !Ref WorkloadName
      InstanceConfiguration:
        Cpu: !Ref InstanceCPU
        Memory: !Ref InstanceMemory
        InstanceRoleArn: !GetAtt InstanceRole.Arn
      Tags:
        - Key: copilot-application
          Value: !Ref AppName
        - Key: copilot-environment
          Value: !Ref EnvName
        - Key: copilot-service
          Value: !Ref WorkloadName

必要なIAMロールを作成しているのと、AWS::AppRunner::Serviceタイプのリソースを作成していることがわかります。これはそのまま、CloudFormationでApp Runnerを作成したいときに参考になりそうですね。

カスタムドメインの作成

App Runnerではパブリックアクセス可能なエンドポイントが自動的に用意されますが、カスタムドメインを設定することも可能です。

カスタムドメイン

表示されているCNAMEレコードをRoute 53に登録することで、カスタムドメインの設定が完了します。

ここで、「証明書の検証」となっているレコードは、ACM証明書をDNS検証で作成する際に必要となるCNAMEレコードと似たようなものになっています。このレコードを登録することで、証明書の検証が完了します。

ただし、App Runnerでカスタムドメインを作成した場合、ACM証明書が作成されるわけではありません。Application Load Balancerなどと同じように、少なくとも表面上は管理する必要がないリソースとして隠蔽されているものと思われます。

マニフェストファイルをいじってみる

Copilotの公式ドキュメントでは、すでにRequest-Driven Web Serviceのマニフェストについて説明が追加されています。

設定可能な項目を確認すると、他のServiceタイプと同じように、ヘルスチェック、CPUやメモリのスペック、出力するログレベルなどの指定ができるようになっています。

ただし、2021年5月時点ではAuto Scalingの設定はできないようで、デフォルトの設定のまま利用するしかなさそうです。

また、カスタムドメインの設定もできないようで、マネジメントコンソールやAWS CLIで設定する必要があります。

こういった他の項目についても、マニフェストファイルで設定変更できるようになると嬉しいですね。

CopilotでCI/CDパイプラインを構築してみる

Copilotでは、CI/CDパイプラインがPipelineとして抽象化された形で提供されています。このPipelineを利用してApp Runnerを自動的にデプロイできるようにしてみます。

CopilotのPipelineでは、ソースとしてGitリポジトリを指定する必要があります。そこで、既存のコンテナイメージを利用せずDockerfileを指定したRequest-Driven Web Serviceを作成します。

$ copilot init
Welcome to the Copilot CLI! We're going to walk you through some questions
to help you get set up with a containerized application on AWS. An application is a collection of
containerized services that operate together.

Use existing application: No
Application name: sample2
Workload type: Request-Driven Web Service
Service name: web
Dockerfile: ./Dockerfile
no EXPOSE statements in Dockerfile ./Dockerfile
Port: 80

次に、Pipelineを作成しソースとしてGitリポジトリを指定します。

$ copilot pipeline init
1st stage: test
Which repository would you like to use for your pipeline? https://github.com/xxxxx/test-app-runner
✔ Pipeline manifest file for test-app-runner already exists at copilot/pipeline.yml, skipping writing it.
The manifest contains configurations for your CodePipeline resources, such as your pipeline stages and build steps.
Update the file to add additional stages, change the branch to be tracked, or add test commands or manual approval actions.
✔ Buildspec file for pipeline already exists at copilot/buildspec.yml, skipping writing it.
The buildspec contains the commands to build and push your container images to your ECR repositories.
Update the build phase to unit test your services before pushing the images.

Required follow-up actions:
- Commit and push the buildspec.yml, pipeline.yml, and .workspace files of your copilot directory to your repository.
- Run `copilot pipeline update` to create your pipeline.

作成したPipelineを実リソース(CodePipeline)として反映させます。途中で表示されるURLにアクセスして、CodePipelineからGitリポジトリへの接続を許可する設定をします。

ちなみに余談ですが、copilot pipeline initを実行するとPipelineのマニフェストファイルが作成されます。ソースの変更をServiceに反映させるブランチ名を指定するのですが、デフォルトでは「main」となっています。プロジェクトによっては「master」をproduction相当のブランチとして利用しているケースもあるかと思いますので、その点はご注意ください。

$ copilot pipeline update
✔ Successfully added pipeline resources to your application: sample2

ACTION REQUIRED! Go to https://console.aws.amazon.com/codesuite/settings/connections to update the status of connection copilot-xxxxx-test-app-runner from PENDING to AVAILABLE.
✔ Successfully created a new pipeline: pipeline-sample2-test-app-runner

Recommended follow-up actions:
- Run `copilot pipeline status` to see the state of your pipeline.
- Run `copilot pipeline show` for info about your pipeline.

これで、GitHubリポジトリへのpushをトリガーとして、App Runnerでサービスが起動するようになります。

CodePipeline

App Runnerの自動デプロイ設定とは異なるので注意

App Runnerでサービスを作成する際、デプロイを手動でやるか自動でやるか設定する項目があります。自動デプロイを設定する場合、コンテナレジストリもしくはソースコードリポジトリを指定して変更をトリガーすることになります。

CopilotでCI/CDパイプラインを構築するとCodePipelineが作成されるわけですが、実はCopilot Serviceとして作成したApp Runnerサービスを確認すると手動デプロイの設定になっています。よく考えれば当たり前なのですが、App Runnerの自動デプロイの仕組みを使うわけではないようです。

App Runnerデプロイ設定

ECSと同じツールでApp Runnerを管理できる

すでにCopilotを使い慣れている方であれば、今までと同じような感覚でApp Runnerにサービスをデプロイできます。

ECSとApp Runnerの使い分けですが、Copilot公式ドキュメントによれば次の記載があります。

Request-Driven Web Service

An AWS App Runner service that autoscales your services based on incoming traffic and scales down to a baseline instance when there's no traffic. This option is more cost effective for HTTP services with sudden bursts in request volumes or low request volumes.

どうやら、App Runnerはある程度リクエスト頻度が安定しているサービスに適しているようです。App RunnerではAuto Scalingをサポートしていますが、リクエストの急増や急減に対して迅速にスケールできないのではないかと予測されます。

とはいえ、ネットワークやインスタンスといったインフラリソースの管理を考えずにサービスを起動できるというのは大きな魅力です。例えば、開発中のWebアプリケーションを試しに起動してみたり、各開発者メンバーが個人で使うような開発環境を自由に作ってもらう、といった使い方ができるのではないかと思います。

これからApp Runnerを使い始めようというときにデプロイツールとしてCopilotを選択しておくと、App RunnerとECSの間でサービスをスムーズに移行できそうです。

App Runnerの開発ロードマップ

他のAWSサービスと同じように、パブリックな開発ロードマップが用意されています。機能改善など要望があればIssueを上げてフィードバックしていきましょう!

関連するドキュメント

以上、コンサル部のとばち(@toda_kk)でした。