基于Pipeline的CI/CD在趣头条的应用实践
在今天的趣头条,随着业务需求的快速增长,部署与扩容的需求也越来越多,为更快的响应业务需求,业务容器化也随之加速。本次分享主要介绍在此业务场景下,部署在ECS的服务如何进行容器化的快速接入,使用基于Pipeline的Jenkins实现流程控制及部署,并动态的适配多环境与多集群。
CI/CD 作为业务自动化部署流水线的重要一环,在容器化快速及频繁发布的需求下,迎来了新的挑战。传统项目中,使用Shell或Pipeline脚本,将编译好的代码上传至服务器并启动就算完成了,而在容器环境中,则涉及到更为复杂的流程。
流程概览
在初期,CI究竟是使用基于Shell的自由风格任务还是基于Pipeline的任务,做个简单对比来看看:
Shell | Pipeline | |
缺点 | 单个任务流程不能并行处理任务无法分解至多个节点执行 | 初期有一定学习成本需要从头编写Groovy脚本 |
优点 | 上手简单对于运维无门槛有大量Shell脚本可以复用 | 任务可以按阶段分解至不同节点执行且可并行处理友好的可视化流程图 |
基于以上,最终还是选择了已当前流行的Pipeline为主要任务类型,并据此重新设计了任务流程。看图:
代码:
#! /usr/bin/env groovy
def Controller(){ Init.ExtraSettings()
node(NODE_STAGE_INIT) { stage('Stage 1: Pre-Process') { // Fetch data from CMDB CMDB.FetchConfig()
if (APP_LANG in APP_LANG_NO_COMPILE) { NODE_STAGE_BUILD = "master" } else { NODE_STAGE_BUILD = APP_LANG } } }
node(NODE_STAGE_GIT) { stage('Stage 2: Checkout & SonarQube') { Git.Controller()
// SonarScanner Init.SonarAnalyzer() } }
node(NODE_STAGE_BUILD) { stage('Stage 3: Build Project') { // Compile Compile.Controller() } }
if ( BUILD_LEGACY == false ) { node(NODE_STAGE_DOCKER) { stage('Stage 4: Build Image') { // Build & Push Docker image Docker.Controller() } }
node(NODE_STAGE_K8S) { stage('Stage 5: Deploy to k8s') { k8s.Controller() } }
next_stage_id = 6
} else { // 兼容发布至非容器环境 node(NODE_STAGE_BUILD) { stage('Stage 4: Deploy') { Deploy.Legacy() } }
next_stage_id = 5 }
node(NODE_STAGE_INIT) { stage("Stage $next_stage_id: Post-Process") { // Report Notice.Report()
// Automatic Test } } }
return this- Code stages.groovy
对每一个关键步骤都设置一个开关,便于调试的同时也更大的增加灵活性。
// TriggersSKIP_DOCKER = falseSKIP_KUBE = falseSKIP_COMPILE = falseSKIP_GIT = falseSKIP_TEST = falseSKIP_SONAR = trueSKIP_REPORT = false
可以在任务配置中通过定义变量来改变行为。
任务配置
每一个任务都可以通过变量进行定义,可接受的变量及其作用如下:
是不是非常复杂?看一眼实际任务配置:
任务的配置在开始构建时从CMDB获取,但实际工作中总会有一些看似比较合理的需求需要能支持,因此可以在任务配置中定义变量来覆盖CMDB的配置,如下图:
现在,新建Jenkins任务就非常容易了,模块化的函数配合灵活的变量定义,可以轻松应对大部分需求。
Stage 1:Pre-Process
获取项目配置
项目配置信息直接写在Jenkins任务配置里简单方便,但项目变多时配置维护就变得复杂了,因此需要集中统一管理配置,方便维护的同时,也能将配置权限下放至项目开发者,配置变更也能更快速。
在每次构建的时候才去获取配置,确保拿到最新配置。
拿到配置后,使用readJSON将配置解析为相关变量供后续流程使用。
权限控制
Jenkins内置有多个权限控制方式,但在多项目+多用户下进行权限控制时,情况就变复杂了,其实也不算特别复杂,就是需要勾太多框框,随着项目与用户增多,难度呈指数级上升。
因此,在设计流程时,就完全抛弃了Jenkins内置的那几套,基于CMDB/GitLab进行权限控制,一个很简单的思路:
如果你没权限访问代码,那么你可能也不能发布我的项目
权限检查在任务预处理阶段进行,不通过则直接终止任务
简单方便易于实现(且又能少只锅)
Stage 2:Checkout & SonarQube
Checkout
初始化,项目第一次构建自动进行初始化操作
检查
检查Git Repo是否为空
检查是否选择了版本
检查是否需要在指定目录下进行Checkout
检查发布环境与代码版本规则是否匹配
最后,输出代码相关信息,方便事后追溯
SonarQube
SonarQube是一个开源的代码质量管理系统,支持25+种语言,可以通过使用插件机制与Eclipse和Jira等其他外部工具集成,从而实现了对代码的质量的全面自动化分析和管理。
集成
SonarQube与Jenkins集成也非常简单,构建时根据当前项目生成配置,再调用SonarScanner就行。
权限控制
SoanrQube中默认情况下用户可以看到所有项目,且可查看源码,这肯定不是我们所期望的,因此也需要进行权限控制,这个思路同上面Jenkins的权限管理一致,依据代码库权限进行控制。
Stage 3:Build Project
这里比较简单,根据项目语言(APP_LANG),自动匹配相关节点进行构建。
PHP项目,如检测到项目根目录存在composer.json则调用compoer install
NodeJS项目,如未提供编译命令(BUILD_COMMAND),则执行默认指令(npm i)
GoLang项目,如未提供编译命令(BUILD_COMMAND),则执行默认指令(make)
Stage 4:Build Image
终于跟容器有点关系了!
是不是很简单?
确实很简单:
查找并模版文件
在模版文件基础上加入项目信息,如
项目代码
为满足稀奇古怪的需求而特设的指令
Build image
Push image
看到这里,也许你会明白为何不用插件非要不自量力的自己实现。
Stage 5:Deploy to Kubernetes
部署至Kubernetes相对简单多了,替换deployment.yaml文件, apply 一下就完了。
不信看这里:
等等,注意CronJob函数,难免会有些项目需要利用CronJob完成一些定时任务。
需求多的时候,CronJob的管理相当麻烦为了(偷懒)减少不必要的麻烦,我们针对业务需求写了个小函数(CronJob)自动化处理定时任务。
开发者在自己项目中提供一个文件,命名为 cronjob.json,在项目发布时,Pipeline检测到这个文件即进行处理,文件格式大致如下:
[{"id":0, "time": "00 01 * * *", "name": "test-task", "command": "echo 'hello world'", "description": "Hello world", "notify": "user1@abc.com|user2@abc.com", "when": "failure"}]
id为编号,从0开始,必填重要项
time为执行任务时间,标准Cron格式
name为计划任务名称,应与项目相关
command为要执行的命令
description为备注信息
notify为接收通知者邮件地址,多个之间加 '|', 企业微信发送
when为发送消息的条件:
always
never
failure
success
为避免任务失败后循环执行,所有失败的任务都会先发送失败消息然后再以成功状态结束。
如此,计划任务管理在Kubernetes这部分基本无须人工干预了。
Q&A
Q:生成新的镜像怎么自动打新的tag?A:我们镜像Tag使用本次构建选定的Git版本,如分支名称或者Tag。
Q:你们的Jenkins实例有多少,Jenkins实例是怎么规划的?A:1个Master节点提供UI界面,几个Agent分别对应不同语言版本和不同环境Kubernetes集群,运行在容器中。规划就是按语言或版本分节点,按集群分节点(Agent)。
Q:Jenkins的权限控制能否再细化一下?A:我们这边权限实际上是在CMDB中完成的。构建时向CMDB发起查询请求,传递当前项目名称、选择的环境、用户名过去,CMDB判断当前用户是否有权限构建选定的环境,允许则返回项目配置信息,否则返回错误代码,这边收到后报错终止。
Q:SonarQube的权限控制及性能当面?A:权限控制使用SonarQube提供的API,将项目跟GitLab中相应项目权限匹配起来,GitLab中可以查看这个项目代码,那么SonarQube中就能看到这个项目结果和Code。
Q:Kubernetes的services.yaml文件在哪里管理?
A:deployment & service & configmap之类文件都是提供Git进行版本控制,针对语言有模版,构建时进行替换。
Q: 你们的Pipeline触发策略是什么样的?A:人工触发,因为有必须要人工选择的Git版本。为防止误发布,默认没有选定版本,不选则在预处理时报错终止。
Q:构建及部署都在容器中?要构建的文件或制品文件怎么存放与管理的?
A:Agent容器启动时挂载了一个目录,里面有全套附属文件及Jenkins home目录。build节点完成自己工作后,其它节点按需接手处理。
Kubernetes入门与进阶实战培训
本次培训包括:Docker介绍、Docker镜像、网络、存储、容器安全;Kubernetes架构、设计理念、常用对象、网络、存储、网络隔离、服务发现与负载均衡;Kubernetes核心组件、Pod、插件、微服务、云原生、Kubernetes Operator、集群灾备等,点击了解具体培训内容。
7月13日正式上课,点击阅读原文链接即可报名。
基于Pipeline的CI/CD在趣头条的应用实践相关推荐
- Jenkins X:基于Kubernetes的CI/CD平台
背景 Jenkins自动化服务器一直都是DevOps工具链的重要组成部分,并且已发展成为开源持续集成和持续部署(CI&CD)软件的领导者.据不完全统计,截至2019年6月,已有将近26万的Je ...
- 基于 Kubernetes 实现 CI/CD 配置
基于 Kubernetes 实现 CI/CD 配置 一.基本介绍 二.基于 Kubernetes 实现 CI/CD 配置 1.配置 GitLab 2.配置 Jenkins 3.实现 CI/CD 配置 ...
- winform 项目 发布后比本地运行慢_前端团队基于 GitLab CI/CD 的自动化构建、发布实践,快来学习吧...
在公司搭建内部 GitLab 平台后,前端活动项目从 SVN 迁移到 GitLab.本文介绍如何基于 GitLab CI/CD 实现自动化构建及发布. 在从 SVN 迁移到 GitLab 和接入 Gi ...
- 基于K8s的CI/CD自动化持续集成部署框架
文章目录 什么是CI/CD? 1 环境准备 2 组件部署 2.1 jenkins快速部署 2.2 gitlab快速部署 2.3 harbor快速部署 3 CI/CD交付 什么是CI/CD? CI/CD ...
- 【aws】ECS上构筑基于Concourse的CI/CD方案
Amazon Elastic Container Service (Amazon ECS) 是一项高度可扩展的快速容器管理服务,它可轻松运行.停止和管理群集上的容器.您的容器在任务定义中定义,用于运行 ...
- 实时平台在趣头条的建设实践
原创: 席建刚 本文由趣头条实时平台负责人席建刚分享趣头条实时平台的建设,整理者叶里君.文章将从平台的架构.Flink现状,Flink应用以及未来计划四部分分享. 一.平台架构 1.Flink 应用时 ...
- 基于docker的CI/CD
准备条件 使用docker的机器,添加用户时需要指定用户的uid : sudo groupadd -g 500 work && useradd -g 500 -u 500 work ...
- OpenShift 4 Hands-on Lab (8) 基于Gogs+Nexus+Sonarqube的Jenkins CI/CD Pipeline
<OpenShift 4.x HOL教程汇总> 说明:本文已经在 OpenShift 4.8 环境中验证(OpenShift 4.9 环境的 Jenkins 版本较新,编译 Java 报错 ...
- OpenShift 4之实现一个基于Gogs+Nexus+Sonarqube的Jenkins CI/CD Pipeline
OpenShift 4之实现一个基于Gogs+Nexus+Sonarqube的Jenkins CI/CD Pipeline 场景说明 运行环境 配置操作过程 准备运行所需资源 配置Gogs并导入应用代 ...
- 基于docker-compose的Gitlab CI/CD实践排坑指南
长话短说 经过长时间实操验证,终于完成基于Gitlab的CI/CD实践,本次实践的坑位很多, 实操过程尽量接近最佳实践(不做hack, 不做骚操作),记录下来加深理解. 看过博客园<docker ...
最新文章
- 天天用事务,但是你知道MySQL事务的实现原理吗?
- 杰奇数据库mysql_杰奇模板出现Unable to save result set in…可尝试修复数据库
- Caffe官方教程翻译(3):Siamese Network Training with Caffe
- 4.空悬指针和野指针
- JSF优点(转载自中国IT实验室)
- Ocelot简易教程(七)之配置文件数据库存储插件源码解析
- React setStats数组不更新,百思不得其解。
- 教你如何玩转GitHub
- docker-compose部署Minio
- 2018中国十大科技进展公布!两院院士投票,港珠澳大桥和天河三号上榜
- 发现TP5一个神奇的问题
- P2P技术简介(包括BT软件的分析)(转)
- 【F2FS LFS SSR】华为如何打造智能终端的有趣灵魂?(上)
- SQL Server 无法启动WMI服务
- Promise详解(resolve,reject,catch)
- BugKu-CTF(杂项misc)--YST的小游戏/easy_python
- python人工智能之:多边形矩阵热图程序实战篇(二)
- Bootstrap 教程第四课:制作一组功能图标按钮
- 说真的,喜欢偶尔这样的激情解说!
- 帝国CMS教程:ECMS(帝国CMS)搜索伪静态