博客列表
/

Choerodon猪齿鱼 Agent——基于GitOps的云原生持续交付模型

Choerodon猪齿鱼 Agent——基于GitOps的云原生持续交付模型

作者:李佳桐 全部标签: 技术类
2019年01月08号

概述

Choerodon Agent是支撑Choerodon平台持续交付部署流水线的一个核心组件,负责将平台生成的部署文件应用到应用部署环境对应的Kubernetes集群之中。并实施返回各个应用实例以及应用实例下所有资源的最新状态信息,同时通过监听各个环境对应的部署文件Git库,执行CD操作。而且支持混合云以及多云作为平台的部署环境,通过返回回来的容器信息和反馈回来各个实例下的容器,还可以实时获取容器日志,以及容器exec执行远程命令。

Choerodon持续交付可以支持任意数量的集群加入平台,作为应用的部署环境,只要将平台中生成的Agent安装脚本在任意Kubernetes集群中执行,就可以将该集群加入平台,然后在平台上创建环境时可以选择该集群,可以一键创建环境。在同一个集群中可以创建多个环境,各个环境之间通过Kubernetes的命令空间隔离。

平台初始化部署集群只需要将平台生成的Agent安装脚本在Kubernetes环境中执行。Agent在集群中安装之后便可以在该集群中创建环境。作为项目应用的部署环境。

创建集群之后,平台会提供一份激活指令,将指令粘贴至Kubernetes集群中执行,成功后集群就连接成功了。在平台的界面上集群显示的状态也为运行中。下图所示脚本就是Agent的激活指令。

helm install --repo=http://chart.choerodon.com.cn/choerodon/c7ncd/ \
--namespace=choerodon \
--name=choerodon-cluster-agent-test \
--version=2018.12.10-112732-master \
--set config.connect=ws://devops.com.cn/agent/ \
--set config.token=dccf4539-43e7-4970-a2d4-271267850d67 \
--set config.clusterId=21 \
--set config.choerodonId=434ha8v7sz90 \
--set rbac.create=true \
choerodon-cluster-agent

集群连接成功之后,可以在环境流水线管理界面,选择相应的集群一键创建环境。创建环境时,平台会给Agent发送一条指令,让Agent创建相应命令空间,并拉去初始化环境对应的Git库,开始准备同步。

环境创建成功之后相关持续交付的部署操作即可选择该环境作为目标环境,进行应用部署,网络、域名、证书的创建。所有操作都将发送至Agent由Agent执行,所对应资源对象状态的变更也有Agent传输回来,进行实时展示。

实现分析

基于以上的这些功能目标,而且考虑到Choerodon Agent作为一个连通持续交付平台和Kubernetes集群的代理客户端,需要具备实时性、稳定性和高性能,所以决定用go语言实现,充分利用go轻量高效的特性。使用go作为开发语言,可以便捷的使用client-go,helm client等现成工具库开发CD相关操作。由于需要实时监听,实时反馈,等特性,Agent与DevOps之间的交互采用WebSocket长连接。并且使用客户端的方式,不提供对外暴露访问接口,充分保证安全性而且不需要集群提供对外暴露访问接口。

用户在平台中创建环境时同时会创建一个与环境对应的Git仓库用来存放部署配置文件,之后所有在环境中部署相关操作,都会转化为Git库中部署配置文件的操作,用户在平台界面操作部署或者直接推送部署文件至Git库都会触发Git库配置的Webhook,之后继续交付微服务拉取最新提交,解析并生成tag,然后通知环境客户端去执行环境对应Git库中最新的变更。环境客户端收到持续交付服务通知后,执行最新一次的tag,执行完毕后生成执行tag,当环境的最新提交Commit sha,与持续交付服务解释tag的sha,与环境客户端执行的tag sha一致时,表示最新的操作或者提交都已经应用到环境。

  1. 用户可以通过直接向Git库提交和在界面上进行相关部署操作,在GitOps中,界面上进行的部署操作都会先直接修改环境对应的部署文件Git库。例如一个应用实例版本更新部署操作对应在部署文件中的提交如上图。

  2. 部署文件Git库产生提交后,git库中的webhook随机触发,将变更发送至DevOps服务

  3. DevOps服务拉取库中最新提交,与上一个tag版本进行比较,根据比较结果分别生成创建、更新、删除记录,重新生成tag。

  4. 通知对应环境Agent拉取DevOps服务最新解析tag。

  5. Agent从部署库中拉取最新DevOps解析tag。

  6. 并根据部署库文件,与环境中真实部署的对象列表进行比较,然后在环境执行创建、更新、删除操作。执行完成后将执行结果发回至DevOps服务。

具体设计

Choerodon Agent通过WebSocket Client与外部的猪齿鱼部署服务进行连接、执行命令等交互。内部通过Helm客户端与Kubernetes集群。

内部的tiller server执行Chart安装删除等操作,并且通过Kube Client直接对Kubernetes各种资源对象进行操作,监听各资源对象的状态变更。

通过长连接及时通知部署服务。Choerodon Agent和部署服务之间的交互采用Command/Response模式,启动时立即向部署服务建立连接,接收Command执行并返回结果Repsonse。作为WebSocket Client将Command通过Channel不断的发送至执行器,执行器Worker是一个可伸缩配置的工作线程/协程池,执行后将结果通过Channel给Websocket Client写回。具体实现可主要分为如下几个主要功能块。

建立连接初始化信息

Agent启动时立即与DevOps服务建立WebSocket长连接,通过Websocket Client立即与DevOps服务建立WebSocket长连接,连接成功之后,DevOps服务集群的初始化信息从WebSocket发送至Agent、Agent根据初始化信息,启动Controller监听对应的命名空间,对集群下的每个GitOps环境库启动Git库同步程序。初始配置信息包含对各个环境Git库的SSH配置,如下所示。

 Host c7n-agile-prod
   HostName code.choerodon.com.cn
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   IdentityFile /rsa-c7n-agile-prod
   LogLevel error
 Host c7n-tm-prod
   HostName code.choerodon.com.cn
   StrictHostKeyChecking no
   UserKnownHostsFile /dev/null
   IdentityFile /rsa-c7n-tm-prod
   LogLevel error

Command/Response模式

Agent不断从长连接中读取命令,也不停的从Channel中读取返回结果写至长连接中,命令解析出来之后通过Channel发送至Worker,然后在Worker中通过K8S Client或者Helm Client执行相应命令。执行成功之后将结果再通过Channel发回至 Agent Websocket Client,Client将结果通过长连接发送回DevOps。

实时状态反馈

通过Controller机制监听实例下的各个Kubernetes资源对象、只要有对象创建、更新或者删除、Controller中就会监听到,在Controller监听到对应的资源对象之后,判断,并实时反馈传输回DevOps服务。

func NewpodController(podInformer v1_informer.PodInformer, responseChan chan<- *model.Packet, namespaces *manager.Namespaces) *controller {
   c := &controller{
      queue:            workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "pod"),
      workerLoopPeriod: time.Second,
      lister:           podInformer.Lister(),
      responseChan:     responseChan,
      namespaces:        namespaces,
   }

  podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
      AddFunc: c.enqueuepod,
      UpdateFunc: func(old, new interface{}) {
         newpod := new.(*v1.Pod)
         oldpod := old.(*v1.Pod)
         if newpod.ResourceVersion == oldpod.ResourceVersion                 {        return
         }
         c.enqueuepod(new)
      },

      DeleteFunc: c.enqueuepod,
   })
   c.podsSynced = podInformer.Informer().HasSynced
   return c

}

Helm Operator

将Chart应用实例通过K8S自定义对象描述出来,执行创建或者修改实例时候,先创建相应实例对应的文件或者修改应用实例在Git库中对应的文件,Controller中监听到这些文件的变化之后在通过文件执行相应的Install或者Upgrade操作。保证环境中实例的状态与描述文件的状态一致。

---
apiVersion: choerodon.io/v1alpha1
kind: C7NHelmRelease
metadata:
  name: choerodon-front-devops-5c483
spec:
  chartName: choerodon-front-devops
  chartVersion: 0.11.0
  repoUrl: http://chart.choerodon.com.cn/choerodon/c7ncd/
  values: |-
    env:
      open:
        PRO_HEADER_TITLE_NAME: Choerodon1

GitOps

在GitOps中针对每个环境,在Agent初始化之后,将各个环境Git库SSH配置创建出来、并将Git库通过SSH拉至本机,检测是否有权限创建和删除tag,定时拉取最新的提交、同时在收到DevOps服务执行指令后,将最新的提交版本中的所有K8S资源文件执行至环境对应的命令空间之中。

状态同步与修复

由于Agent和DevOps服务之间连接交互采用长连接,可能出现由于网络或者其他原因导致消息丢失,从而产生预期与实际的状态不一致。所以增加了状态同步和修复的机制。保证一致性。当网络连接断开重新连接之后,各个Controller重新同步各类Kubernetes资源,使DevOps服务中各类资源对象的状态与实际情况保持一致,避免环境中的各实例资源状态与平台中展示的不一致.同时Devops服务会定时将一些超过一段时间还处于中间状态的对象发送至DevOps服务查询状态。如果中间Agent发给DevOps的部分消息丢失或者处理失败,造成一些不一致的状态,会通过这个状态修复功能将该对象的状态修复正常,以保证两边的资源状态一致性。

Log和Exec长连接

Agent从长连接中收到Log或者Exec请求指令后,建立一个Pipe,通过K8S Client Log或者Exec相关Api建立与Api Server的长连接,同时通过WebSocket Client 向DevOps请求建立一个长连接,通过这个Pipe中转打通两个长连接。从而实现Log和Exec长连接的中转代理。

总结

Choerodon Agent 自发布以来,经历了一系列优化与改进,不管是易用性还是稳定性都在不断提升,例如应用Chart模板中的资源对象将不用再预先插入平台所需要的标签,每个环境一个Agent客户端改成了一个集群一个客户端。增加了定期同步各资源状态的逻辑,有效地消除了平台中与集群的K8S资源状态的不一致,GitOps流程也越来越稳定。同时也感谢社区的朋友们反馈的一些Bug和建议,一起为产品完善而努力。

关于猪齿鱼

Choerodon 猪齿鱼是一个开源企业服务平台,基于 Kubernetes 的容器编排和管理能力,整合 DevOps 工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理的开源平台,同时提供 IoT、支付、数据、智能洞察、企业应用市场等业务组件,致力帮助企业聚焦于业务,加速数字化转型。

大家也可以通过以下社区途径了解猪齿鱼的最新动态、产品特性,以及参与社区贡献:

作者:李佳桐

出处:Choerodon

欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。