如何通过云效实现K8s持续部署

本文以Java应用为例为您介绍如何通过云效flow流水线配置实现应用快速构建、持续部署与交付。

背景信息

云原生浪潮中,如何基于云原生架构快速实现K8s应用部署交付越发的优势。相较于传统部署方式,Kubernetes可以快速便捷的针对场景对服务进行扩缩容版本迭代,通过自动化一键打包做到应用容器化部署,跨环境轻松地保证其一致性;面对基础设施的挑战,服务Pod凭借智能自愈,自动创建迁移,无需人工干预等场景;并且以容器为单位对应用资源进行精细调控,极大的提高了资源利用率。

解决方案

使用阿里云云效Flow流水线和K8s资源的结合,为应用的持续交付提供了很好的基础保障,大致可分为3步,如下:高的 (51).png

  1. 开发者提交代码变更:开发者将代码变更提交到代码仓库,例如,使用git push命令将代码推送到远程仓库。

  2. 代码库变更监测:云效通过Webhook监听代码仓库的变更事件,一旦检测到代码提交,自动触发持续部署流水线。

  3. 持续部署流水线:代码检查,执行静态代码分析,确保代码质量;

    使用Dockerfile构建应用镜像,将构建好的Docker镜像推送到镜像仓库(如阿里云容器镜像仓库);

    使用自动化流水线部署应用到测试环境;

    执行自动化测试用例,确保应用功能正常;

    使用自动化流水线部署发布应用到生产环境。

前提条件

  • 注册阿里云账号或RAM账号。

  • 准备阿里云ACK集群,创建方式请参考创建ACK托管集群

  • 准备一个已备案的域名,通过域名路由Ingress访问后端服务。

  • 容器服务ACK集群安装Nginx Ingress Controller组件

  • 准备阿里云镜像仓库ACR。为了能够快速的拉取镜像,建议将ACK集群与ACR放在同一地域,如本例中的华东1(杭州),这样后续在进行Kubernetes部署的时候,我们可以选择镜像VPC地址。若不在同一地域,请选择镜像公网地址。创建方式请参考创建个人版实例

场景案例

说明

本文通过一个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。

调用关系如下:

image

操作步骤

步骤一:创建流水线

  • 进入云效工作台,在云效产品选择流水线

    高的 (59).png

    • 在流水线Flow页面新建流水线,通过流水线模板,单击可视化编排 > Java > Java·测试、构建镜像,发布到Kubernetes集群/阿里云容器服务为例,完成创建。

      高的 (55).png

步骤二:添加流水线源

创建流水线之后,添加流水线源 > 代码源 > 示例代码源,此处以Java代码类型为例,完成添加,其它参数默认会自动填写到表单中。

高的 (40).png

步骤三:配置镜像构建任务

  • 单击Java构建Docker镜像并推送镜像仓库设置相关参数,如下图所示。高的 (41).png

    参数

    描述

    添加服务连接

    服务连接即凭证,用于连接RAM用户与容器镜像服务(ACR)之间的授权。

    地域

    指创建的容器镜像服务(ACR)所在的开服地域

    仓库

    创建镜像仓库,用于存储流水线构建镜像制品的上传与拉取仓库地址。

    标签

    ${DATETIME},表示以流水线触发时的时间戳为例作为镜像的标签,很多企业习惯将分支名或者tag作为镜像的标签,云效也是支持的,详情参考环境变量

    • Dockerfile路径指案例的代码仓库路径,即文件名称Dockerfile2 ,如下图所示。

      高的 (43).png

    • 任务输出是添加构建镜像阶段自动生成的,变量可以在后续的任务中引用。

      说明

      关注其中的第二个和第三个变量即可,其中第二个是该镜像地址的公网地址,第三个是该镜像地址的VPC地址。这里推荐将镜像仓库和ACK集群放在同一个地域,然后在后续的部署任务中选择VPC地址,以加速部署过程。

      高的 (45).png

步骤四:配置部署任务

  • Kubernetes发布配置,在集群连接右侧单击新建连接,创建阿里云Kubernetes集群服务与RAM用户的服务连接。创建保存之后,选择对应的服务连接信息。

    高的 (64).png高的 (47).png

    说明

    不同企业资源互通:云效支持不同企业资源在同一账号下进行使用,具体参考链接授权管理—添加多个阿里云账号的授权服务

  • 配置YAML路径:示例中YAML路径为:app-configs/manifest-app。

    高的 (49).png

  • 添加变量,本案例配置的自定义参数变量如下。

    变量

    描述

    IMAGE

    指变量的镜像地址IMAGE,选择“镜像构建并推送至阿里云镜像仓库个人版.镜像公网地址” 或 “镜像构建并推送至阿里云镜像仓库个人版.镜像VPC地址”作为变量值。

    HOST

    指路由Ingress规则中定义的host映射的域名,通过域名链路到路由访问不同的后端服务。Ingress 定义host可以简化配置,具体操作,请参见创建Nginx Ingress

    • 添加变量 IMAGE,如下图所示。高的 (58).png案例代码库中的app.yaml文件内容如下,在运行时Flow路径下YAML文件中 ${IMAGE} 变量以及引用的参数变量会被渲染成真实的镜像地址,通过拉取仓库镜像完成kubectl发布。

      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
              ports:
              - containerPort: 8080
    • 添加变量 HOST,进入目标集群网络 > 路由复制规则中的域名。

      高的 (50).png

      添加自定义参数变量 HOST,如下图所示。

      高的 (60).png

      参考案例代码库Ingress.yaml文件修改内容如下,其中的${HOST}变量会被渲染替换成真实的测试请求地址。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: spring-boot-ingress
        namespace: default
      spec:
        rules:
        - host: ${HOST}
          http:
            paths:
            - path: /foo
              pathType: ImplementationSpecific
              backend:
                service:
                  name: spring-boot-sample
                  port:
                    number: 8080

步骤五:运行流水线

配置完毕,单击保存并运行,运行流水线。

高的 (61).png

由于在manifest中包含了ingress配置,因此可以通过ack规则的ingress绑定的域名访问服务,在浏览器中输入地址 http://${HOST}进行验证,也可以在Shell命令行中进行验证。

curl http://${HOST}
#Greetings from Spring Boot!V4

步骤六:镜像升级发布

  1. 新建云效仓库:单击代码管理进入云效Codeup页面,单击导入代码库,将案例代码导入到云效代码库。

    高的 (2)

    单击URL导入,在源代码库地址框中输入案例代码库地址,单击确定。

    高的 (33).png

  2. 切换流水线源

    1. 进入流水线页面,编辑步骤一:创建流水线,如下图所示。

      高的 (63).png

    2. 删除之前的流水线源,如下图所示。

      高的 (40).png

    3. 然后单击添加流水线源,将新建的Codeup代码仓库添加进来,选择默认分支,单击添加,如下图所示。

      高的 (41).png

  3. YAML 发布

    1. 修改代码:进入导入的代码库,修改 src/main/java/com/example/demo/ 文件夹下的HelloController.java 文件,做出如下图修改。

      高的 (32).png

    2. 运行流水线:单击左上角我的流水线,找到目标流水线,单击运行,如下图所示。

      高的 (42).png

    3. 访问验证:运行成功后,通过下面的方式进行访问验证。

      $ curl http://${HOST}
      #Greetings from Spring Boot! V5
  4. 镜像升级

    1. 应用场景:开发团队只负责完成代码开发,并通过流水线自动化完成应用镜像构建,并使用该镜像对集群中已有的应用进行升级。开发团队只关心应用的工作负载实例资源。

    2. 修改代码:进入导入的代码库,修改 src/main/java/com/example/demo/ 文件夹下的 HelloController.java 文件,做出如下图修改。

      高的 (29).png

    3. 编辑流水线

      单击左上角image然后单击流水线,进入流水线页面,选择之前创建的流水线,单击编辑,在Kubernetes发布任务中,单击删除,如下图所示。

      image

      然后单击新的任务,选择如下图所示Kubernetes镜像升级任务。

      image

      Kubernetes镜像升级任务中,选择相应集群、命名空间、应用类型、应用名称、容器名称、镜像地址,如下图所示。

      高的 (62).png

      单击保存并运行,运行成功后,通过下面的方式进行访问验证。

      curl http://${HOST}
      #Greetings from Spring Boot!V6
  5. 分批发布

    1. 应用场景:前两种策略主要是用的Kubernetes原生的发布策略RollingUpdate模式进行滚动升级,整个发布过程是不可逆的,假如认定当前发布出现了异常我们只能通过重新发布的方式来使应用回到可用状态。

      而在云效的分批发布中,我们以Service为最小发布单元,在发布开始阶段我们将基于新版镜像创建出应用的版本V2,并根据当前应用的副本总数以及分批数量,对新旧两个版本的应用实例分别进行缩容和扩容,来控制实际进入到新版应用的流量比例,从而可以实现小规模的发布验证,在对发布进行充分验证后再逐步完全下线老版应用。同时批次之间支持暂停和手动恢复让用户可以灵活对发布过程进行控制。

      image

    2. 修改代码

      进入导入的代码库,修改 src/main/java/com/example/demo/ 文件夹下的HelloController.java 文件,做出如下图修改。

      高的 (27).png

    3. 编辑流水线

      单击左上角image流水线,进入流水线页面,选择之前创建的流水线,单击编辑,在Kubernetes镜像升级任务中,单击删除,如下图所示。

      高的 (52).png

      然后单击新的任务,选择如下图所示Kubernetes 分批发布任务。

      高的 (54).png

      Kubernetes 分批发布任务中,选择相应集群、命名空间、服务Service、关联Workloads类型、分批策略、分批数、容器名称、镜像地址,如下图所示。

      高的 (55).png

      单击保存并运行,运行成功后,流水线会在第一批发布完成后暂停,等待发布第二批,如下图所示。

      高的 (51).png

      进入阿里云容器服务控制台,单击目标集群,进入无状态工作负载,如下图所示,有两个不同容器组,每个容器组的数量是1。

      高的 (56).png

      通过下面的方式进行访问验证,会发现V6与V7 交替出现。

      curl http://${HOST}
      #Greetings from Spring Boot!V6
      curl http://${HOST}
      #Greetings from Spring Boot!V7

      此时用户可以在V7上进行验证,如果有问题,可以通过【回退发布】按钮回退到V6版本,如果没有问题可以单击按钮【继续发布】,如下图所示。高的 (65).png

常见问题

  1. 如何解决集群版本不支持extensions/v1beta1问题?

    问题描述:Kubectl发布部署,Kubernetes 集群版本不支持extensions/v1beta1,失败提示:

    "no matches for kind "Ingress" in version "extensions/v1beta1"

    解决方案:公共案例代码库ingress.yaml文件中配置的Kubernetes集群版本与当前使用的集群版本不匹配,具体解决方案请参考1.19及之后版本集群更新Ingress.yaml参数值apiVersion: networking.k8s.io/v1

  2. 镜像仓库拉取容器镜像失败如何处理?

    问题描述:Kubectl发布,镜像仓库拉取容器镜像失败,事件日志如下:

    Error:ImagePullBackOff,Failed to pull image "registry.cn-hangzhou.aliyuncs.com/xxxx/xxxxxx:tag": failed to pull and unpack image "registry.cn-hangzhou.aliyuncs.comxxxx/xxxxxx:tag": failed to resolve reference "registry.cn-hangzhou.aliyuncs.com/xxxx/xxxxxx:tag": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed

    解决方案:安装免密组件,创建配置项,详细请参考使用免密组件拉取容器镜像

相关文档

Java 构建部署到 ACK 或自建 K8s 集群

基于nginx ingress+云效Appstack实现灰度发布