kashinoki38 blog

something like tech blog

CodeCatalyst で App Runner にデプロイする

これは App Runner アドベントカレンダー の21日目です。

完全に年を跨いで最早あれなんですが、なんとか。。

あまり App Runner 本体のトピックではないが、CodeCatalyst で App Runner をにデプロイする記事を書こうと思う。

CodeCalyst で App Runner にデプロイする方法案

現状、App Runner のソールコードリポジトリプロバイダーは GitHub のみなので、CodeCatalys リポジトリ上からは直接デプロイできない。

GA時には、ここは App Runner のソースとしてサポートされることを期待。

https://docs.aws.amazon.com/ja_jp/apprunner/latest/dg/service-source-code.html#service-source-code.providers

よって自動デプロイを実現するには以下の2パターンが想定される

  • ECRを使う
    • ECR までは CodeCatalyst 側のワークフローで Push
    • その後 Workflow 内で App Runner のサービスを更新する
  • GitHub リポジトリとリンクさせる

今回は前者のECRを使う方法でやってみる。

CodeCatalyst準備

Project 作成

Repository 作成

  • link repository で GitHub とリンクさせることも可能

Dev Environment 作成

GitHub Codespaces のような機能。裏側で開発用サーバーとその上にコンテナが立ち上がり、そこに IDE から接続することにより、どこからでも同一環境で開発できる。

IAM 接続方法

Dev Environment から IAM 利用する方法。  

https://docs.aws.amazon.com/ja_jp/toolkit-for-vscode/latest/userguide/codecatalyst-devenvironment.html#codecatalyst-devenvironment-credentials

IAM の接続は Toolkit 経由で行うとあるがこれでできるのは VSCode Toolkit の機能のみであり、Terminal で使う場合は普通に Crendential から利用する必要がある模様。

IAM Role 連携できるようになることを期待する。

App Runner 用のソースコードの準備

Dev Environment として VSCode が使えるので、そこから App Runner のサンプルコードを CodeCatalyst のリポジトリに Push する。

https://github.com/aws-containers/hello-app-runner このリポジトリからCloneした内容を取り込み

$ cd ..
$ mkdir origin-repo
$ cd origin-repo/
$ git clone https://github.com/aws-containers/hello-app-runner.git
Cloning into 'hello-app-runner'...
remote: Enumerating objects: 115, done.
remote: Counting objects: 100% (33/33), done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 115 (delta 25), reused 20 (delta 20), pack-reused 82
Receiving objects: 100% (115/115), 446.01 KiB | 13.51 MiB/s, done.
Resolving deltas: 100% (46/46), done.
$ cp -r hello-app-runner/* ../hello-app-runner/

git push

$ git add .
$ git commit -m "initial commit"
[main f45a2b4] initial commit
 34 files changed, 5120 insertions(+), 19 deletions(-)
 create mode 100644 ATTRIBUTION.md
 create mode 100644 Dockerfile
 create mode 100644 LICENSE
 create mode 100644 Notice.txt
 create mode 100644 Pipfile
 create mode 100644 Pipfile.lock
 create mode 100755 app.py
 create mode 100644 apprunner.yaml
 create mode 100644 banner_base_dark.png
 create mode 100644 banner_base_light.png
 create mode 100644 cf.yaml
 create mode 100644 requirements.txt
 create mode 100644 static/apprunner_icon.svg
 create mode 100644 static/background-mobile.svg
 create mode 100644 static/background.bak.svg
 create mode 100644 static/background.svg
 create mode 100644 static/banner.svg
 create mode 100644 static/banner_sample.png
 create mode 100644 static/banner_satellite.svg
 create mode 100644 static/banner_stars.svg
 create mode 100644 static/docs_icon.svg
 create mode 100644 static/external_link_icon.svg
 create mode 100644 static/favicon.svg
 create mode 100644 static/fonts/open-sans-v18-latin-regular.eot
 create mode 100644 static/fonts/open-sans-v18-latin-regular.svg
 create mode 100644 static/fonts/open-sans-v18-latin-regular.ttf
 create mode 100644 static/fonts/open-sans-v18-latin-regular.woff
 create mode 100644 static/fonts/open-sans-v18-latin-regular.woff2
 create mode 100644 static/git_icon.svg
 create mode 100644 static/twitter_icon.svg
 create mode 100644 static/workshop_icon.svg
 create mode 100644 templates/index.html
 create mode 100644 templates/index.txt
$ git push origin main
Enumerating objects: 41, done.
Counting objects: 100% (41/41), done.
Delta compression using up to 2 threads
Compressing objects: 100% (39/39), done.
Writing objects: 100% (39/39), 434.75 KiB | 13.17 MiB/s, done.
Total 39 (delta 5), reused 0 (delta 0), pack-reused 0
remote: Validating objects: 100%
To https://git.us-west-2.codecatalyst.aws/v1/yasuhiro-horiuchi/hello-app-runner/hello-app-runner
   fa02be1..f45a2b4  main -> main

AWS リソースの準備

AWS リソースとして ECR と App Runner を用意する。  

ECR の作成 by awscli

先に ECR 作っとかないと CDK コケるので。

CodeCatalyst の Dev Environment から実行する。

$ aws ecr create-repository --repository-name app-runner-hello
$ aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin XXXXXXX.dkr.ecr.us-west-2.amazonaws.com
$ docker build -t app-runner-hello .
$ docker tag app-runner-hello:latest XXXXXXX.dkr.ecr.us-west-2.amazonaws.com/app-runner-hello:latest
$ docker push XXXXXXX.dkr.ecr.us-west-2.amazonaws.com/app-runner-hello:latest

App Runner の作成 by CDK

なんとなく、App Runner は CDK で作成する。  

App Runnerの作成はExperimentalなL2 Constructを使用する

https://constructs.dev/packages/@aws-cdk/aws-apprunner-alpha/v/2.59.0-alpha.0?

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as apprunner from '@aws-cdk/aws-apprunner-alpha';
import * as ecr from 'aws-cdk-lib/aws-ecr';


export class AppRunnerHelloStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const service = new apprunner.Service(this, 'Service', {
      source: apprunner.Source.fromEcr({
        imageConfiguration: { port: 80 },
        repository: ecr.Repository.fromRepositoryName(this, 'App-Runner-Hello', 'app-runner-hello'),
        tagOrDigest: 'latest',
      }),
      serviceName: 'App-Runner-Hello',
    });
  }
}
$ npm install
$ cdk deploy

デプロイ連携

CodeCatalyst Workflows により ECR に push して App Runner にデプロイさせる。  

GitHub Actions が Workflows では使えるので、この App Runner の GitHub Actions を CodeCatlyst Workflows に持ち込んでみる。

https://github.com/awslabs/amazon-app-runner-deploy/blob/main/README.md#image-based-service

修正点

Secretsパラメータの修正

Secrets の記法が GitHub Actions と CodeCatalys で異なる。

${{ secrets.AWS_REGION }}${Secrets.AWS_REGION}

CodeCatalyst の場合不要なステップ削除

actions/checkout@

actions/checkout@ ステップは、CodeCatalyst の場合 Inputs.Sources を指定するだけで良い

https://docs.aws.amazon.com/ja_jp/codecatalyst/latest/userguide/workflows-sources.html#workflows-sources-specify-action

Inputs:
      Sources:
        - WorkflowSource
aws-credentials

aws-credentials ステップは、CodeCatalyst だと CI/CD の Environments としてデプロイ先の AWSアカウントを定義することで代替する。  

Environment では AWSアカウントと、そこで利用する IAM Role を指定する。

environmentの作成

IAM の設定で、CodeCatalystPreviewDevelopmentAdministrator ロールに AWSAppRunnerFullAccess ポリシーを追加。

Workflow の Configuration で Environment, Account, IAM Role を紐づける。

以下が Workflow.yaml に追記される

Environment:
      Connections:
        - Role: CodeCatalystPreviewDevelopmentAdministrator-d6mk1k
          Name: "XXXXXXXXXXXX"
      Name: dev

${{ github.sha }}

イメージタグとして ${{ github.sha }} =コミットハッシュを利用している。

CodeCatalyst だと ${WorkflowSource.CommitId} で取得できるので、これを利用する。  

https://docs.aws.amazon.com/codecatalyst/latest/userguide/workflows-working-with-variables.html#workflows-working-with-variables-ex-refer-action

GitHub Actions のOutputパラメータ関連

CodeCatalyst では CodeCatalyst の Action 間のパラメータ受け渡しはできるが、同一 Actrion 内での Step 間の受け渡しができない。

以下の Output パラメータ利用しており、これを修正する。  

  • ${{ steps.login-ecr.outputs.registry }}
  • ${{ steps.build-image.outputs.image }}

https://docs.aws.amazon.com/codecatalyst/latest/userguide/integrations-github-action-working.html

regstry について

Secrets で Registry 名は渡すことにした。

image について

image 名は、$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG で、 $IMAGE_TAG${WorkflowSource.CommitId} なので、別に受け渡さなくて作れる。  

${Secrets.ECR_REGISTRY}/${Secrets.ECR_REPO}:${WorkflowSource.CommitId}
ちなみに1

別 Action の Output パラメータは${action-name.step-id_output-name} で参照できるが同一Actionだと、Circular Dependencyエラーが出る

The workflow cannot be constructed because a circular dependency was detected for the actions or action groups [GitHubActions_1]. Verify the "DependsOn" and "Inputs" properties to ensure they are properly configured.

Action 分けると環境もわかれるのか、 login-ecrbuild-image が別になると認証が引き継がれない。

ちなみに2

image 変数の引き継ぎは Action 分けてもなんとかなりそうなので、やってみたが、パラメータにシークレットが含まれると見做されて連携されない。

2023-01-14T03:27:12.4755637Z ##[warning]Skip output 'registry' since it may contain secret.
2023-01-14T03:27:12.4762083Z ##[warning]Skip output 'IMAGE' since it may contain secret.

image名にはリージョンが含まれるが、リージョンを Secret として定義しているためだった。

※シークレットを含めるとパラメータ連携しないのは、GitHub Actions の仕様。

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjobs_idoutputs:~:text=Job outputs containing expressions are evaluated on the runner at the end of each job. Outputs containing secrets are redacted on the runner and not sent to GitHub Actions.

Job outputs containing expressions are evaluated on the runner at the end of each job. Outputs containing secrets are redacted on the runner and not sent to GitHub Actions.

Secrets の追加

ということで、以下が必要な Secret となった。

  • Secrets.ECR_REPO
  • Secrets.ECR_REGISTRY
  • Secrets.ROLE_ARN
    • CDKで自動生成される App Runner のロールを指定
  • Secrets.AWS_REGION
  • Secrets.APP_RUNNER_SERIVCE

Workflow これで動いた

.codecatalyst/workflows/Workflow.yaml

Name: Workflow_5012
SchemaVersion: "1.0"

# Optional - Set automatic triggers.
Triggers:
  - Type: Push
    Branches:
      - main

# Required - Define action configurations.
Actions:
  GitHubActions_1:
    Identifier: aws/github-actions-runner@v1
    Inputs:
      Sources:
        - WorkflowSource
    Configuration:
      Steps:
        - name: Login to Amazon ECR
          id: login-ecr
          uses: aws-actions/amazon-ecr-login@v1
        - name: Build, tag, and push image to Amazon ECR
          id: build-image
          env:
            ECR_REGISTRY: ${Secrets.ECR_REGISTRY}
            ECR_REPOSITORY: ${Secrets.ECR_REPO}
            IMAGE_TAG: ${WorkflowSource.CommitId}
          run: >-
            docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .

            docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        - name: Deploy to App Runner Image
          id: deploy-apprunner
          uses: awslabs/amazon-app-runner-deploy@main
          with:
            service: ${Secrets.APP_RUNNER_SERIVCE}
            image: '${Secrets.ECR_REGISTRY}/${Secrets.ECR_REPO}:${WorkflowSource.CommitId}'
            access-role-arn: ${Secrets.ROLE_ARN}
            region: ${Secrets.AWS_REGION}
            cpu: 1
            memory: 2
            # wait-for-service-stability-seconds: 1200
    Compute:
      Type: EC2
    Environment:
      Connections:
        - Role: CodeCatalystPreviewDevelopmentAdministrator-d6mk1k
          Name: "XXXXXXXX"
      Name: dev

デプロイの確認

少しコードを修正して、CodeCatalyst リポジトリにプッシュすると、無事に App Runner に反映された。

完全に CodeCatalyst の検証記事みたいになってしまったが、デプロイ先が App Runner ということで許してください。

App Runner 用の Action の追加や、App Runner のソースリポジトリとしてのサポート等、AWSのサービスならではのネイティブ連携をGA時には期待する。

ちなみに

Dev Env は Amazon Linux2 が動く

$ cat /etc/os-release 
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"
  • awscli, cdk, docker, python(v3.9.14), pip (v3.9)使えた

デフォルトのdevfile.yml(/projects/devfile.yaml )

schemaVersion: 2.0.0
metadata:
  name: aws-universal
  version: 1.0.1
  displayName: AWS Universal
  description: Stack with AWS Universal Tooling
  tags: ["aws", "al2"]
  projectType: "aws"
components:
  - name: aws-runtime
    container:
      image: public.ecr.aws/aws-mde/universal-image:latest
      mountSources: true
      volumeMounts:
        - name: docker-store
          path: /var/lib/docker
  - name: docker-store
    volume:
      size: 16Gi

VSCode Toolkit との連携いい感じ

存在しない Secret を読むとログなしでワークフロー失敗する

デプロイのタイミングが被ると App Runner で OPERATION_IN_PROGRESS でワークフロー失敗する

2023-01-14T08:41:29.0014539Z ##[error]Service cannot be updated in the current state: OPERATION_IN_PROGRESS.

ワークフローを手動実行すると直前の Commit の ID が CommitId として定義される