aws codepipeline 配置 ecs 蓝绿部署

news2024/11/15 15:53:43

参考资料

  • CI/CD workshop for Amazon ECS
  • Tutorial: Create a pipeline with an Amazon ECR source and ECS-to-CodeDeploy deployment
  • Amazon ECS 计算平台上的部署
  • CodeDeploy AppSpec 文件引用

之前的文章介绍了通过codepipeline对ecs服务进行滚动更新,本文主要介绍通过codepipeline创建ecs蓝绿部署的过程

蓝绿部署的好处

  • 在将生产流量路由到新部署的环境之前对其进行测试。

  • 支持从旧版本立即切换到新版本,避免在使用就地滚动更新时可能出现的任何不一致。

  • 如果在新版本启动后检测到问题,将启用即时回滚到以前的版本。

本次涉及到的资源

git clone https://github.com/aws-samples/cicd-for-ecs-workshop-code.git

检查开启container insight功能

aws ecs put-account-setting-default --name containerInsights --value enabled
aws ecs list-account-settings --effective-settings --name containerInsights

确保服务相关角色存在

aws iam get-role --role-name "AWSServiceRoleForElasticLoadBalancing" || aws iam create-service-linked-role --aws-service-name "elasticloadbalancing.amazonaws.com"
aws iam get-role --role-name "AWSServiceRoleForECS" || aws iam create-service-linked-role --aws-service-name "ecs.amazonaws.com"

部署项目创建逻辑如下

  • 创建codecommit
  • 推送web server
  • 创建codepipeline,添加source阶段为codecommit
  • 添加build阶段,创建codebuild项目构建image并推送到ecr
  • 添加deploy阶段,创建ecs蓝绿部署部署组

workflow

创建 ecs 蓝绿部署

web server以及dockerfile

cat > server.js << EOF
'use strict'

const greeting = "Hi there is hello-servre blue green !"  // Change this line to change your greeting

const port = (typeof process.env.PORT !== 'undefined')
  ? process.env.PORT
  : '80'

const express = require('express')
const bodyParser = require('body-parser')

const app = express()
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))

// Constants
const host = '0.0.0.0';

function format(o, pretty) {
  return (pretty)
    ? JSON.stringify(o, null, 2) + '\n'
    : JSON.stringify(o);
}

app.get('/hello/:name', (req, res) => {
  var name = req.params.name
  let timestamp = Date.now()
  res.send(greeting + " " + name + "<br>\n<i>" + timestamp + "</i>\n")
})
app.get('/ping', (req, res) => {
  res.send("ok")
})

const server = app.listen(port, host);
console.log(`Service running on http://${host}:${port}`)

process.on('SIGTERM', () => {
  console.info('SIGTERM signal received.');
  console.log('Closing http server.');
  server.close(() => {
    console.log('Http server closed.');
    process.exit(0);
  })
})
EOF
cat > package.json << EOF
{
  "name": "hello-server",
  "version": "1.0.0",
  "description": "Simple server that says hello to a named person",
  "author": "Mike Rizzo <michariz@amazon.co.uk>",
  "license": "MIT",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "body-parser": "^1.19.0",
    "express": "^4.17.1"
  }
}
EOF
cat > Dockerfile << EOF
FROM node:buster-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 80
CMD ["node", "server.js"]
EOF

通过任务定义创建任务,这里需要随便指定一个image就行

cat > taskdef-prod.json << EOF
{
  "family": "hello-server-prod",
  "networkMode": "bridge",
  "memory": "256",
  "requiresCompatibilities": [
    "EC2"
  ],
  "containerDefinitions": [
    {
      "name": "hello-server",
      "image": "xxxxxx.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-server",
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/hello-server-prod",
          "awslogs-region": "cn-north-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "portMappings": [
        {
          "containerPort": 80,
          "protocol": "tcp"
        }
      ],
      "essential": true
    }
  ]
}
EOF
aws ecs register-task-definition --cli-input-json file://taskdef-prod.json

创建 ecs 服务,服务绑定目标组,指定deploymentController类型为CODE_DEPLOY

侦听器 由负载均衡器用于将流量定向到目标组。必须提供一个生产侦听器。您可以指定可选的第二个测试侦听器,在您运行验证测试时该侦听器可以将流量定向到替换任务集

目标组 用于将流量路由到一个注册目标。Amazon ECS 部署需要两个目标组:一个用于您的 Amazon ECS 应用程序的原始任务集,另一个用于替换任务集。在部署期间,CodeDeploy 会创建替换任务集,并将流量从原始任务集重新路由到新的任务集

cat > service-prod.json << EOF
{
    "taskDefinition": "hello-server-prod:1",
    "cluster": "worktest",
    "loadBalancers": [
        {
            "targetGroupArn": "arn:aws-cn:elasticloadbalancing:cn-north-1:xxxxxxxxxx:targetgroup/test-deploy-ecs-blue/86c5601b7042a987",
            "containerName": "hello-server",
            "containerPort": 80
        }
    ],
    "desiredCount": 3,
    "launchType": "EC2",
    "schedulingStrategy": "REPLICA",
    "deploymentController": {
        "type": "CODE_DEPLOY"
    },
    "healthCheckGracePeriodSeconds": 8
}
EOF
aws ecs create-service --cli-input-json file://service-prod.json

构建image的过程和ecs滚动更新的项目没有区别, 区别在于post_build阶段的输出文件增加了imageDetail.json

Image definitions file reference

cat > buildspec.yml << EOF
version: 0.2
env:
  exported-variables:
    - AWS_DEFAULT_REGION
phases:
  # install:
  #   runtime-versions:
  #     docker: 18
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws --version
      - $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)
      - REPOSITORY_URI=xxxxxxxxxx.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-server-bluegreen
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:=latest}
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t $REPOSITORY_URI:latest .
      - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker images...
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - echo Writing image definitions file...
      - printf '{"ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
      - cat imagedefinitions.json
      - cat imageDetail.json
artifacts:
  files:
    - imageDetail.json
    - appspec.yaml
    - taskdef-prod.json
EOF

buildspec.yaml中输出的taksdef-prod.json

注意:“image”: “<IMAGE_NAME>” 等待动态填充

$ cat taskdef-prod.json
{
  "family": "hello-server-prod",
  "networkMode": "bridge",
  "memory": "256",
  "requiresCompatibilities": [
    "EC2"
  ],
  "containerDefinitions": [
    {
      "name": "hello-server",
      "image": "<IMAGE_NAME>",
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/hello-server-prod",
          "awslogs-region": "cn-north-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "portMappings": [
        {
          "containerPort": 80,
          "protocol": "tcp"
        }
      ],
      "essential": true
    }
  ]
}

查看codepipeline的deploy阶段配置

填充的内容包括deploy应用和部署组,同时需要填写build阶段输出文件中的参数,以便于动态填充

在这里插入图片描述

buildspec.yaml中输出的appspec.yaml

对于 TaskDefinition,请勿更改 <TASK_DEFINITION> 占位符文本。此值会在管道运行时进行更新。

cat > appspec.yaml << EOF
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: "hello-server"
          ContainerPort: 80
EOF

ecs控制台的部署过程

在这里插入图片描述

ecs部署配置有以下几个,示例中一次性转移所有流量

  • Canary:流量在两次增量中转移。可以设定时间间隔
  • Linear:流量使用相等的增量转移,在每次递增之间间隔的分钟数相同。
  • AllAtOnce:所有流量均从原始 Amazon ECS 任务集一次性地转移到更新后的 Amazon ECS 任务集。

在这里插入图片描述

完整的生命周期如下

Lifecycle eventLifecycle event action
BeforeInstall (a hook for Lambda functions)Run Lambda functions.
InstallSet up the replacement task set.
AfterInstall (a hook for Lambda functions)Run Lambda functions.
AllowTestTrafficRoute traffic from the test listener to target group 2.
AfterAllowTestTraffic (a hook for Lambda functions)Run Lambda functions.
BeforeAllowTraffic (a hook for Lambda functions)Run Lambda functions.
AllowTrafficRoute traffic from the production listener to target group 2.
AfterAllowTrafficRun Lambda functions.

由于没有指定测试监听器,因此本次不会触发测试阶段

在这里插入图片描述

在这里插入图片描述

添加测试监听器

通过在codedeploy部署组配置中指定测试监听器,能够在切换蓝/绿组使替换生效之前,验证测试端口上的新(替换)任务集

添加测试阶段后,完整的ecs蓝绿部署过程如下:

在这里插入图片描述

修改部署组配置,增加测试监听器

在这里插入图片描述

nodejs创建的lambda测试函数

const aws = require('aws-sdk');
const codedeploy = new aws.CodeDeploy({apiVersion: '2014-10-06'});

exports.handler = (event, context, callback) => {
    console.log(event)
    var deploymentId = event.DeploymentId;
    var lifecycleEventHookExecutionId = event.LifecycleEventHookExecutionId;
    
    /*
     Enter validation tests here.
    */
    
    var params = {
        deploymentId: deploymentId,
        lifecycleEventHookExecutionId: lifecycleEventHookExecutionId,
        status: 'Succeeded' // status can be 'Succeeded' or 'Failed'
    };
    
    codedeploy.putLifecycleEventHookExecutionStatus(params, function(err, data) {
        if (err) {
            console.log(err, err.stack);
            // Validation failed.
            callback('Validation test failed');
        } else {
            console.log(data); 
            // Validation succeeded.
            callback(null, 'Validation test succeeded');
        }
    });
};

修改appspec.yaml增加hook,test-ecs-bluegreen为lambda函数的名称

cat appspec.yaml
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: "hello-server"
          ContainerPort: 80
Hooks:
  - BeforeAllowTraffic: "test-ecs-bluegreen"

重新git push提交之后触发pipeline,在codedeploy阶段意料之中会卡在BeforeAllowTraffic,转而去执行lambda测试

在这里插入图片描述

在lambda调用的cloudwatch log中查看具体的事件内容

{
  "DeploymentId": "d-4VQ95PY4K",
  "LifecycleEventHookExecutionId": "eyJlbmNyeXB0ZWREYXRhIjoid1dEUngzbkU5RjRwZC9PNTIzNzhVTUZyRDhRNnk4ZnlhVi9MYXZJRWE5S1RKRXBUdWN1SUhhSmgvOW1OU0t2NzZsbnpFNDlGdDczVE5BN0JWNlhFRlIvekQycGpvanFPU3RhQWVyM0l4VDlRQ0Fsb3BJNVpoQ2JsRWlUa2JuSTd5UTRldWcraWhRPT0iLCJpdlBhcmFtZXRlclNwZWMiOiJiWDNRSWJqSFZTK2swMUZKIiwibWF0ZXJpYWxTZXRTZXJpYWwiOjF9"
}

lambda中出现以下报错,lambda需要配置执行角色

AccessDeniedException: User: arn:aws-cn:sts::xxxxxxxxxx:assumed-role/test-ecs-bluegreen-role-jsj5bg7k/test-ecs-bluegreen is not authorized to perform: codedeploy:PutLifecycleEventHookExecutionStatus on resource: arn:aws-cn:codedeploy:cn-north-1:xxxxxxxxxx:deploymentgroup:hello-server-bluegreen/hello-server-bluegreen because no identity-based policy allows the codedeploy:PutLifecycleEventHookExecutionStatus action

索性手动发送api通过

aws deploy put-lifecycle-event-hook-execution-status --deployment-id d-4VQ95PY4K --lifecycle-event-hook-execution-id eyJlbmNyeXB0ZWREYXRhIjoid1dEUngzbkU5RjRwZC9PNTIzNzhVTUZyRDhRNnk4ZnlhVi9MYXZJRWE5S1RKRXBUdWN1SUhhSmgvOW1OU0t2NzZsbnpFNDlGdDczVE5BN0JWNlhFRlIvekQycGpvanFPU3RhQWVyM0l4VDlRQ0Fsb3BJNVpoQ2JsRWlUa2JuSTd5UTRldWcraWhRPT0iLCJpdlBhcmFtZXRlclNwZWMiOiJiWDNRSWJqSFZTK2swMUZKIiwibWF0ZXJpYWxTZXRTZXJpYWwiOjF9 --status Succeeded

手动发送之后成功进入下一步,开始线性转移流量生产监听器的流量到green目标组

在这里插入图片描述

具体是通过在alb中设置权重实现的

在这里插入图片描述

50%时进行访问测试,结果符合预期

for i in {1..20} ;do curl http://main-alb-1897344746.cn-north-1.elb.amazonaws.com.cn:8085/hello/test ; done
Hi there is hello-servre blue green ! test lambda test<br>
<i>1672497407811</i>
Hi there is hello-servre blue green ! test lambda test test<br>
<i>1672497407920</i>
Hi there is hello-servre blue green ! test lambda test<br>
<i>1672497408026</i>
Hi there is hello-servre blue green ! test lambda test test<br>
<i>1672497408149</i>
Hi there is hello-servre blue green ! test lambda test test<br>
<i>1672497408262</i>
Hi there is hello-servre blue green ! test lambda test<br>
<i>1672497408356</i>
Hi there is hello-servre blue green ! test lambda test<br>
<i>1672497408487</i>
Hi there is hello-servre blue green ! test lambda test test<br>
<i>1672497408589</i>
Hi there is hello-servre blue green ! test lambda test test<br>
<i>1672497408671</i>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/131603.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker 学习总结(78)—— WebAssembly 入门简介

什么是 WebAssembly? WebAssembly 是一种定义二进制指令格式的开放标准&#xff0c;它支持从不同的源语言创建可移植的二进制可执行文件。这些二进制文件可以在各种环境中运行。它起源于 Web&#xff0c;并得到各大主流浏览器的支持。 Wasm 如何在浏览器中工作&#xff1f; …

RCTF-pwn-diary

RCTF-pwn-diary 赛后看了一眼发现给出了源码&#xff0c;https://github.com/ruan777/RCTF2022/blob/main/diary/main.cpp 漏洞是erase的问题 解释一下 add(0) add(1) add(2) delete(1)这样子的话&#xff0c;其实就是把2给删除&#xff0c;把2的内容复制到1中&#xff0c;所…

Base64自定义编码表及破解

什么是Base64 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一&#xff0c;Base64并不是安全领域的加密算法&#xff0c;其实Base64只能算是一个编码算法&#xff0c;对数据内容进行编码来适合传输。标准Base64编码解码无需额外信息即完全可逆&#xff0c;即使你自…

基于Python + Django 开发一款学生管理系统(附源码)

文章目录1.开发环境源码分享&技术交流2.项目实战1&#xff09;创建Django项目2&#xff09;创建应用3&#xff09;配置MySQL4&#xff09;数据模型层创建5&#xff09;路由配置6&#xff09;增删改查视图函数7&#xff09;模板页面创建8&#xff09;启动web服务1.开发环境 …

最大似然和贝叶斯参数估计

统计生成模型的参数估计 – Maximum Likelihood(ML) 假设参数是某个确定的值&#xff0c;通过使似然度最大求出参数 – Bayesian estimation 假设参数是随机变量&#xff0c;估计参数分布的参数 – 最大似然求出具体的参数&#xff0c;贝叶斯求的是参数的分布 最大似然估计 假…

献给自己技术成长的第三年

年度总结词语&#xff1a;幸运 献给自己技术成长的第三年一、五州一都二、if else量产三、学技术四、用真心五、设计精产六、感恩幸运一、五州一都 1.1-1.12成都、2.23-3.19广州、4.12-7.23苏州、8.12-8.20兰州、8.23-9.20湖州、其余杭州 成都。去年年底出差到成都&#xff0c;…

HTTP_day01

在互联网世界里&#xff0c;HTTP 通常跑在 TCP/IP 协议栈之上&#xff0c;依靠 IP 协议实现寻址和路由、TCP 协议实现可靠数据传输、DNS 协议实现域名查找、SSL/TLS 协议实现安全通信。此外&#xff0c;还有一些协议依赖于 HTTP&#xff0c;例如 WebSocket、HTTPDNS 等。这些协…

【数据结构】冒泡排序、快速排序(递归,非递归)、归并排序(递归,非递归),七大排序比较,

文章目录冒泡排序快速排序归并排序七大排序之间的对比冒泡排序 基本思想&#xff1a;所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置&#xff0c;交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小…

高性能web网关之Openresty相关基础知识

高性能web网关之Openresty一、Openresty 简介二、Openresty 应用场景三、lua-nginx-module3.1、Lua 模块指令顺序3.2、Lua嵌入nginx四、责任链五、cosocket后言一、Openresty 简介 openresty 是一个基于 nginx 与 lua 的高性能 web 平台&#xff0c;其内部集成了大量精良的 lu…

148.排序链表

148.排序链表 题目&#xff1a; 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;…

【论文阅读】CVPR2018-深度材料感知跨光谱立体匹配

深度材料感知跨光谱立体匹配 摘要 跨光谱成像对识别和检测任务很有帮助。通常&#xff0c;多个相机用于跨光谱成像&#xff0c;因此需要图像对齐或双目系统中的视差估计。多相机跨光谱系统逐渐被嵌入到有源RGB-D设备中&#xff08;例如Kinect和iPhone X中的RGB-NIR相机&#…

2022 年度回忆

2022 年度回忆 过了今天就是2023年了&#xff0c;记录一下在这一年里发生的点点滴滴吧。 年度总结2022 年度回忆1.石家庄实习2.准备秋招&#xff0c;然后去沈阳实习3.回学校4.来北京实习了总结今年大体且分为四条故事线 1.22年上半年石家庄实习 2.实习结束回家准备秋招&#…

句子表征(各项异性等偏差):PromptBERT: Improving BERT Sentence Embeddings with Prompts

一、核心 句子表征存在不足之处&#xff0c;可能面临各向异性、可能受到词频的影响、可能受到子词、大小写等的影响等等。 Gao et al.(2019)和Wang et al.(2020)指出&#xff0c;对于语言建模&#xff0c;使用最大似然训练通常会产生一个各向异性的词嵌入空间。“各向异性”是…

BabaSSL:支持半同态加密算法 EC-ElGamal

01 背 景 随着大数据与人工智能的快速发展&#xff0c;个人隐私数据泄露和滥用时有发生&#xff0c;隐私安全问题也越来越被重视。 国家于 2020 年施行密码法、2021 年施行个人信息保护法&#xff0c;对个人隐私数据和数据安全加密有更高的要求。 因此&#xff0c;隐私计算也…

2022年博客之路总结

今年是不平凡的一年&#xff0c;IT行业 开卷 的一年&#xff0c;今年大多数人 都 因种种原因 被迫换了工作&#xff0c;再次 先感谢CSDN 这个平台&#xff0c;在这里 给自己了一块可以展示自己才华的空间&#xff0c;通过CSDN平台的各项运营数据&#xff0c;让我有幸 拿到了 更…

flv.js播放flv视频

flv.js是FLV视频播放器&#xff0c;纯JS开发&#xff0c;无需Flash。 <!DOCTYPE html> <html><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport"…

【虚幻引擎UE】UE5 制作一个元旦烟花短视频的小案例(使用sequence制作视频案例)

祝愿大家元旦快乐&#xff01; 效果预览 一、创建粒子烟花特效 可以使用现成的Niagara烟花粒子特效&#xff0c;直接跳过这一步。 1、 通过Niagara系统创建粒子特效 选择现有发射器素材。 或者也可新建空白特效&#xff0c;将发射器拖入轨道&#xff08;素材包含闪光、拖…

基于TP6+Uni-app框架开发的多端圈子社区论坛小程序H5系统,带数据库和安装教程

正文&#xff1a; 前台uni-app后台tp6开发的多端圈子社区论坛小程序H5系统,带数据库和安装教程。 系统基于TP6Uni-app框架开发&#xff1b;客户移动端采用uni-app开发&#xff0c;管理后台TH6开发。 系统支持微信公众号端、微信小程序端、H5端、PC端多端账号同步&#xff0c…

CSDN的2022和2023

前言 今天是2022年12月31日&#xff0c;今年的最后一天&#xff0c;年关已至。 又到了&#xff1a;回头看路&#xff0c;低头赶路&#xff0c;抬头望路的时候。 回顾2022 疫情中的2022 今年应该算是疫情的高峰期吧&#xff0c;各种新冠变异株横行&#xff0c;从严控到一夜…

Day845.Fork/Join -Java 并发编程实战

Fork/Join Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于Fork/Join的内容。 线程池、Future、CompletableFuture 和 CompletionService&#xff0c;仔细观察会发现这些工具类都是在帮助站在任务的视角来解决并发问题&#xff0c;而不是让纠缠在线程之间如何协作的…