一、背景
云原生兴起,带动Kubernetes越发主流,如何将应用在K8s上进行简单、快捷的部署愈发受到关注。
相较于传统的部署方式,Kubernetes可以更快的更新新版本,打包应用,所有应用都是容器,可以轻松做到跨开发、测试和生产的环境一致性;基础设施出现问题时,服务Pod能够根据生命自动创建和迁移,无需人工干预;并且以容器为单位对应用资源进行精确控制,极大的提高了资源利用率。
二、云效解决方案
通过云效持续交付流水线和阿里云K8s很好的结合在一起,为应用的持续交付提供了很好的基础保障,如下图:
开发者提交代码变更到代码库,云效在监听着代码库的变动,一旦代码发生变化,将自动触发云效持续部署流水线一次构建任务的运行,包括代码检查、构建、测试部署、测试验证和生产部署等过程。其中,在构建完之后,生成Docker镜像,并自动上传至应用镜像仓库,在部署阶段(测试环境的部署和生产环境的部署)时,获取当前流水线实例构建出来的镜像版本,通过K8s进行容器编排部署。而这一切,都是通过自动化的手段进行完成。
在接下来的实操实践中,会着重透出以下几方面内容:
1、如何通过云效流水线进行镜像构建,并自定义镜像tag。
2、如何通过YAML进行发布,并进行动态进行模板化处理。
3、如何通过云效流水线进行镜像升级、分批发布和基于流量的灰度发布。
三、场景案例
本文通过一个Springboot项目来具体演示,如何通过云效快速实现K8s的部署发布。
示例代码库地址为:https://atomgit.com/flow-example/spring-boot.git,代码库主要目录结构如下所示:
spring-boot
|---app-configs
|---manifest-app
|---app.YAML
|---ingress.YAML
|---service.YAML
|---Dockerfile2
其中包含了一个deployment,一个service,以及一个ingress将这个服务暴露到公网上。Dockerfile2是我们在本例中构建镜像会用到的Dockerfile。
调用关系如下:
四、云效操作实践
接下来讲解如何将示例代码库进行构建并以kubectl apply的方式部署到阿里云 ACK。
准备工作
注册阿里云账号或RAM账号。
准备阿里云ACK集群。注意云效Ingress灰度发布目前支持的Kubernetes版本为1.18及之前版本。创建方式请参考创建Kubernetes托管版集群。
准备阿里云镜像仓库ACR。为了能够快速的拉取镜像,建议将ACK集群与ACR放在同一区域,如本例中的华东1:杭州,这样后续在进行Kubernetes部署的时候,我们可以选择镜像VPC地址。若不在同一区域,请选择VPC公网地址。创建方式请参考创建个人版实例。
配置代码库
创建流水线之后会自动弹出添加代码源的窗口,这里选择Flow提供的示例代码源,并进行添加
配置镜像构建任务
进入“镜像构建并推送至阿里云镜像仓库”的任务进行编辑。如下图所示,点击”新建服务授权”,进行阿里云授权。同意授权之后,Flow会将创建好的服务授权自动回填写到表单中。
接下来完成区域、仓库的选取。标签填入“${DATETIME}”,表示以流水线触发时的时间戳作为镜像的标签,很多企业习惯将分支名或者tag作为镜像的标签,云效也是支持的,如下图所示,详情参考链接环境变量。
Dockerfile路径填入”Dockerfile2”,如下图所示。
配置好之后在“镜像构建并推送至阿里云镜像仓库”任务的下方可以看到该任务输出的变量,这些变量可以在后续的任务中引用。关注其中的第二个和第三个变量即可,其中第二个是该镜像地址的公网地址,第三个是该镜像地址的VPC地址。这里推荐将镜像仓库和ACK集群放在同一个region,然后在后续的部署任务中选择VPC地址,以加速部署过程。
配置部署任务
点击“Kubernetes发布”任务,进入配置。点击”新建连接”,进行集群授权,完成阿里云授权及集群选取。点击确认之后,集群信息会自动填到任务配置中。
不同企业资源互通,云效支持不同企业资源在同一账号下进行使用,具体参考链接授权管理—添加多个阿里云账号的授权服务。
配置YAML路径,本示例中YAML路径地址为:app-configs/manifest-app。
配置变量,本演示案例中,需配置两个变量,一个镜像地址IMAGE,一个是服务访问地址HOST。
配置变量IMAGE。点击【添加参数】按钮,变量类型选择上游输出,变量名填入IMAGE,选择镜像的VPC地址作为变量值。如下图所示
这样在运行时,Flow会把YAML路径下的所有文件中的${IMAGE}都替换成镜像的地址,然后再进行kubectl发布。示例代码库中的文件https://atomgit.com/flow-example/spring-boot/blob/master/app-configs/manifest-app/app.yaml的内容如下,所以其中的${IMAGE}就会被替换成实际的镜像地址。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
run: spring-boot-sample
name: spring-boot-sample
spec:
replicas: 2
selector:
matchLabels:
run: spring-boot-sample
template:
metadata:
labels:
run: spring-boot-sample
spec:
containers:
- image: ${IMAGE}
name: app
配置变量HOST。点击【添加参数】按钮,变量类型选择自定义,变量名填入HOST,填入连接集群的测试域名作为变量值,连接集群测试域名的获取方式如下:进入阿里云容器服务控制台,点击相应集群,点击基本信息,复制测试域名。注意复制测试域名的时候,不需要复制前面的“.*”。
将复制的测试域名,填入新建的自定义变量HOST,如下图所示:
示例代码库中的文件 https://atomgit.com/flow-example/spring-boot/blob/master/app-configs/manifest-app/ingress.yaml的内容如下,所以其中的${HOST}就会被替换成实际的测试地址。
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: spring-boot-route
spec:
rules:
- host: www.${HOST}
http:
paths:
- backend:
serviceName: spring-boot-service
servicePort: 8080
path: /
运行流水线
配置完毕,点击”保存并运行”触发流水线:
由于在manifest中包含了ingress配置,因此可以通过ack的ingress提供的域名访问服务:
可以直接在浏览器中输入地址http://www.${HOST}进行验证,也可以通过下面的方式进行验证。
$ curl http://www.${HOST}
Greetings from Spring Boot!V4
镜像升级发布
1.准备工作
新建云效仓库
将示例代码拉取到云效仓库中。
点击进入云效Codeup页面,点击【添加库】-【导入代码库】
在弹出页面中,选择【URL导入】,在源代码库地址框中输入本示例代码库地址: https://atomgit.com/flow-example/spring-boot.git,点击确定。
切换流水线源
点击进入流水线页面,点击刚刚创建的流水线,然后点击【编辑】按钮,如下图所示
将之前的流水线源,删除掉如下图所示
然后点击【添加代码源】,将新建的codeup代码仓库添加进来,选择默认分支,点击【添加】按钮。如下图所示
2.YAML发布
修改代码
进入导入的代码库,修改src/main/java/com/example/demo/文件夹下的HelloController.java文件,做出如下图修改。
运行流水线
点击进入流水线页面,选择之前创建的流水线,点击【运行】按钮,如下图所示
运行成功后,通过下面的方式进行访问验证。
$ curl http://www.${HOST}
Greetings from Spring Boot! V5
3.镜像升级
应用场景:开发团队只负责完成代码开发,并通过流水线自动化完成应用镜像构建,并使用该镜像对集群中已有的应用进行升级。开发团队只关心应用的工作负载实例资源。
修改代码
进入导入的代码库,修改src/main/java/com/example/demo/文件夹下的HelloController.java文件,做出如下图修改。
编辑流水线
点击进入流水线页面,选择之前创建的流水线,点击【编辑】按钮,在Kubernetes发布任务中,点击删除按钮,如下图所示
然后点击【新的任务】按钮,选择如下图所示【Kubernetes镜像升级】任务。
在【Kubernetes镜像升级】任务中,选择相应集群、命名空间、应用类型、应用名称、容器名称、镜像地址,如下图所示。
点击【保存并运行】按钮,运行成功后,通过下面的方式进行访问验证。
$ curl http://www.${HOST}
Greetings from Spring Boot!V6
4.分批发布
应用场景:前两种策略主要是用的Kubernetes原生的发布策略RollingUpdate模式进行滚动升级,整个发布过程是不可逆的,假如认定当前发布出现了异常我们只能通过重新发布的方式来使应用回到可用状态。
而在云效的分批发布中,我们以Service为最小发布单元,在发布开始阶段我们将基于新版镜像创建出应用的版本V2,并根据当前应用的副本总数以及分批数量,对新旧两个版本的应用实例分别进行缩容和扩容,来控制实际进入到新版应用的流量比例,从而可以实现小规模的发布验证,在对发布进行充分验证后再逐步完全下线老版应用。同时批次之间支持暂停和手动恢复让用户可以充分对针对发布过程进行控制。
修改代码
进入导入的代码库,修改src/main/java/com/example/demo/文件夹下的HelloController.java文件,做出如下图修改。
编辑流水线
点击进入流水线页面,选择之前创建的流水线,点击【编辑】按钮,在Kubernetes镜像升级任务中,点击删除按钮,如下图所示
然后点击【新的任务】按钮,选择如下图所示【Kubernetes分批发布】任务。
在【Kubernetes分批发布】任务中,选择相应集群、命名空间、服务service、关联的应用类型、分批策略、分批数、容器名称、镜像地址,如下图所示。
点击【保存并运行】按钮,运行成功后,流水线会在第一批发布完成后暂停,如下图所示
进入阿里云容器服务控制台,点击相应集群,点击进入无状态工作负载,如下图所示,有两个不同容器组,每个容器组的数量是1。
通过下面的方式进行访问验证,会发现V6跟V7交替出现
$ curl http://www.${HOST}
Greetings from Spring Boot!V6
$ curl http://www.${HOST}
Greetings from Spring Boot!V7
此时用户可以在V7上进行验证,如果有问题,可以通过【回滚】按钮回退到V6版本,如下图所示
如果验证没有问题可以点击恢复按钮,将剩下的V6容器组升级到V7,如下图所示。
此时再次验证,会发现只有V7出现
$ curl http://www.${HOST}
Greetings from Spring Boot!V7
5.Ingress灰度发布
应用场景:相比于分批发布灰度发布更强调更加可控和安全的线上验证。在发布过程中我们希望能够通过cookie或者header的方式使得特定的用户或者开发人员,能够在线上对新版本引用进行验证,经过小部分可控的线上流量验证后,我们的发布可靠性更好,如果出现预期外的问题,也可以快速回滚,并且整个灰度验证过程对非灰度用户完全不可感知。
修改代码
进入导入的代码库,修改src/main/java/com/example/demo/文件夹下的HelloController.java文件,做出如下图修改。
编辑流水线
点击进入流水线页面,选择之前创建的流水线,点击【编辑】按钮,在Kubernetes分批发布任务中,点击删除按钮,如下图所示
然后点击【新的任务】按钮,选择如下图所示【Kubernetes Nginx Ingress 灰度发布】任务。
在【Kubernetes Nginx Ingress 灰度发布】任务中,选择相应集群、命名空间、Ingress名称、服务端口、应用端口、容器名称、镜像、灰度匹配方式、灰度匹配名称、灰度匹配值、灰度版本初始化流量权重,如下图所示。
点击【保存并运行】按钮,运行成功后,如下图所示
进入阿里云容器服务控制台,点击相应集群,点击进入无状态工作负载,如下图所示,有两个不同容器组,每个容器组的数量是2。
通过下面的方式进行访问验证,会发现只有V7出现
$ curl http://www.${HOST}
Greetings from Spring Boot!V7
我们通过浏览器进入如下页面,新增我们预设的Cookie,foo=bar,如下图所示
设置完成后,再次进行访问验证,会按照预设的灰度版本初始化的流量权重,如本案例设置的20%,显示V8,如下图所示。
此时用户可以在V8上进行验证,如果有问题,可以通过【回滚】按钮回退到V7版本,如下图所示
如果验证没有问题可以点击【完成】按钮,整体升级到V8。
此时再次验证,会发现只有V8出现
$ curl http://www.${HOST}
Greetings from Spring Boot!V8
五、结语
通过以上的操作流程,就可以建立起来一个协同多角色的流水线。接下来你可能想再了解其中的一些细节:
定制化代码扫描规则及定制化扫描及单元测试通过规则
如何添加非ACK的K8s集群