1、概述
1.1 背景与目标
在当今快速迭代的软件开发周期中,“速度”和“稳定”是决定业务成败的两个关键因素。容器化技术和编排服务,极大地简化了应用的打包和运行,但“如何安全、快速、可靠地将新版本的应用代码,部署到生产环境”仍然是一个核心挑战。
许多团队仍然依赖手动或半自动化的脚本来执行部署。这些方法不仅耗时,而且极易出错:一个配置疏忽、一个错误的命令,都可能导致服务中断。这正是我们需要一个全自动 CI/CD (持续集成/持续交付) 流程的原因。
本文将重点介绍,如何使用 Amazon Web Services 托管的 CI/CD 服务套件(特别是 Amazon CodePipeline)与 Amazon Elastic Container Service(Amazon ECS)相结合,实现从代码提交到生产部署的全流程自动化,特别是实现蓝/绿部署(Blue/Green Deployment),最大限度地提高发布的可靠性。
1.2 为什么选择 Amazon CodePipeline + Amazon ECS?方案优势解读
将 Amazon CodePipeline 与 Amazon ECS 结合使用,不仅仅是“自动化”,更是构建了一个云原生的、弹性的、可观测的交付系统。
1.2.1 自动化与一致性(The “Why”)
消除人为错误:流程中的每一步(构建、测试、部署)都由机器严格执行预定义的规范。这消除了“我本地可以, 上生产就不行”的典型问题,以及手动操作带来的疏忽(例如,忘记更新某个环境变量)。
标准化发布流程:无论是开发环境、测试环境还是生产环境,都遵循同一套 CI/CD 流程。这保证了跨环境的一致性,使得在生产环境中发现的问题更容易在开发环境中复现。
1.2.2 快速迭代与价值交付(The Benefit)
缩短交付周期:开发者只需 git push,剩下的事情交给 Amazon CodePipeline。从代码提交到功能上线的时间,可以从几天缩短到几分钟。
聚焦核心业务:开发团队可以从繁琐的部署工作中解放出来,专注于编写能为客户创造价值的代码,而不是维护复杂的部署脚本。
1.2.3 可靠性:蓝/绿部署(The “How-To-Be-Safe”)
零停机部署:这是本方案的核心优势。通过与 Amazon CodeDeploy 集成,Amazon ECS 可以实现无缝的蓝/绿部署。Amazon CodeDeploy 会启动一个全新的、与当前生产环境(“蓝”环境)并行的“绿”环境,并将新版本的应用部署在“绿”环境中。
安全可控的流量切换:一旦“绿”环境准备就绪并通过健康检查,Amazon CodeDeploy 会通过修改 Application Load Balancer(ALB)的监听器规则,将生产流量(例如 10%、50% 乃至 100%)逐步切换到“绿”环境。
快速一键回滚:如果在流量切换过程中发现任何问题(例如,新版本的错误率飙升),您可以在几秒钟内将流量切回仍然在运行的“蓝”环境(旧版本),实现近乎即时的回滚,将故障影响降至最低。
1.2.4 深度集成与安全性
原生集成:Amazon CodePipeline 无缝集成了 Amazon CodeCommit(代码仓库)、Amazon CodeBuild(构建服务)、Amazon Elastic Container Registry(Amazon ECR)(容器镜像仓库)和 Amazon ECS(运行环境)。无需管理和集成多个第三方工具。
精细的权限管控:所有的操作都基于 Amazon Identity and Access Management(Amazon IAM)角色和策略。您可以精确控制 Amazon CodeBuild 有权推送到哪个 Amazon ECR 仓库,Amazon CodePipeline 有权部署到哪个 Amazon ECS 集群,确保了整个流程的安全性。
合规与审计:所有的 API 调用和操作都由 Amazon CloudTrail 记录,提供了完整的审计日志,满足合规性要求。
2、方案架构概览
目标架构:
1. Source(源):开发者将代码(包括 Dockerfile、yml 和 taskdef.json 模板)推送到 Amazon CodeCommit。
2. Trigger(触发):Amazon CodeCommit 的推送事件自动触发 Amazon CodePipeline。
3. Build(构建):
Amazon CodePipeline 启动 Amazon CodeBuild 项目。
Amazon CodeBuild 拉取源码,基于 Dockerfile 构建 Docker 镜像。
Amazon CodeBuild 将新镜像推送到 Amazon ECR。
Amazon CodeBuild 根据新镜像的 URI 更新 json 文件。
Amazon CodeBuild 将更新后的 json 和 appspec.yml 作为构建产物输出。
4. Deploy(部署):
Amazon CodePipeline 触发 Amazon CodeDeploy。
Amazon CodeDeploy 读取yml 和 new-taskdef.json。
Amazon CodeDeploy 在 Amazon ECS 集群上执行蓝/绿部署:
启动一个包含新任务定义的“绿”部署。
在 ALB 上配置测试监听器(可选),允许在切换前进行最后测试。
将生产流量从“蓝”环境(旧版本)切换到“绿”环境(新版本)。
(可选)在一段时间后自动终止“蓝”环境。
3、详细 Demo: 一步步搭建 Amazon ECS 蓝/绿部署管道
目标:搭建一个 CI/CD 管道,当 index.html 发生变化时,使用蓝/绿部署策略,自动将一个新的 Nginx 容器版本,部署到 Amazon ECS Fargate 集群。
前提条件:
一个 Amazon Web Services 中国区账户(如 cn-north-1 或 cn-northwest-1)。
具有管理员权限的 Amazon IAM 用户(或至少有 Amazon ECS、Amazon ECR、Amazon CodePipeline、Amazon CodeBuild、Amazon CodeDeploy、VPC、ALB、Amazon IAM 的完全访问权限)。
本地安装并配置 Git。
3.1 准备 Amazon ECS 运行环境(VPC、ALB、Amazon ECS 集群)
3.1.1 创建 VPC
为简单起见,您可以直接使用默认 VPC。
关键:确保您的 VPC 至少有两个位于不同可用区(AZ)的公有子网(如果使用 Amazon Fargate,并需要拉取公网镜像)和私有子网(推荐用于运行任务)。
本 Demo 为简单起见,我们假设使用公有子网,并为 Amazon Fargate 任务分配公有 IP。
3.1.2 创建ALB
导航到 Amazon Elastic Compute Cloud(Amazon EC2)控制台 > 负载均衡器 > 创建负载均衡器 > 选择 “Application Load Balancer”。
网络映射:选择您的 VPC 和至少两个可用区的公有子网。
安全组:创建一个新的安全组,允许来自 0.0.0.0/0 的 HTTP(80)流量。
监听器和路由:创建一个监听器,协议 HTTP,端口 80。
关键:为此监听器创建一个目标组(Target Group),命名为 tg-blue。
目标类型:IP (因为我们将使用 Amazon Fargate)。
协议 HTTP,端口 80。
健康检查:路径 /。
将监听器的默认操作设置为转发到 tg-blue。
创建第二个目标组:
我们还需要一个用于“绿”部署的目标组。
重复上述步骤,创建第二个目标组,命名为 tg-green。创建一个监听器,协议HTTP,端口 8080,关联到 tg-green。
创建 ALB。记下 ALB 的 DNS 名称。
3.2 创建 Amazon ECR 镜像仓库
导航到 Amazon ECR 控制台。
创建仓库。
记下仓库的 repositoryUri(例如:[account-id].dkr.ecr.cn-north-1.amazonaws.com.cn/<namespaces/名字>)。
3.3 (手动)部署“蓝”环境(v1)
在设置管道之前,我们必须先有一个正在运行的“v1”版本(“蓝”环境)。
3.3.1 创建初始 Task Definition (任务定义):
在 Amazon ECS 控制台 > 任务定义 > 创建新任务定义 > 选择 Amazon Fargate。
命名:my-app-task-def (Amazon CodeDeploy 会在此基础上创建新版本)。
任务角色:留空(或 ecsTaskExecutionRole)。
重要:CPU 架构设置成 arm64。
任务执行角色:选择(或创建)ecsTaskExecutionRole(允许 Amazon ECR 拉取镜像)。
任务大小:5 vCPU, 1 GB 内存。
容器定义:
点击 “添加容器”。
容器名称:my-app-container(**重要:**这个名字必须在后续步骤中保持一致)。
镜像:nginx:alpine(我们先用一个公开的镜像作为 v1,中国区可能有无法访问镜像库, 可以参考附加内容解决)。
端口映射:80 / tcp。
创建任务定义。它会被命名为 my-app-task-def:1。
3.3.2 创建 Amazon ECS 服务(service)
Amazon ECS 服务 > 创建集群 > my-app-cluster。
启动类型:Amazon Fargate。
任务定义:my-app-task-def,版本 1。
服务名称:my-app-service。
所需任务:1。
部署类型: 选择 “Blue/green deployment (powered by Amazon CodeDeploy)”。
Amazon CodeDeploy 配置:Amazon CodeDeploy 会自动为您创建 “Amazon CodeDeploy 应用程序” 和 “部署组”。您可以保留默认名称(例如 AppECS-my-app-cluster-my-app-service)。
Amazon CodeDeploy Role:
负载均衡:选择 “Application Load Balancer” > 选择您在步骤 1 中创建的 ALB。
容器: 选择 my-app-container:80。
生产监听器: 选择 HTTP:80。
目标组 1(Blue):选择 tg-blue。
目标组 2(Green):选择 tg-green。
网络配置:
选择您的 VPC 和公有子网。
安全组:选择您为 ALB 创建的安全组。
自动分配公有 IP:启用(ENABLED)。
创建服务。
几分钟后,服务应变为 ACTIVE。访问您的 ALB DNS,您应该能看到 Nginx 的欢迎页面。我们的“蓝”环境(v1)现在已上线。
3.4 准备代码仓库和 CI/CD 配置文件
3.4.1 创建 Amazon CodeCommit 仓库:
导航到 Amazon CodeCommit 控制台 > 创建存储库 > 命名为 my-ecs-app-repo。
在本地克隆该仓库:git clone [your-repo-url]
进入新目录:cd my-ecs-app-repo
3.4.2 在本地仓库中创建以下文件:
创建 index.html:(这是我们的 v2 版本)
cat << 'EOF' > index.html
<!DOCTYPE html>
<html>
<head><title>v2.0</title></head>
<body>
<h1>Hello World - v2.0</h1>
<p>Deployed by Amazon CodePipeline!</p>
</body>
</html>
EOF
创建 Dockerfile(适配中国区):(使用的是 Amazon ECR 中的模版,具体操作查看附录)
cat << 'EOF' > Dockerfile
# 使用我们 V1 的 Amazon ECR 镜像作为 V2 的基础
FROM <your account id>.dkr.ecr.cn-north-1.amazonaws.com.cn/my-hello-app:v1
# 将 V2 的 index.html 复制进去,覆盖 V1 的内容
COPY index.html /usr/share/nginx/html/
EOF
taskdef-template.json:(这是任务定义的模板,注意 image 字段的占位符)
cat << 'EOF' > taskdef-template.json
{
"family": "my-app-task-def",
"containerDefinitions": [
{
"name": "my-app-container",
"image": "REPLACE_IMAGE_URI",
"cpu": 512,
"memory": 1024,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true
}
],
"requiresCompatibilities": [
"FARGATE"
],
"networkMode": "awsvpc",
"cpu": "512",
"memory": "1024",
"executionRoleArn": "arn:aws-cn:iam::<your account ID>:role/ecsTaskExecutionRole",
"runtimePlatform": {
"operatingSystemFamily": "LINUX",
"cpuArchitecture": "ARM64"
}
}
EOF
滑动查看更多
appspec.yml:(这是告诉 Amazon CodeDeploy 如何部署的文件)
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
# <TASK_DEFINITION> 是 Amazon CodePipeline 自动填充的特殊占位符
TaskDefinition: "<TASK_DEFINITION>"
LoadBalancerInfo:
ContainerName: "my-app-container"
ContainerPort: 80
buildspec.yml:(这是告诉 Amazon CodeBuild 如何构建的文件)
version: 0.2
phases:
pre_build:
commands:
# $AWS_ACCOUNT_ID 和 $AWS_DEFAULT_REGION 是 Amazon CodeBuild 提供的环境变量
# $ECR_REPO_NAME 是我们在 Amazon CodeBuild 项目中定义的环境变量
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com.cn
- REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com.cn/$ECR_REPO_NAME
- IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7) # 使用 Git commit ID 作为标签
build:
commands:
- echo Building the Docker image...
- docker build -t $REPOSITORY_URI:$IMAGE_TAG .
post_build:
commands:
- echo Pushing the Docker image to ECR...
- docker push $REPOSITORY_URI:$IMAGE_TAG
- echo Preparing artifact files...
# 1. 创建新的 taskdef.json
- echo "Updating task definition..."
- sed -e "s|REPLACE_IMAGE_URI|$REPOSITORY_URI:$IMAGE_TAG|" taskdef-template.json > new-taskdef.json
# 2. 将 appspec.yml 和 new-taskdef.json 放入 artifacts
- echo "Build complete."
artifacts:
files:
- new-taskdef.json
- appspec.yml
3.4.3提交文件:
git add .
git commit -m "Initial commit v2 files"
git push origin master
3.5 创建 Amazon CodeBuild 项目
3.5.1 导航到 Amazon CodeBuild 控制台 > 创建构建项目。
3.5.2 项目名称:ecs-app-builder。
3.5.3 源:
源提供程序:Amazon CodeCommit。
存储库:my-ecs-app-repo。
分支:main。
3.5.4 环境:
镜像:托管镜像。
操作系统:Amazon Linux 2 (或 Ubuntu), ARM64。
运行时:Standard。
关键:勾选 “Privileged” (特权),因为需要构建 Docker 镜像。
3.5.5 服务角色:
选择 “新建服务角色”。
角色名称:codebuild-ecs-app-builder-role。
3.5.6 环境变量 (重要):
AWS_ACCOUNT_ID:您的账户 ID。
ECR_REPO_NAME:my-hello-app(步骤 2 中创建的 Amazon ECR 仓库名)。
3.5.7 BuildSpec:
选择 “使用 buildspec 文件”(默认)。
3.5.8 创建构建项目。
修改 Amazon CodeBuild 角色权限:
构建项目创建后,它会创建一个 Amazon IAM 角色。
导航到 Amazon IAM 控制台 > 角色 > 找到 codebuild-ecs-app-builder-role。
添加权限:附加策略 AmazonEC2ContainerRegistryPowerUser。这将允许 Amazon CodeBuild 登录 Amazon ECR,并推送镜像。
3.6 创建 Amazon CodePipeline
这是将所有组件串联起来的最后一步。
3.6.1 Amazon CodePipeline 控制台 > 创建流水线。
流水线名称:my-ecs-app-pipeline。
服务角色:新服务角色。
阶段 1:Source(源)
源提供程序:Amazon CodeCommit。
存储库名称:my-ecs-app-repo。
分支名称:main。
检测选项:Amazon CloudWatch Events (推荐)。
阶段 2:Build(构建)
构建提供程序:Amazon CodeBuild。
项目名称:ecs-app-builder (上一步创建的)。
构建类型:单个构建。
阶段 3:Deploy(部署)
部署提供程序:Amazon ECS(Blue/Green)。
区域:(您的区域)。
应用程序名称:选择由 Amazon ECS 自动创建的名称(例如 AppECS-my-app-cluster-my-app-service)。
部署组名称: 选择由 Amazon ECS 自动创建的名称(例如 DgpECS-my-app-cluster-my-app-service)。
Amazon ECS 任务定义:
输入构件:BuildArtifact(或您在 Build 阶段的输出构件名)。
文件名:new-taskdef.json(这必须匹配yml 中 artifacts 的定义)。
Amazon CodeDeploy AppSpec 文件:
输入构件:BuildArtifact。
文件名:appspec.yml。
查看并创建管道。
3.7 触发和验证部署 (v2)
创建管道后,它会自动从 Amazon CodeCommit 拉取最新代码(v2)并开始执行。
观察管道:
Source:变为绿色(成功)。
Build:变为蓝色(进行中),然后变为绿色。您可以点击 “详细信息” 查看 Amazon CodeBuild 日志,确认 docker build 和 docker push 成功。
Deploy:变为蓝色(进行中)。
切换到 Amazon CodeDeploy 控制台:在 Amazon CodeDeploy > 部署 > 找到正在进行的部署。
您将看到蓝/绿部署的三个步骤:
步骤 1:部署开始。 Amazon CodeDeploy 正在拉取新任务定义,并在 tg-green 上启动新的 Amazon Fargate 任务。
步骤 2:流量重新路由。 此时,Amazon CodeDeploy 会等待(默认 5 分钟)。
步骤 3:终止原始任务。
验证 v2:
在“步骤 2”期间,立即访问您的 ALB DNS。您应该仍然看到 Nginx 的默认页面(v1)。
等待 5 分钟(或您在 Amazon CodeDeploy 部署组中设置的等待时间)。
Amazon CodeDeploy 会自动将 ALB 监听器的规则从 tg-blue 切换到 tg-green。
再次刷新 ALB DNS 页面。 您现在应该能看到:
Hello World – v2.0 Deployed by Amazon CodePipeline!
部署成功!Amazon CodeDeploy 稍后会终止“蓝”环境(v1)的旧任务。
3.8 测试 v3(CI/CD 闭环)
3.8.1 在本地,修改 index.html 文件:
<h1>Hello World - v3.0 - Fully Automated!</h1>
3.8.2 提交并推送代码:
git add index.html
git commit -m "Deploy v3.0"
git push origin master
3.8.3 返回 Amazon CodePipeline 控制台。您会发现管道在几秒钟内被自动触发。
3.8.4 重复步骤 7 的验证过程。几分钟后,您的 ALB DNS 将自动显示 “v3.0″。
4、结语
在本文中,我们利用 Amazon CodePipeline、Amazon CodeBuild、Amazon CodeDeploy 和 Amazon ECS(Amazon Fargate),搭建了一条从代码提交到生产环境的全自动 CI/CD 管道。
这套方案的核心价值在于,通过自动化的蓝/绿部署,我们实现了零停机、低风险的安全发布。这不仅彻底告别了复杂易错的手动部署,还提供了近乎即时的回滚能力,确保了生产环境的稳定。
开发团队最终得以从繁琐的运维工作中解放出来,真正专注于业务创新和价值交付。这套 Amazon Web Services 原生集成的 CI/CD 流程,是实现快速、可靠迭代的坚实起点。
附加内容:
中国区无法访问nginx: alpine 解决方案:
Docker pull nginx:alpine
下载镜像到本地,然后上传到 Amazon ECR:
aws ecr get-login-password --region cn-north-1 | docker login --username AWS --password-stdin <your account id>.dkr.ecr.cn-north-1.amazonaws.com.cn
docker push <your account id>.dkr.ecr.cn-north-1.amazonaws.com.cn/my-hello-app:v1
配置修订版时使用:
<your account id>.dkr.ecr.cn-north-1.amazonaws.com.cn/my-hello-app:v1
注意:ecsTaskExecutionRole 需要有 AmazonECSTaskExecutionRolePolicy 权限。
*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国(宁夏)区域相关云服务由西云数据运营,具体信息以中国区域官网为准。
*本文作者
Yan Ze,西云数据技术客户经理
拥有 14+ 年 IT 行业经验,熟悉网络、数据库、云计算等领域,致力为制造/零售/网络等行业客户,提供企业级架构、运维治理与优化、技术支持等服务。
推荐阅读
无服务器架构的二次验证机制:保障企业云安全的最后一道防线
利用 Amazon CloudFront Edge Function 和 Amazon Lambda 对访问图片进行动态压缩
使用 pgpool-II 与 Amazon Aurora for PostgreSQL 构建高可用读写分离架构

