AWS CDK で ECS をデプロイ (Immutable Tag 運用)¶
やり方の概要¶
- アクティブなタグは Parameter Store に保存
- repository スタックで ECR リポジトリと初期イメージを生成してpush、Parameter を生成する
- Parameter の初期値はビルドしたダミーイメージ (initial) とする。
- ecr スタックで Parameter Store からタグを読んでデプロイ
Repository スタック¶
lib/repository/initial 配下に、初期イメージ生成用の Dockerfile を作成します。
FROM amd64/node:18-slim
RUN npm install -g install http-server
EXPOSE 80
ENTRYPOINT ["http-server", "-p", "80"]
lib/repository/stack.ts
import * as cdk from "aws-cdk-lib";
import * as ecr from "aws-cdk-lib/aws-ecr";
import * as ecr_deployment from "cdk-ecr-deployment";
import * as ecr_assets from "aws-cdk-lib/aws-ecr-assets";
import * as path from "path";
import {Construct} from "constructs";
const INITIAL_IMAGE_TAG = "initial"; // 初期値: 変更しないこと!
export class RepositoryStack extends cdk.Stack {
public repository: ecr.IRepository;
public imageTagParameterName: string;
constructor(scope: Construct, id: string, props: cdk.StackProps) {
super(scope, id, props);
const repositoryName = "foo"; // リポジトリ名
const imageTagParameterName = `/foo/imageTag`; // イメージタグ保存先 Parameter
// 初期イメージ作成 (タグ: initial)
const initialImage = new ecr_assets.DockerImageAsset(this, "InitialImageAssets", {
directory: path.resolve(__dirname, INITIAL_IMAGE_TAG),
});
// ECR Repository
const repository = new ecr.Repository(this, "Repository", {
repositoryName: repositoryName,
});
new ecr_deployment.ECRDeployment(this, "WebInitialImage", {
src: new ecr_deployment.DockerImageName(initialImage.imageUri),
dest: new ecr_deployment.DockerImageName(repository.repositoryUriForTag(INITIAL_IMAGE_TAG)),
});
イメージタグは Parameter Store に保存する
new ssm.StringParameter(this, "ImageTag", {
parameterName: imageTagParameterName,
stringValue: INITIAL_IMAGE_TAG, // 初期値
});
this.repository = repository;
this.imageTagParameterName = imageTagParameterName;
}
}
ECR スタック¶
lib/ecs/stack.ts
import * as cdk from "aws-cdk-lib";
import * as ecs from "aws-cdk-lib/aws-ecs";
import * as ecs_patterns from "aws-cdk-lib/aws-ecs-patterns";
import * as ssm from "aws-cdk-lib/aws-ssm";
import {Construct} from "constructs";
interface EcsStackProps extends cdk.StackProps {
readonly repository: ecr.IRepository;
readonly imageTagParameterName: string;
}
export class EcsStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: EcsStackProps) {
super(scope, id, props);
// Parameter
const imageTagParameter = ssm.StringParameter.fromStringParameterName(this, "ImageTag", props.imageTagParameterName);
// ECS
const service = new ecs_patterns.ApplicationLoadBalancedFargateService(this, "Service", {
taskImageOptions: {
image: ecs.ContainerImage.fromEcrRepository(props.webRepository, imageTagParameter.stringValue),
...
},
...
});
}
}
スタックの作成¶
const repositoryStack = new repositoryStack(app, "repository", {
...
});
const ecsStack = new ecsStack(app, "ecs", {
...,
repository: repositoryStack.repository,
imageTagParameterName: repositoryStack.imageTagParameterName,
});
ecsStack.addDependency(repositoryStack);