And*_*nko 5 amazon-ecs amazon-ecr aws-fargate aws-cdk
首先,这是特定于 CDK 的 - 我知道围绕这个主题有很多问题/答案,但没有一个是特定于 CDK 的。
鉴于最佳实践规定 Fargate 部署不应在 ECR 存储库中查找“最新”标签,那么在使用 ECR 作为源时如何设置 CDK 管道呢?
在多存储库应用程序中,每个服务都位于其自己的存储库中(这些存储库将有自己的 CDK CodeBuild 部署来设置构建并推送到 ECR),基础设施 CDK 管道如何知道新镜像被推送到ECR 存储库并能够将该新映像部署到 ECS Fargate 服务吗?
由于任务定义必须指定图像标签(否则它将查找可能不存在的“最新”),这似乎是不可能的。
作为一个具体的例子,假设我有以下 2 个存储库:
cdk
定义 CodeBuild 项目的目录,因此当检测到推送到 master 时,将构建服务并将映像推送到 ECR预期的工作流程如下:
我知道目前 CodeDeploy 不支持 ECS 部署存在限制,因为 CFN 不支持 ECS 部署,但 CodePipelineActions 似乎能够设置一个 EcrSourceAction ,它可能能够实现此目的,但我一直无法得到这个工作至今。
这是否可能,或者我是否一直在等待 CFN 支持 ECS CodeDeploy 功能?
好吧,经过一番黑客攻击后,我成功做到了这一点。
首先,服务本身(在本例中是一个 Spring Boot 项目)cdk
在其根目录中获取一个目录。这基本上只是设置 CI/CD 管道的 CI 部分:
const appName: string = this.node.tryGetContext('app-name');
const ecrRepo = new ecr.Repository(this, `${appName}Repository`, {
repositoryName: appName,
imageScanOnPush: true,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
const bbSource = codebuild.Source.bitBucket({
// BitBucket account
owner: 'mycompany',
// Name of the repository this project belongs to
repo: 'reponame',
// Enable webhook
webhook: true,
// Configure so webhook only fires when the master branch has an update to any code other than this CDK project (e.g. Spring source only)
webhookFilters: [codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andBranchIs('master').andFilePathIsNot('./cdk/*')],
});
const buildSpec = {
version: '0.2',
phases: {
pre_build: {
// Get the git commit hash that triggered this build
commands: ['env', 'export TAG=${CODEBUILD_RESOLVED_SOURCE_VERSION}'],
},
build: {
commands: [
// Build Java project
'./mvnw clean install -Dskiptests',
// Log in to ECR repository that contains the Corretto image
'aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin 489478819445.dkr.ecr.us-west-2.amazonaws.com',
// Build docker images and tag them with the commit hash as well as 'latest'
'docker build -t $ECR_REPO_URI:$TAG -t $ECR_REPO_URI:latest .',
// Log in to our own ECR repository to push
'$(aws ecr get-login --no-include-email)',
// Push docker images to ECR repository defined above
'docker push $ECR_REPO_URI:$TAG',
'docker push $ECR_REPO_URI:latest',
],
},
post_build: {
commands: [
// Prepare the image definitions artifact file
'printf \'[{"name":"servicename","imageUri":"%s"}]\' $ECR_REPO_URI:$TAG > imagedefinitions.json',
'pwd; ls -al; cat imagedefinitions.json',
],
},
},
// Define the image definitions artifact - is required for deployments by other CDK projects
artifacts: {
files: ['imagedefinitions.json'],
},
};
const buildProject = new codebuild.Project(this, `${appName}BuildProject`, {
projectName: appName,
source: bbSource,
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3,
privileged: true,
environmentVariables: {
// Required for tagging/pushing image
ECR_REPO_URI: { value: ecrRepo.repositoryUri },
},
},
buildSpec: codebuild.BuildSpec.fromObject(buildSpec),
});
!!buildProject.role &&
buildProject.role.addToPrincipalPolicy(
new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['ecr:*'],
resources: ['*'],
}),
);
Run Code Online (Sandbox Code Playgroud)
设置完成后,必须手动构建 CodeBuild 项目一次,以便 ECR 存储库具有有效的“最新”映像(否则将无法正确创建 ECS 服务)。
现在,在单独的基础设施代码库中,您可以照常创建 ECS 集群和服务,并从查找中获取 ECR 存储库:
const repo = ecr.Repository.fromRepositoryName(this, 'SomeRepository', 'reponame'); // reponame here has to match what you defined in the bbSource previously
const cluster = new ecs.Cluster(this, `Cluster`, { vpc });
const service = new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'Service', {
cluster,
serviceName: 'servicename',
taskImageOptions: {
image: ecs.ContainerImage.fromEcrRepository(repo, 'latest'),
containerName: repo.repositoryName,
containerPort: 8080,
},
});
Run Code Online (Sandbox Code Playgroud)
最后创建一个侦听 ECR 事件的部署构造,手动将生成的 imageDetail.json 文件转换为有效的 imagedefinitions.json 文件,然后部署到现有服务。
const sourceOutput = new cp.Artifact();
const ecrAction = new cpa.EcrSourceAction({
actionName: 'ECR-action',
output: sourceOutput,
repository: repo, // this is the same repo from where the service was originally defined
});
const buildProject = new codebuild.Project(this, 'BuildProject', {
environment: {
buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_3,
privileged: true,
},
buildSpec: codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
build: {
commands: [
'cat imageDetail.json | jq "[. | {name: .RepositoryName, imageUri: .ImageURI}]" > imagedefinitions.json',
'cat imagedefinitions.json',
],
},
},
artifacts: {
files: ['imagedefinitions.json'],
},
}),
});
const convertOutput = new cp.Artifact();
const convertAction = new cpa.CodeBuildAction({
actionName: 'Convert-Action',
input: sourceOutput,
outputs: [convertOutput],
project: buildProject,
});
const deployAction = new cpa.EcsDeployAction({
actionName: 'Deploy-Action',
service: service.service,
input: convertOutput,
});
new cp.Pipeline(this, 'Pipeline', {
stages: [
{ stageName: 'Source', actions: [ecrAction] },
{ stageName: 'Convert', actions: [convertAction] },
{ stageName: 'Deploy', actions: [deployAction] },
],
});
Run Code Online (Sandbox Code Playgroud)
显然,一旦 CloudFormation 完全支持这一点,这并不像原本那样干净,但它工作得很好。
归档时间: |
|
查看次数: |
3886 次 |
最近记录: |