关于集群:CODING-CD-Nginx-Ingress-实现蓝绿发布

42次阅读

共计 9219 个字符,预计需要花费 24 分钟才能阅读完成。

本文作者:杨浩佳 – CODING 后端开发工程师
全文约 4000+ 字,预计浏览工夫 20 分钟

前言

本文将介绍如何通过 CODING CD 应用 Nginx Ingress 来实现 蓝绿公布

为什么要采纳蓝绿公布?随着业务的疾速倒退,对开发团队的要求越来越高,一方面要求为用户提供稳固的服务,一方面要求进行疾速业务迭代。因而基于零碎稳定性和疾速业务迭代的综合思考,须要采纳蓝绿公布上线新版本服务的形式,实现应用服务的安稳降级。

为什么要应用 CODING CD?传统的部署是批改 YAML 文件的镜像版本,而后通过命令行 kubectl apply 的形式更新应用服务的版本,这种公布形式过于依赖人工执行,对于 DevOps 团队来说是不可忍耐的。而通过 CODING CD 部署流程实现自动化流水线,流水线的所有阶段都能够供团队中的任何人查看、改良和验证,开发团队能够进步公布的速度和升高公布的危险和老本。

概述

什么是 Nginx Ingress

Nginx Ingress 是 Kubernetes Ingress 的一种实现,它通过 watch Kubernetes 集群的 Ingress 资源,将 Ingress 规定转换成 Nginx 的配置,而后让 Nginx 来进行 7 层的流量转发。

应用注解阐明

咱们通过给 Ingress 资源指定 Nginx Ingress 所反对的一些 annotation 能够实现蓝绿公布,须要给服务创立两个 Ingress,一个失常的 Ingress(myapp-ingress),另一个是带 nginx.ingress.kubernetes.io/canary: "true" 这个固定的 annotation 的 Ingress,咱们权且称它为 Canary Ingress(myapp-blue-ingress),个别代表新版本的服务,联合另外针对流量切分策略的 annotation 一起配置即可实现多种场景的蓝绿公布,以下是对本次实际应用到的 annotation 的介绍:

  • nginx.ingress.kubernetes.io/canary-by-header: 示意如果申请头中蕴含这里指定的 header 名称,并且值为 always 的话,就将该申请转发给该 Ingress 定义的对应后端服务;如果值为 never 就不转发,能够用于回滚到旧版;如果是其它值则疏忽该 annotation。
  • nginx.ingress.kubernetes.io/canary-by-header-value: 这个能够作为 canary-by-header的补充,容许指定申请头的值能够自定义成其它值,不再只能是 alwaysnever;当申请头的值命中这里的自定义值时,申请将会转发给该 Ingress 定义的对应后端服务,如果是其它值则将会疏忽该 annotation。
  • nginx.ingress.kubernetes.io/canary-weight: 示意 Canary Ingress 所调配流量的比例的百分比,取值范畴 [0-100],比方设置为 10,意思是调配 10% 的流量给 Canary Ingress 对应的后端服务。

更多对于 Nginx Ingress 的注解阐明能够参考官网文档。

什么是蓝绿公布

蓝绿公布,是在生产环境稳固集群之外,额定部署一个与稳固集群规模雷同的新集群,并通过流量管制,逐渐引入流量至新集群直至 100%,原先稳固集群将与新集群同时放弃在线一段时间,期间产生任何异样,可立即将所有流量切回至原稳固集群,实现疾速回滚。直到全副验证胜利后,下线老的稳固集群,新集群成为新的稳固集群。

公布流程

蓝绿公布的流程,包含:蓝绿公布开始、蓝绿初始化、蓝绿验证、蓝绿勾销或实现上线。

如上图所示,老集群集群的版本为 v1,该集群通过 version=v1 标签被 Service myapp-svc 拜访到。

  • 额定部署了一个新集群,版本为 v2,该集群通过 version=v2 标签被 Service myapp-blue-svc 拜访到。
  • 通过流量管制,管制局部流量或全副流量到新集群,进行蓝绿验证,同时原稳固集群持续放弃在线。
  • 如果验证没有发现任何故障,则利用 myapp 的蓝绿公布实现,v2 版本集群成为新的稳固集群。
  • 如果在验证中发现了故障,则通过流量管制,将全副流量切回原来稳固的老集群,实现疾速回滚。

实际

前提条件

Kubernetes 集群中须要部署 Nginx Ingress 作为 Ingress Controller,并且对外裸露了对立的流量入口。

老集群初始化

公布流程

配置

这里配置部署 myapp 应用服务所须要的 docker 镜像制品,还有启动参数 version,该参数的作用次要是作为标签为 Service 提供筛选过滤条件,实现新老版本服务的流量管制。

公布策略

公布策略采纳 人工确认 阶段,可配置确认人,抉择不同公布形式。

惯例公布

惯例公布采纳 预置条件查看 阶段,预置条件配置 #judgment("公布策略") == '惯例公布' 表达式,表达式中的 judgment 函数返回 人工确认 阶段选定的选项,并通过 == 关系运算符来比拟表达式中的值,如果表达式判断胜利,将执行这个分支的阶段。

新集群 (即绿集群) 部署

apiVersion: apps/v1

kind: Deployment

metadata:

annotations:

strategy.spinnaker.io/max-version-history: ‘3’   # 示意保留 3 个历史版本的 myapp-deploy

strategy.spinnaker.io/versioned: ‘true’   # 示意 Spinnaker 对 myapp-deploy 进行版本治理

name: myapp-deploy

spec:

replicas: 3

selector:

matchLabels:

app: myapp

version: ‘${parameters.version}’   # 援用配置中的启动参数 version

template:

metadata:

labels:

app: myapp

version: ‘${parameters.version}’

spec:

containers:

  • image: selinaxeon-docker.pkg.coding.net/coding-yhj/docker/myapp

name: myapp

ports:

  • containerPort: 80

${parameters.version} 表达式示意援用配置中已配置的启动参数 version。

这里部署新集群的 Deployment 被打上 Spinnaker 注解:

  • strategy.spinnaker.io/versioned,当该注解被设置为‘true’时,Spinnaker 将对 Deployment 资源进行版本治理。简略来说,就是公布后的 Deployment 名称将带有版本号,如 myapp-deploy-v000。
  • strategy.spinnaker.io/max-version-history,该注解示意 Spinnaker 将配置要保留的资源版本数。当 Spinnaker 公布的 k8s 资源的历史版本数超过 max-version-history 时,Spinnaker 会删除旧版本的资源。这里设置为 ‘3’,示意要保留 3 个历史版本的 Deployment myapp-deploy。

留神,此阶段还须要绑定配置中已配置的 myapp-image Docker 镜像制品,Spinnaker 将主动替换 Manifest 中匹配的 image。具体绑定替换规定参考帮忙文档。

切换流量

apiVersion: v1

kind: Service

metadata:

name: myapp-svc

spec:

ports:

  • name: tcp-80-80

port: 80

protocol: TCP

targetPort: 80

selector:

app: myapp

version: ‘${parameters.version}’

type: NodePort


apiVersion: extensions/v1beta1

kind: Ingress

metadata:

annotations:

kubernetes.io/ingress.class: nginx

name: myapp-ingress

spec:

rules:

  • host: myapp.coding.prod

http:

paths:

  • backend:

serviceName: myapp-svc

servicePort: 80

path: /

这里 Service myapp-svc 通过 version: '${parameters.version}' 标签拜访到带有雷同标签的 myapp-deploy Pod,myapp-ingress 配置路由到 Service myapp-svc 的规定,可通过 http://myapp.coding.prod 拜访到 myapp-svc 后端服务。

老集群下线

这里采纳 扩缩容 (Manifest) 阶段,抉择 动静抉择指标 并且 Target 抉择 次新的 ,将 Deployment myapp-deploy 的 replicas 设置为 0,实现老集群下线操作。之所以不采纳 删除 (Manifest)阶段是因为要保留 myapp-deploy 的历史公布版本,不便回滚操作,另外删除 myapp-deploy 的历史版本交给 strategy.spinnaker.io/max-version-history 注解实现。

留神,这里 执行选项 如果阶段失败 选项抉择 终止流程中的这个分支,因为对于老集群初始化部署时,没有次新的版本可供下线操作,此阶段会执行失败,导致整个流程部署失败。

为什么在惯例公布多了此阶段?目标是实现流水线可复用,第二次公布新版本服务时还能够通过该部署流程执行,新集群部署完直到服务稳固,即可同时进行 切换流量 老集群下线 操作。

蓝绿公布开始

在“公布策略”的人工确认阶段抉择公布类型“蓝绿公布”,即可开始蓝绿公布。在“蓝绿公布”的预置条件查看阶段配置条件表达式:#judgment("公布策略") == '蓝绿公布'

蓝绿初始化

新集群 (即蓝集群) 部署

apiVersion: apps/v1

kind: Deployment

metadata:

annotations:

strategy.spinnaker.io/max-version-history: ‘3’

strategy.spinnaker.io/versioned: ‘true’

name: myapp-deploy

spec:

replicas: 3

selector:

matchLabels:

app: myapp

version: ‘${parameters.version}’

template:

metadata:

labels:

app: myapp

version: ‘${parameters.version}’

spec:

containers:

  • image: selinaxeon-docker.pkg.coding.net/coding-yhj/docker/myapp

name: myapp

ports:

  • containerPort: 80

apiVersion: v1

kind: Service

metadata:

name: myapp-blue-svc

spec:

ports:

  • name: tcp-80-80

port: 80

protocol: TCP

targetPort: 80

selector:

app: myapp

version: ‘${parameters.version}’

type: NodePort


apiVersion: extensions/v1beta1

kind: Ingress

metadata:

annotations:

kubernetes.io/ingress.class: nginx

nginx.ingress.kubernetes.io/canary: ‘true’   # 开启 canary 性能

nginx.ingress.kubernetes.io/canary-by-header: blueGreenVersion   # 基于申请头路由

nginx.ingress.kubernetes.io/canary-by-header-value: blue   # 申请头满足 blueGreenVersion=blue 的申请会被路由到 myapp-blue-svc

name: myapp-blue-ingress

spec:

rules:

  • host: myapp.coding.prod

http:

paths:

  • backend:

serviceName: myapp-blue-svc

servicePort: 80

path: /

蓝绿初始化 流程:首先推送路由规定,管制全副流量在老集群,保障新集群部署启动期间不会接管任何流量。

咱们通过实例的 version: '${parameters.version}' 标签来辨认是蓝集群还是绿集群,因而启动部署流程前须填写不同的启动参数,确保 Service myapp-blue-svc 通过不同的 version 标签值筛选到蓝集群的实例 Pod;另外,通过公布 Ingress 规定 myapp-blue-ingress,申请头满足 blueGreenVersion=blue 匹配的申请会被路由到蓝集群的 Service myapp-blue-svc。推送完规定后,就能够部署新集群了。

留神,此阶段也须要绑定配置中已配置的 myapp-image Docker 镜像制品。

用户须要在正确匹配申请头才能够拜访新版本服务:curl -H 'blueGreenVersion:blue' http://myapp.coding.prod

蓝绿验证

蓝绿验证 流程:初始化实现后,能够推送路由规定,将局部申请流量或全副流量路由至新集群进行验证。验证过程中如果没有问题,能够一直将流量迁徙至新集群,直至所有流量都在新集群。如果蓝绿验证胜利则进入 蓝绿实现上线 流程,验证失败则进入 蓝绿勾销 流程。

蓝绿验证

蓝绿验证采纳 人工确认 阶段,配置确认人,可抉择管制局部申请流量或全副流量路由至新集群进行验证。这里还配置了自定义参数 blue_ratio,该参数是管制局部流量到新集群的申请百分比。

管制局部流量到新集群

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

annotations:

kubernetes.io/ingress.class: nginx

nginx.ingress.kubernetes.io/canary: ‘true’

nginx.ingress.kubernetes.io/canary-weight: ‘${#stage(“ 蓝绿验证 ”)”context”[“blue_ratio”]}’

name: myapp-blue-ingress

spec:

rules:

  • host: myapp.coding.prod

http:

paths:

  • backend:

serviceName: myapp-blue-svc

servicePort: 80

path: /

#stage("蓝绿验证")["context"]["customParams"]["blue_ratio"] 表达式示意援用 人工确认 阶段中已配置的自定义参数 blue_ratio,这将管制随机 blue_ratio% 申请进入新版本集群。

在此阶段的 执行选项 还需配置条件表达式 #judgment("蓝绿验证") == '管制局部流量到新集群',管制部署流程分支执行方向。

蓝绿验证后果确认

如果在管制局部流量到新集群验证过程中发现问题,能够通过此人工确认阶段实现将全副流量切回老集群。

在此阶段的 执行选项 也须要配置条件表达式 #judgment("蓝绿验证") == '管制局部流量到新集群',因为上一阶段因不满足条件被跳过执行,此阶段为上一阶段的上游阶段,还会继续执行,因而也须要配置条件表达式。

管制全副流量到新集群

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

annotations:

kubernetes.io/ingress.class: nginx

nginx.ingress.kubernetes.io/canary: ‘true’

nginx.ingress.kubernetes.io/canary-weight: ‘100’

name: myapp-blue-ingress

spec:

rules:

  • host: myapp.coding.prod

http:

paths:

  • backend:

serviceName: myapp-blue-svc

servicePort: 80

path: /

阐明:通过设置 nginx.ingress.kubernetes.io/canary-weight: '100' 管制全副流量到新集群。

留神,在此阶段的 执行选项 须要配置条件表达式 ${(#stage("蓝绿验证")["status"].toString() == "SUCCEEDED" && #judgment( '蓝绿验证') == '管制全副流量到新集群') || (#stage("蓝绿验证后果确认")["status"].toString() == "SUCCEEDED" && #judgment('蓝绿验证后果确认') == '验证胜利,管制全副流量到新集群') }。表达式中的 stage 函数 应用 #stage("蓝绿验证")["status"].toString() 返回 ” 蓝绿验证 ” 人工确认阶段的执行状态。Spinnaker 表达式的语法基于 Spring Expression Language (SpEL),能够应用 && 和 || 等关系运算符。

这里须要这么简单的条件表达式,是因为既能够从“蓝绿验证”人工确认阶段间接抉择 管制全副流量到新集群 选项进入此阶段,也能够从“蓝绿验证后果确认“人工确认阶段抉择 验证胜利,管制全副流量到新集群 选项进入此阶段,因而须要弱小的条件表达式来管制流程分支的走向。由此可见,Spinnaker 部署流程的弱小,可反对简单的流程分支管制,满足各种公布场景的不同需要。而且流水线只需一次配置,屡次执行。

蓝绿最终成果确认

如果在管制全副流量到新集群验证过程中发现问题,能够通过此人工确认阶段进入“蓝绿勾销”流程,实现将全副流量切回老集群。

在此阶段的 执行选项 也须要配置跟“管制全副流量到新集群”阶段一样的条件表达式,来管制部署流程分支执行方向。

蓝绿实现上线

新集群验证胜利

新集群验证胜利采纳 预置条件查看 阶段,预置条件配置比较简单:#judgment("蓝绿最终成果确认") == '新集群验证胜利'

蓝绿实现上线

apiVersion: v1

kind: Service

metadata:

name: myapp-svc

spec:

ports:

  • name: tcp-80-80

port: 80

protocol: TCP

targetPort: 80

selector:

app: myapp

version: ‘${parameters.version}’

type: NodePort


apiVersion: extensions/v1beta1

kind: Ingress

metadata:

annotations:

kubernetes.io/ingress.class: nginx

name: myapp-blue-ingress

spec:

rules:

  • host: myapp.coding.prod

http:

paths:

  • backend:

serviceName: myapp-svc

servicePort: 80

path: /

如果蓝绿验证没有发现问题,那么就能够实现蓝绿公布上线了。只有当全副流量在新集群时能力操作实现上线。实现上线后,如果再有须要回滚,那只能走一般的回滚流程了。

这里 Service myapp-svc 通过 version: '${parameters.version}' 标签拜访到带有雷同标签的新集群 Pod,实现流量切换,myapp-blue-ingress 也配置路由到 Service myapp-svc 的规定。

老集群下线

“老集群下线”跟惯例公布的“老集群下线”类似,都采纳 扩缩容 (Manifest) 阶段,只不过 执行选项 采纳默认配置。

蓝绿勾销

新集群验证失败

新集群验证失败采纳 预置条件查看 阶段,预置条件比较复杂:${(#stage("蓝绿验证后果确认")["status"].toString() == "SUCCEEDED" && #judgment( '蓝绿验证后果确认') == '验证失败,蓝绿勾销') || (#stage("蓝绿最终成果确认")["status"].toString() == "SUCCEEDED" && #judgment('蓝绿最终成果确认') == '新集群验证失败') }。因为既能够从“蓝绿验证后果确认”人工确认阶段间接抉择 验证失败,蓝绿勾销 选项进入此阶段,也能够从“蓝绿最终成果确认人工确认阶段抉择 新集群验证失败 选项进入此阶段。

蓝绿勾销

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

annotations:

kubernetes.io/ingress.class: nginx

nginx.ingress.kubernetes.io/canary: ‘true’

nginx.ingress.kubernetes.io/canary-by-header: blueGreenVersion

nginx.ingress.kubernetes.io/canary-by-header-value: blue

name: myapp-blue-ingress

spec:

rules:

  • host: myapp.coding.prod

http:

paths:

  • backend:

serviceName: myapp-blue-svc

servicePort: 80

path: /

如果在蓝绿验证过程中发现了问题,蓝绿勾销可秒级将全副流量切回老集群,具体步骤:推送路由规定管制所有流量到老集群。

这里批改 myapp-blue-ingress 的路由规定,只有申请头匹配 blueGreenVersion=blue 才能够拜访到新集群,不匹配则拜访老集群,实现了全副流量切换回老集群。

新集群下线

这里采纳 删除 (Manifest) 阶段,抉择 动静抉择指标 并且 Target 抉择 最新的,将新集群的 Deployment myapp-deploy 删除,实现老集群下线操作。

当然,也可先通过批改路由规定的形式,先将流量切回老集群,而后保留现场,不便进行问题排查。

成果

终于配置实现蓝绿公布的部署流程,接下来咱们来看一下蓝绿公布成果。

初始化绿集群

蓝绿公布胜利

蓝绿公布失败

结语

在下面的示例中,咱们通过在 CODING CD 中配置一条流水线,实现了基于 Nginx Ingress 的蓝绿公布。部署流程只需配置一次,便可永恒应用,大大减少了手工部署带来的失误,晋升了利用的公布效率。

正文完
 0