kakakakakku blog

Weekly Tech Blog: Keep on Learning!

AWS CDK の DockerImageAsset と cdk-ecr-deployment でビルドしたイメージを Amazon ECR に保存する

AWS CDK で「Dockerfile をビルドして Amazon ECR リポジトリにイメージを保存する」選択肢として DockerImageAssetcdklabs/cdk-ecr-deployment を紹介する❗️

aws_ecr_assets.DockerImageAsset を使う

まず,1番簡単なのは aws_ecr_assets.DockerImageAsset を使うという選択肢だと思う.

docs.aws.amazon.com

👾 sandbox-cdk-ecr-deployment-stack.ts (Step.1)

Dockerfile を準備して(今回は ../images/app ディレクトリに置いた)以下のような AWS CDK コードを実装すれば OK👌

import {
  Stack,
  StackProps,
  aws_ecr_assets,
} from 'aws-cdk-lib'
import { Construct } from 'constructs'
import path = require('path')

export class SandboxCdkEcrDeploymentStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props)

    new aws_ecr_assets.DockerImageAsset(this, 'SandboxAppImage', {
      directory: path.join(__dirname, '../images/app'),
    })
  }
}

デプロイすると自動的に cdk-hnb659fds-container-assets-${ACCOUNTID}-ap-northeast-1 という Amazon ECR リポジトリにイメージが保存される.hnb659fds は AWS CDK 側で付けられた名前でドキュメントこの値には意味がありません と書かれてておもしろい😃実装も少なく1番お手軽だと思う (๑•̀ㅂ•́)و✧

デメリットとしては任意の Amazon ECR リポジトリにイメージを保存できないというところだと思う.言い換えるとリポジトリ名・ライフサイクルポリシー・リポジトリタグなどは自由に設定できず,AWS CDK 側に管理されてしまうため微妙な使いづらさがある.ちなみにこれはドキュメントにも明記されていて「そういう意図である」と読み取れる📝

DockerImageAsset is designed for seamless build & consumption of image assets by CDK code deployed to multiple environments through the CDK CLI or through CI/CD workflows. To that end, the ECR repository behind this construct is controlled by the AWS CDK. The mechanics of where these images are published and how are intentionally kept as an implementation detail, and the construct does not support customizations such as specifying the ECR repository name or tags.

cdklabs/cdk-ecr-deployment と組み合わせて使う

そこで aws_ecr_assets.DockerImageAssetcdklabs/cdk-ecr-deployment を組み合わせて使うという選択肢もある💡cdklabs/cdk-ecr-deployment を使うと,指定した Docker Hub・Amazon ECR リポジトリなどのイメージを任意の Amazon ECR リポジトリにコピーできる.

github.com

👾 sandbox-cdk-ecr-deployment-stack.ts (Step.2)

例えば,以下のような AWS CDK コードを実装してデプロイすると,Docker Hub の amazonlinux:2023 イメージを自分で実装した Amazon ECR リポジトリ(今回は sandbox-repository)にコピーできる.

import {
  Stack,
  StackProps,
  aws_ecr,
} from 'aws-cdk-lib'
import * as ecrdeploy from 'cdk-ecr-deployment'
import { Construct } from 'constructs'

export class SandboxCdkEcrDeploymentStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props)

    const repository = new aws_ecr.Repository(this, 'SandboxRepository', {
      repositoryName: 'sandbox-repository',
    })

    new ecrdeploy.ECRDeployment(this, 'SandboxImageDeployment', {
      src: new ecrdeploy.DockerImageName('amazonlinux:2023'),
      dest: new ecrdeploy.DockerImageName(repository.repositoryUriForTag('2023')),
    })
  }
}

👾 sandbox-cdk-ecr-deployment-stack.ts (Step.3)

よって aws_ecr_assets.DockerImageAsset で Amazon ECR リポジトリ cdk-hnb659fds-container-assets-${ACCOUNTID}-ap-northeast-1 に保存されたイメージを自分で実装した Amazon ECR リポジトリにコピーすることで,Dockerfile をビルドして Amazon ECR リポジトリにイメージを保存する流れを AWS CDK で柔軟に実現できる👏

import {
  Stack,
  StackProps,
  aws_ecr,
  aws_ecr_assets,
} from 'aws-cdk-lib'
import * as ecrdeploy from 'cdk-ecr-deployment'
import { Construct } from 'constructs'
import path = require('path')

export class SandboxCdkEcrDeploymentStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props)

    const image = new aws_ecr_assets.DockerImageAsset(this, 'SandboxAppImage', {
      directory: path.join(__dirname, '../images/app'),
    })

    const repository = new aws_ecr.Repository(this, 'SandboxRepository', {
      repositoryName: 'sandbox-repository',
    })

    new ecrdeploy.ECRDeployment(this, 'SandboxImageDeployment', {
      src: new ecrdeploy.DockerImageName(image.imageUri),
      dest: new ecrdeploy.DockerImageName(repository.repositoryUriForTag('my-tag')),
    })
  }
}

cdk-ecr-deployment で事前にビルドされたイメージを使う

cdklabs/cdk-ecr-deployment は内部的にイメージをコピーするための AWS Lambda 関数もデプロイされている.AWS CDK をデプロイするときに環境変数として FORCE_PREBUILT_LAMBDA=1 を設定しておくと,AWS Lambda 関数を作るときに事前にビルドされたイメージを使うようになる.ビルド時間を短縮できるので使っても良いと思う👌実装を見たところ GitHub リポジトリのリリースアセットからダウンロードしているようだった.

github.com