简介
在上一篇文章中,我们介绍了CodeCommit和CodeBuild的一般用法。
本文中我们先建一个ECR Repository,然后利用CloudWatch rule把CodeCommit和CodeBuild连接起来。
实现当有代码push到CodeCommit后,自动启动CodeBuild,拉取代码,生成镜像,并推入ECR。
接下来,我们会利用之前讲到的Lamdba函数,把CodeBuild和CodeDeploy连接起来,形成一个完整的CICD流水线,如下图所示。
图52
目录
•环境(配置)
•ECR 简介•CloudWatch 简介•实战步骤1.新建 ECR Repository2.修改CodeBuil项目•增加使用ECR权限•增加环境变量•修改BuildSpec方式及内容3.设置CloudWatch•创建Rule•测试Push代码后自动运行CodeBuild4.利用Lambda函数连接CodeBuild和CodeDeploy•创建Lambda函数•创建Rule•创建新Fargate Task版本•修改CodeDeploy中用的appspec.json•上传appspec.json到S35.测试CICD工具链•总结•引申•后记
环境(配置)
- AWS 中国或 Global 帐号,可在官网申请,一年内使用指定资源免费
- AWS cli,Win10 + terminal
- Git
ECR 简介
Amazon ECR(Amazon Elastic Container Registry)是AWS提供的镜像注册服务,具有安全,可扩展,高可靠等特点。
我们可以在ECR中保存管理Docker镜像,OCI(Open Container Initiative)镜像或者和OCI兼容的制品。
我们通过IAM控制访问ECR的权限。
下面测试中生成的镜像,会保存在ECR Repository中,最后Fargate Task中定义中的镜像会从ECR Repo中拉取。
CloudWatch 简介
CloudWatch 可以实时监控AWS服务,还可以搜集信息,日志,设置告警等。
本文在CloudWatch中设置Rule,用来触发CodeBuild服务和Lambda函数。
实战步骤
1. 新建 ECR Repository
在AWS中控台,选择“ECR”,点击进入“Amazon Container Services”界面,点击左边“Repositories”后,点击“Create repository”
图3
添加Repo名称“tstest”,点击“Create repository”
图4
创建完成
图5
2. 修改CodeBuild项目
我们利用上一篇文章建好的CodeBuild项目“tstestCodeCommit”,在项目Role中增加使用ECR的权限。
增加使用ECR权限
在AWS中控台,选择“CodeBuild”,展开“Build”,点击“Build project”,然后点击项目“tstestCodeCommit”,点击“Build detail”后,向下滚到“Environment”部分,点击Service role,新打开IAM role页面
图7
我们给Role增加一个inline policy,点击“Add inline policy”
图8
选择JSON,粘贴下列使用ECR的权限,注意把“XXXX”换成你的Account
图9
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:CompleteLayerUpload",
"ecr:GetAuthorizationToken",
"ecr:InitiateLayerUpload",
"ecr:PutImage",
"ecr:UploadLayerPart"
],
"Resource": "*"
}
]
}
添加policy名称后,点击“Create policy”
图10
增加权限完成
图11
增加环境变量
在Build项目“tstestCodeCommit”的“Build details”的“Environment”部分,点击“Edit”
图12
展开“Additional configuration”
图13
在“Enviroment variables Name”部分,增加下列四个环境变量,然后点击“Update enviroment”,这些环境变量会在BuildSpec中使用。
图14
添加完成
图15
修改Buildspec方式及内容
上次我们是在界面上直接粘贴Buildspec的内容,这次我们把Buildspec的内容保存成yaml文件,和Dockerfile等一起放在CodeCommit中。
在Build项目“tstestCodeCommit”的“Build details”的“Buildspec”部分,点击“Edit”
图17
选择“Use a buildspec file”,点击“Update buildspec”
图18说明:
这样Codebuild会在和源代码同一层的目录中查找buildspec.yml
更新完成
图19
我们利用上篇文章中在本地clone的代码仓库 “tstestrep”。在“tstestrep”增加下面几个文件。(HelloWorld.java是上次测试的文件,可以删除)
tstestrep/
├── Dockerfile
├── HelloWorld.java
├── buildspec.yml
├── entrypoint.sh
└── test.html
- buildspec.yml
version: 0.2
phases:
pre_build:
commands:
- 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
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
- docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com.cn/$IMAGE_REPO_NAME:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker image...
- docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com.cn/$IMAGE_REPO_NAME:$IMAGE_TAG
说明:
- pre_build 通过“aws ecr get-login-password...” 登录ECR
- build 利用Dockerfile生成镜像并打Tag
- post_build 把生成的镜像推入ECR “tstest”
注意:CodeBuild在中国区上面的后缀是amazonaws.com.cn,在Global区是amazonaws.com
- Dockerfile
FROM httpd:2.4
COPY ./test.html/ /usr/local/apache2/htdocs/test.html
COPY entrypoint.sh /entrypoint.sh
RUN chmod 755 /entrypoint.sh
WORKDIR /usr/local/apache2
EXPOSE 80
ENTRYPOINT ["/entrypoint.sh"]
说明:
这里把我们的网页“test.html”复制到httpd的部署目录,生成新的镜像
- entrypoint.sh
#!/bin/sh
#when using apachectl it take environment varianles in /usr/local/apache2/bin/envvars but when using httpd start directly it will not use env in envvars
HOST=`hostname`
echo "export HOSTNAME=$HOST" >>/usr/local/apache2/bin/envvars
/usr/local/apache2/bin/apachectl -k start
tail -f /dev/null
说明:
entrypoint.sh是容器启动时运行的脚本,最后一行tail命令是前台命令,运行后不会退出,保持容器一直运行的状态。
注意:docker容器运行的最后一条命令必须是前台命令,即运行后不会自己退出的命令,否则容器运行完所有命令后会自动退出
- test.html
<p>this is codebuild test for realCrapForAWS</p>
说明:
测试页面,来代替实际环境中编译好的文件
3. 设置CloudWatch
创建Rule
在AWS中控台,先择CloudWatch,在左边点击“Rules”,然后点击“Create rule”
图24
进行以下配置
- 选择“Event Pattern”
- Service Name 选择“CodeCommit”
- Event Type 选择“All Events”
- 点击“Edit”,粘入以下Event Pattern
{
"source": [
"aws.codecommit"
],
"detail-type": [
"CodeCommit Repository State Change"
],
"resources": [
"arn:aws-cn:codecommit:cn-north-1:XXXX:tstestrep"
],
"detail": {
"referenceType": [
"branch"
],
"referenceName": [
"master"
]
}
}
说明:Event Pattern用来对AWS Event进行过滤,满足Pattern则触发Targets,这里当CodeCommit Repo“tstestrep”中有变动时,触发Targets
图25
然后在页面的右半部分Targets中,下拉列表选择“CodeBuild project”,然后粘贴我们的Build project信息“arn:aws-cn:codebuild:cn-north-1:XXXX:project/tstestCodeCommit”(可以在Build detail中找到),然后点击“Configure details”
图20
添加Rule名称和描述后,点击“Create rule”
图21
创建完成
图22
测试Push代码后自动运行CodeBuild
现在我们在本地git环境把新文件push到CodeCommit中
tstestrep/
├── Dockerfile
├── HelloWorld.java
├── buildspec.yml
├── entrypoint.sh
└── test.html
图26
然后我们在CodeBuild “tstestCodeCommit”的“Build history”中,就可以看到新的构建自动开始运行了
图23
点进去可以看到Build日志,过一会儿Build完成
图27
现在可以在ECR Repo “tstest”中看到我们新推入的镜像
图28
4. 利用Lambda函数连接CodeBuild和CodeDeploy
我们在CloudWatch中,直接利用Rule的Targets,选择到CodeBuild的项目,把CodeCommit和Build连接起来。
但是Targets中没有CodeDeploy选项,所以下面我们利用Lambda函数把Build和Deploy连接起来。
创建Lambda函数
创建Lambda函数的详细过程请参考“AWS Lambda之CodeDeploy部署测试”一文,本文只列出不同的地方
在Lambda界面新建函数“tsCodeBuildTriggerDeploy”,“Execution role”可以选择我们上次Lambda函数中用过的“tstestCodeDeploy-role-tlh9dusl”。
在lambda_function.py文件中粘贴以下内容,然后点击“Deploy”
import json
import boto3
client = boto3.client('codedeploy')
def lambda_handler(event, context):
# TODO implement
print(event)
response = client.create_deployment(
applicationName='tstestFargate',
deploymentGroupName='tstestDGrp',
revision={
'revisionType': 'S3',
's3Location': {
'bucket': 'ts-test',
'key': 'appspec.json',
'bundleType': 'JSON'
}
},
description='testforCodeBuildTriggerDeploy',
autoRollbackConfiguration={
'enabled': True,
'events': [
'DEPLOYMENT_FAILURE',
'DEPLOYMENT_STOP_ON_REQUEST'
]
}
)
print(response)
说明:
Lambda调用Boto3中CodeDeploy,创建一个CodeDeploy应用“tstestFargate”的部署,具体部署内容文件从S3中获取。
可以看到这个Lambda函数没有使用event中的数据,所以建好后可以直接点测试,然后在CodeDeploy界面查看新建的Deployment。
图31
创建Rule
在CouldWatch中,我们新建一个Rule,使得当CodeBuild中“tstestCodeCommit”项目构建成功,并且把镜像推入ECR后,触发上述Lambda函数。
建Rule时,按下述内容配置
- Service Name选择“CodeBuild”
- Event Type选择“CodeBuild Build Phase Change”
- Edit中贴粘以下Event Pattern
{
"source": [
"aws.codebuild"
],
"detail-type": [
"CodeBuild Build Phase Change"
],
"detail": {
"completed-phase": [
"POST_BUILD"
],
"completed-phase-status": [
"SUCCEEDED"
],
"project-name": [
"tstestCodeCommit"
]
}
}
说明:当CodeDeploy项目“tstestCodeCommit”进行到“POST_BUILD”阶段,状态为“SUCCEEDED”的时候,满足Event Pattern就会触发Targets
图32
- Targets选择Lambda function
- Function选择我们上面建好的“tsCodeBuildTriggerDeploy”
图29
添加名称后,点击“Create rule”
图30
结果如下图
图33
创建新Fargate Task版本
接下来我们利用之前的Fargate环境,有关Fargate Task内容,请参见“创建ECS Fargate”一文。
编辑文后附的tstest_task.json文件,把image换成我们在CodeBuild里新生成的Image信息,XXXX换成你的AWS account
{
...
"family": "tstest-fargate-task",
"containerDefinitions": [
{
"name": "fargate-app1",
"image": "XXXX.dkr.ecr.cn-north-1.amazonaws.com.cn/tstest:latest",
...
}
然后利用命令建新Task版本
aws ecs register-task-definition --cli-input-json file://tstest_task.json
结果如下图,记录task版本号“12”
图34
修改CodeDeploy中用的appspec.json
编辑文后附的appspec.json文件,把image换成我们在CodeBuild里新生成的Image信息,XXXX换成你的AWS account
...
"TaskDefinition": "arn:aws-cn:ecs:cn-north-1:XXXX:task-definition/tstest-fargate-task:12",
...
然后上传到上面Lamdba函中指定的s3Location的bucket “ts-test”中
上传appspec.json到S3
在AWS中控台选择S3,点击“Buckets”,然后点击“ts-test”
图35
进入我们的S3桶,点击“Upload”
图36
点击“Add files”后,选择刚才编辑的本地文件“appspec.json”
图37
点击“Upload”
图38
上传完成,点击“Close”
图39
5. 测试CICD工具链
准备工作完成,下面我们测试CICD工具链。
整个流程如下图所示
图52
在本地Git Repo中做一些改动,(或者touch a),然后push代码,启动CICD流水线
Push代码到CodeCommit
图46
CloudWatch中配置的Rule “tsCodeBuildtrigger”会触发CodeBuild
图48
CodeBuild启动(图截的晚了,已经跑完了。正常这里先是“In progress”)
图47
过一会儿POST_BUILD阶段完成
图41
CloudWatch Rule“tsCodeDeploytrigger”触发Lambda函数,由Lambda函数启动CodeDeploy
图49
CodeDeploy中部署启动
图42
在ECS Clsuter的Task界面,可以看到新Task开始启动
图43
过一会儿,流量导入新Task完成,进入等待阶段
图44
新旧Task同时运行
图45
部署完成
图50
旧Task消灭,新Task正常运行
整个流水线完成
总结
我们按着下面的流程图再总结一下全过程
图52
- 用户在客户端用Git命令Push代码到CodeCommit的代码仓库中
- CloudWatch通过设置的Rule触发CodeBuild构建项目
- 构建项目启动后,从代码仓库中拉到代码,生成镜像,然后把镜像推送至ECR
- 在构建项目POST_BUILD成功后,CloudWatch通过设置的Rule触发Lambda函数
- Lambda函数启动CodeDeploy部署
- 最终新镜像在新的ECS Fargate中生成容器并运行
引申
- 中国区没有Codepipeline,有的话,可以用Codepipeline实现上述CICD流水线
- 我们可以继续扩展上述CICD流水线,比如在每个阶段加SNS通知,在CodeBuild阶段加入编译代码的过程,在CodeDeploy过程中加入测试的过程。
资源下载
相关文件可在下列链接中下载https://github.com/tansong0091/realCrapForAWS/tree/main/CodeCommit_build2
后记
可以看到通过综合运用CloudWatch, Lambda, S3我们可以把整个CICD流水线做到尽可能的完善,实现完全的云上CICD流水线。
上面写的AWS CICD流水线也可以利用AWS的其它服务来实现。CICD没有固定的工具集,拿自己用的最熟的工具实现目的即可。
喜欢请点赞,欢迎转发
微信公众号“全是 AWS 干货”