04.CICD实践
# 01.架构设计
- 流水线是把一个重复的过程分解为若干个子过程,使每个子过程与其他子过程并行进行的技术,也叫 Pipeline
# 1.0 介绍
自研的CI/CD流水线解决方案,打通了从需求管理到开发、测试、部署的整个持续交付过程
核心服务包括:流水线服务、发布平台、云原生流水线引擎、原子市场、代码检查、凭证管理等
使用微服务架构
- 服务层包括:前端服务、接口网关、后端服务、原子服务、存储层
- 微服务架构上主要选择:Nacos、Skywalking、ELK、Prometheus、SpringCloud Gateway网关、ETCD
# 1.1 接口网关
- SpringCloud Gateway 接口网关服务
- 动态路由
- 认证授权
- 服务限流熔断Sentinel
# 1.2 后端服务
Done(发布服务)
:打通从需求管理、开发、测试、预发、单台、灰度、多机房
整个持续交付过程- 策略配置、策略自由编排、组件重试、组件回滚、灰度部署、多机房滚动部署、流量摘挂、分支预合并、团队应用管理、权限管理
Process(流水线管理)
:负责管理流水线以及流水线编排调度功能的核心服务- Pipeline(流水线)、Stage(阶段)、Jobs(作业)、Task(任务)
Pipeline(云原生流水线服务)
:将原子能力融入到K8S服务中,实现资源动态扩展能力(go agent负责接收pipeline请求,处理服务)流程介绍
- 构建机是负责运行CI打包编译构建的一台服务器/PC,是由比如go,gcc,java,python,nodejs等等编译环境依赖
- 在集群中
部署一类原子插件服务
的一群机器定义为资源池
(比如:GO环境资源池有 Go1.17、JDK1.8.0、Node10.16等) - 传统资源池资源固定,扩容复杂,云原生流水线通过agent加载BPE环境,
将服务部署到K8S集群中,方便动态扩容
构建机介绍
- 构建机是负责运行CI打包编译构建的一台服务器/PC/容器,是由比如go,gcc,java,python,nodejs等等编译环境依赖
第一:调度服务功能
:权限管理、任务管理、任务调度
第二:PipelineAgent
:由Golang编写实现- Agent和原子插件同时编译到docker镜像里,通过k8s部署
- 虽然原子服务相同,编译环境依赖不同,所以不同资源池实现功能不同(比如go,java等等编译环境依赖)
- Agent核心功能
接受流水线任务调度(输入)
执行原子脚本(执行)
流水线运行状态,日志(输出)
第三:PipelineWorker
:- 由Groovy编写实现,是一个命名为agent.jar的文件,任务真正的执行者
- 被PipelineAgent通过jre来拉起运行,之后会负责与Process(流水线管理)微服务模块通信
Log(构建日志服务)
:负责接收构建的日志的转发存储和查询输出(订阅kafka获取任务状态变化和实时日志)Ticket(凭证管理服务)
:存储用户的凭证信息,比如代码库帐号密码/SSL/Token等信息Artifactory(制品构件服务)
: 该服务存储过程中制品信息(oss构建产物、Harbor镜像等)Store(原子市场)
:负责管理流水线原子插件Dispatch(构建机调度)
: 负责接收流水线的构建机启动事件,分发给相应构建机处理
# 1.3 存储层与架构
MySQL
:弹性数据库,存储所有关系型数据Redis
:缓存构建机信息和构建时的信息和提供分布式锁操作等等Kafka
:核心消息队列服务,推送流水线状态变化和流水线日志等RabbitMQ
:作为异步任务分发队列OSS云存储
:编译产物、图片、视频等Harbor
:docker镜像存储ElasticSearch
: 日志存储,log模块对接ES来对构建的日志做存取ETCD
:服务注册、发现、配置管理、负载均衡微服务相关
SpringCloud Getaway
:动态路由SSO
:认证授权Sentinel
:服务限流熔断Ribbon
:负载均衡Nacos
:服务注册、服务发现、配置管理Skywalking
:链路追踪Prometheus
:服务监控ELK
:日志存储分析
# 1.4 原子服务
代码类
:下载代码、分支合并构建类
:Go编译、JAVA编译、Golang编译、Android编译、IOS编译、NodeJS编译、GCC编译等质量类
:EOS扫描、SonarQube测试类
:JaCoCo代码覆盖率测试、单元测试、Java接口测试部署类
:文件部署、JDos部署、JDos构建镜像、NP网路平台、Django部署安全类
:应用安全检查、IOS资源文件分析、Android安全加固通知类
:咚咚通知自定义类
:自定义脚本、插入环境变量
# 1.5 Agent(构建机)
流程介绍
- 构建机是负责运行CI打包编译构建的一台服务器/PC,是由比如go,gcc,java,python,nodejs等等编译环境依赖
- 在集群中
部署一类原子插件服务
的一群机器定义为资源池
(比如:GO环境资源池有 Go1.17、JDK1.8.0、Node10.16等) - 传统资源池资源固定,扩容复杂,云原生流水线通过agent加载BPE环境,
将服务部署到K8S集群中,方便动态扩容
构建机介绍
- 构建机是负责运行CI打包编译构建的一台服务器/PC/容器,是由比如go,gcc,java,python,nodejs等等编译环境依赖
PipelineAgent:由Golang编写实现
- Agent和原子插件同时编译到docker镜像里,通过k8s部署
- 虽然原子服务相同,编译环境依赖不同,所以不同资源池实现功能不同(比如go,java等等编译环境依赖)
- Agent核心功能
接受流水线任务调度(输入)
加载执行原子脚本(执行)
流水线运行状态,日志(输出)
PipelineWorker:
- 由java编写实现,是一个命名为agent.jar的脚本文件,任务真正的执行者
- 被PipelineAgent通过jre来拉起运行,之后会负责与Process(流水线管理)微服务模块通信
# 02.云原生流水线调度
# 2.1 云原生调度流程
1)
服务编排
在前端配置流水线执行流程2)将流水线流程配置存储到bb服务端(MySQL)
3)bb服务端将任务派发到 云原生流水线服务
- api流水线管理接口(json)
- 权限管理
- 任务管理
- 任务调度
4)云原生流水线服务负责
接收任务请求,任务管理、任务调度
云原生流水线在 redis中维护任务
- 第一:全局队列 list 存放所有待执行任务
- 第二:使用 Hset 有序集合作为 加权任务队列
- 第三:使用 Hash 字典存放正在执行的任务(对超时任务处理)
5)Go Agent
流水线Excutor
Agent核心功能
接受流水线任务调度(输入)
执行原子脚本 .jar(执行)
流水线运行状态,日志(输出)
第一种:使用时创建和销毁(方便用户可以在任意mac机中运行)
- Agent是一个Go服务,部署到k8s集群的pod节点中
- 在创建pod节点时会指定agent拉取对应的原子代码
pod中agent启动后会定时拉取任务,执行,执行完成后主动销毁
- 注:pod节点在创建后会返回当前pod的 container名字,可以通过这个名字来访问容器执行
第二种:Agent资源资源注册到ETCD中
- Go Agent根据环境不同,打包成不同docker镜像(比如:
服务端通用资源池
、特殊服务资源池)- 服务端通用资源池 包括(Go、Node、JDK、Maven、Node、Ant、Gradle)等
- 同一类资源服务使用相同名称注册到etcd中作为作为微服务,提供不同类型原子服务
- 流水线
任务调度
可以根据任务请求
中携带的资源标识从etcd中获取对应的ip和端口进行服务调用 - 服务调用后状态被设置为进行中,并将处理任务的 ip:port 服务一同记录到redis的Hash字典中,以便主动进行任务状态查询
- Go Agent根据环境不同,打包成不同docker镜像(比如:
注:使用时创建和销毁弊端
高频使用的流水线,频繁创建销毁,浪费资源、消耗时间
不利于
代码编译和镜像构建的缓存复用
(通过hostPath Volume在宿主机挂载并缓存,平均提速3~5倍)
# 2.2 缓存支持
- https://cloudnative.to/blog/cloudnative-devops/
缓存作用
- 缓存加速:自研容器化流水线的缓存技术,通过
代码编译和镜像构建的缓存复用
,平均加速流水线3~5倍; - 细粒度缓存配置:任一阶段、步骤可以控制是否开启缓存及缓存路径;
- 可视化编辑界面,灵活配置流水线;
实现方案
云环境下的流水线是通过启动容器来运行具体的功能步骤,每次运行流水线可能会被调度到不同的计算节点上
这会导致一个问题:容器运行完是不会保存数据的,每当流水线重新运行时,
又会重新拉取代码、编译代码、下载依赖包
等等失去了
本地宿主机编译代码、构建镜像时缓存的作用
,大大延长了流水线运行时间,浪费很多不必要的时间、网络和计算成本等为了提高用户使用流水线的体验,加入支持缓存的功能,采用了k8s挂载hostPath Volume方式。
当流水线运行时我们会记录当前运行节点,下次运行时通过设置Pod的亲和性优先调度到该节点上
随着流水线运行次数越来越多,我们会得到一个运行节点列表。