CodePipeline:ECR源+ECS部署配置

CodePipeline: ECR source + ECS deploy configuration

基本上,我需要使用 bitbucket 源代码配置 CI/CD 到 ECS 容器。我想使用 CodePipline 将新的 ECR 镜像部署到 ECS。

目前,AWS CodePipline 中没有指定 bitbucket 作为源的选项。但是,我已经设法使用 webhooks 配置 CodeBuild,因此它构建 docker 文件并在每次推送到发布分支时将其推送到 ECR。

我想将 ECR 配置为 CodePipline 中的 "source" 阶段,并将其部署到现有 ECS cluster/service,以便自动部署。

不幸的是,如果在部署步骤中出现以下错误,将导致基本配置和工件链接:

Invalid action configuration
The image definition file imageDetail.json contains invalid JSON format

虽然 "Amazon ECR" 阶段提供 imageDetail.json 作为输出工件,但似乎并不期望 "Amazon ECS" 部署提供程序。有什么合理的方法可以解决这个问题吗?

我知道,可以使用 bitbucket + API Gateway/Lambda + CodePipeline 配置 CI/CD,我还考虑使用 CodeCommit 而不是 bitbucket 作为源代码库 -尽管如此,还是希望有一个可能的优雅解决方案,可以直接将 bitbucket 与 CodePipeline 一起使用。

更新: 我最终得到了相当不错的配置,如 this 博文所述:总体思路是允许 CodeBuild 将源代码从 bitbucket 上传到 S3,然后使用以 S3 为源的 CodePipeline 来部署新的 docker 图像到 ECR 并在 ECS 集群中发布新的任务定义修订。 S3 仍在开销中,我正在为该任务寻找更优雅的解决方案。

我最近不得不解决一个类似的问题,我想使用 ECR 作为我的管道源并将图像部署到 ECS。我找到的解决方案是创建 3 个阶段:

  • 来源:ECR
  • 构建:将 ECR 工件转换为部署阶段可以理解的工件的自定义代码
  • 部署:到ECS

这是我用作构建阶段的 buildspec.yml 文件:

version: 0.2

phases:
  install:
    runtime-versions:
      python: 3.7
  build:
    commands:
      - PHP_REPOSITORY_URI=$(cat imageDetail.json | python -c "import sys, json; print(json.load(sys.stdin)['ImageURI'].split('@')[0])")
      - IMAGE_TAG=$(cat imageDetail.json | python -c "import sys, json; print(json.load(sys.stdin)['ImageTags'][0])")
      - echo $PHP_REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - echo Writing image definitions file...
      - printf '[{"name":"container","imageUri":"%s"}]' $PHP_REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
    files: imagedefinitions.json

基本上,它所做的是读取 imageDetail.json 文件并提取 ECR 存储库 URL 和 TAG,并输出为 ECS 部署阶段格式化的 json 文件,这只是一个没有定制的标准舞台。

我有一个类似的用例并遇到了同样的问题。解决我的用例的解决方案的答案有点长...

  1. 用例: 工具帐户具有执行 CodeBuild 的 CodePipeline 和 docker 推送到 QA 帐户 ECR。该图像将有 2 个标签 - "commit hash" 和 "latest"。 QA 帐户有一个管道,该管道在新图像可用时执行,并且该管道将新图像部署到 QA 帐户中的 Fargate 集群中。
  2. 部署平台: Amazon ECS 标准部署操作。
  3. 来源: ECR.
  4. 问题的原因: ECR 源的输出工件 正确地 仅包含有关的信息图像,不包括 ECS 标准部署所需的容器名称。
  5. 对 AWS 的建议: 鉴于使用 ECR 作为 ECS 源的流行场景,我们可以提出具有在输出工件中添加容器名称的能力(可选)的论点- 这将允许生成可接受作为 ECS 标准部署输入的输出工件。

根据此 official doco from AWS ECS 标准部署需要 - imagedefinitions.json 文件,其中提供容器名称和图像 URI。 它应该如下所示:

[
  {
    "name": "sample-app",
    "imageUri": "11111EXAMPLE.dkr.ecr.us-west-2.amazonaws.com/ecs-repo:latest"
  }
]

但 ECR 源会生成一个名为 imageDetail.json 的输出工件,示例如下。这与 ECS 标准部署又名 imagedefinitions.json 的预期输入格式不匹配 - 其中包括容器名称(名称)并且部署失败并显示类似 Deploy Failure:

的消息

{
    "ImageSizeInBytes": "44728918",
    "ImageDigest": "sha256:EXAMPLE11223344556677889900bfea42ea2d3b8a1ee8329ba7e68694950afd3",
    "Version": "1.0",
    "ImagePushedAt": "Mon Jan 21 20:04:00 UTC 2019",
    "RegistryId": "EXAMPLE12233",
    "RepositoryName": "dk-image-repo",
    "ImageURI": "ACCOUNTID.dkr.ecr.us-west-2.amazonaws.com/dk-image-repo@sha256:example3",
    "ImageTags": [
        "latest"
    ]
}

我解决这个问题的方法是:

  1. 在源代码阶段:除了 ECR 源代码之外,我还添加了一个来自 s3 的源代码,其中包含 imagedefinitions.json 压缩文件。

  2. 在 ECS 部署阶段操作中,我引用了 s3 源中的输出工件,其中包含 imagedefinitions.json,采用 ECS 标准部署可以理解的格式。

注意: imagedefinitions.json 在 s3 存储桶中是静态的,始终引用所述图像上的最新标签。因此,在 QA 图像定义桶中,我最终会得到一个图像定义 zip,即每个 Fargate 服务实例一个。

我在这里导出了我的管道以供一般参考:

{
"pipeline": {
    "roleArn": "arn:aws:iam::ACCOUNTID:role/service-role/AWSCodePipelineServiceRole-REGION-PIPELINENAME",
    "stages": [
        {
            "name": "Source",
            "actions": [
                {
                    "inputArtifacts": [],
                    "name": "Source",
                    "region": "REGION",
                    "actionTypeId": {
                        "category": "Source",
                        "owner": "AWS",
                        "version": "1",
                        "provider": "ECR"
                    },
                    "outputArtifacts": [
                        {
                            "name": "SourceArtifact"
                        }
                    ],
                    "configuration": {
                        "ImageTag": "latest",
                        "RepositoryName": "PIPELINENAME"
                    },
                    "runOrder": 1
                },
                {
                    "inputArtifacts": [],
                    "name": "sourceimagedeffile",
                    "region": "REGION",
                    "actionTypeId": {
                        "category": "Source",
                        "owner": "AWS",
                        "version": "1",
                        "provider": "S3"
                    },
                    "outputArtifacts": [
                        {
                            "name": "PIPELINENAME-imagedefjson"
                        }
                    ],
                    "configuration": {
                        "S3Bucket": "BUCKETNAME",
                        "PollForSourceChanges": "true",
                        "S3ObjectKey": "PIPELINENAME.zip"
                    },
                    "runOrder": 1
                }
            ]
        },
        {
            "name": "Deploy",
            "actions": [
                {
                    "inputArtifacts": [
                        {
                            "name": "PIPELINENAME-imagedefjson"
                        }
                    ],
                    "name": "Deploy",
                    "region": "REGION",
                    "actionTypeId": {
                        "category": "Deploy",
                        "owner": "AWS",
                        "version": "1",
                        "provider": "ECS"
                    },
                    "outputArtifacts": [],
                    "configuration": {
                        "ClusterName": "FARGATECLUSTERNAME",
                        "ServiceName": "PIPELINENAME",
                        "FileName": "imageDetail.json"
                    },
                    "runOrder": 1
                }
            ]
        }
    ],
    "artifactStore": {
        "type": "S3",
        "location": "codepipeline-REGION-555869339681"
    },
    "name": "PIPELINENAME"
}