Pipeline

Pipeline

基于Jenkins Pipeline自动化部署

尼古拉斯 发表了文章 • 0 个评论 • 345 次浏览 • 2019-06-05 23:53 • 来自相关话题

最近在公司推行Docker Swarm集群的过程中,需要用到Jenkins来做自动化部署,Jenkins实现自动化部署有很多种方案,可以直接在jenkins页面写Job,把一些操作和脚本都通过页面设置,也可以在每个项目中直接写Pipeline脚本,但像我那么追 ...查看全部
最近在公司推行Docker Swarm集群的过程中,需要用到Jenkins来做自动化部署,Jenkins实现自动化部署有很多种方案,可以直接在jenkins页面写Job,把一些操作和脚本都通过页面设置,也可以在每个项目中直接写Pipeline脚本,但像我那么追求极致的程序员来说,这些方案都打动不了我那颗骚动的心,下面我会跟你们讲讲我是如何通过Pipeline脚本实现自动化部署方案的,并且实现多分支构建,还实现了所有项目共享一个Pipeline脚本。
#使用Jenkins前的一些设置

为了快速搭建Jenkins,我这里使用Docker安装运行Jenkins:
$ sudo docker run -it -d \
--rm \
-u root \
-p 8080:8080 \
-v jenkins-data:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$HOME":/home \
--name jenkins jenkinsci/blueocean

初次使用Jenkins,进入Jenkins页面前,需要密码验证,我们需要进入Docker容器查看密码:
$ sudo docker exec -it jenkins /bin/bash
$ vi /var/jenkins_home/secrets/initialAdminPassword

Docker安装的Jenkins稍微有那么一点缺陷,shell版本跟CentOS宿主机的版本不兼容,这时我们需要进入Jenkins容器手动设置shell:
$ sudo docker exec -it jenkins /bin/bash
$ ln -sf /bin/bash /bin/sh

由于我们的Pipeline还需要在远程服务器执行任务,需要通过SSH连接,那么我们就需要在Jenkins里面生成SSH的公钥密钥:
$ sudo docker exec -it jenkins /bin/bash
$ ssh-keygen -C "root@jenkins"

在远程节点的~/.ssh/authorized_keys中添加jenkins的公钥(id_rsa.pub)。

还需要安装一些必要的插件:

  1. Pipeline Maven Integration
  2. SSH Pipeline Steps

安装完插件后,还需要去全局工具那里添加Maven:
1.png

这里后面Jenkinsfile有用到。
#mutiBranch多分支构建

由于我们的开发是基于多分支开发,每个开发环境都对应有一条分支,所以普通的Pipeline自动化构建并不能满足现有的开发部署需求,所以我们需要使用Jenkins的mutiBranch Pipeline。如果你想和更多Jenkins技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

首先当然是新建一个mutiBranch多分支构建Job:
2.jpg

接着设置分支源,分支源就是你项目的Git地址,选择Jenkinsfile在项目的路径:
3.png

接下来Jenkins会在分支源中扫描每个分支下的Jenkinsfile,如果该分支下有Jenkinsfile,那么就会创建一个分支Job:
4.jpg

该Job下的分支Job如下:
5.png

这里需要注意的是,只有需要部署的分支,才加上Jenkinsfile,不然Jenkins会将其余分支也创建一个分支Job。
#通用化Pipeline脚本

到这里之前,基本就可以基于Pipeline脚本自动化部署了,但如果你是一个追求极致,不甘于平庸的程序员,你一定会想,随着项目的增多,Pipeline脚本不断增多,这会造成越来越大的维护成本,业务的极速增长难免会在脚本中修改东西,这就会牵扯太多Pipeline脚本的改动,而且这些脚本基本都相同,那么对于我这么优秀的程序员,怎么会想不到这个问题呢,我第一时间就想到通用化Pipeline脚本。所幸,Jenkins已经看出了我不断骚动的心了,Jenkins甩手就给我一个Shared Libraries。

Shared Libraries是什么呢?顾名思义,它就是一个共享库,它的主要作用是用于将通用的Pipeline脚本放在一个地方,其它项目可以从它那里获取到一个全局通用化的Pipeline脚本,项目之间通过不通的变量参数传递,达到通用化的目的。

接下来我们先创建一个用于存储通用Pipeline脚本的Git仓库:
6.png

仓库目录就不能随便乱添加了,Jenkins有一个严格的规范,下面是官方说明:
7.jpg

官方已经讲得很清楚了,大概意思就是vars目录用于存储通用Pipeline脚本,resources用于存储非Groovy文件。所以我这里就把Pipeline需要的构建脚本以及编排文件都集中放在这里,完全对业务工程师隐蔽,这样做的目的就是为了避免业务工程师不懂瞎几把乱改,导致出bug。

创建完Git仓库后,我们还需要在Jenkins的Manage Jenkins » Configure System » Global Pipeline Libraries中定义全局库:
8.jpg

这里的name,可以在jenkinsfile中通过以下命令引用:
@Library 'objcoding-pipeline-library'

下面我们来看通用Pipeline脚本的编写规则:
#!groovy

def getServer() {
def remote = [:]
remote.name = 'manager node'
remote.user = 'dev'
remote.host = "${REMOTE_HOST}"
remote.port = 22
remote.identityFile = '/root/.ssh/id_rsa'
remote.allowAnyHosts = true
return remote
}

def call(Map map) {

pipeline {
agent any

environment {
REMOTE_HOST = "${map.REMOTE_HOST}"
REPO_URL = "${map.REPO_URL}"
BRANCH_NAME = "${map.BRANCH_NAME}"
STACK_NAME = "${map.STACK_NAME}"
COMPOSE_FILE_NAME = "" + "${map.STACK_NAME}" + "-" + "${map.BRANCH_NAME}" + ".yml"
}

stages {
stage('获取代码') {
steps {
git([url: "${REPO_URL}", branch: "${BRANCH_NAME}"])
}
}

stage('编译代码') {
steps {
withMaven(maven: 'maven 3.6') {
sh "mvn -U -am clean package -DskipTests"
}
}
}

stage('构建镜像') {
steps {
sh "wget -O build.sh https://git.x-vipay.com/docker/jenkins-pipeline-library/raw/master/resources/shell/build.sh"
sh "sh build.sh ${BRANCH_NAME} "
}
}

stage('init-server') {
steps {
script {
server = getServer()
}
}
}

stage('执行发版') {
steps {
writeFile file: 'deploy.sh', text: "wget -O ${COMPOSE_FILE_NAME} " +
" https://git.x-vipay.com/docker/jenkins-pipeline-library/raw/master/resources/docker-compose/${COMPOSE_FILE_NAME} \n" +
"sudo docker stack deploy -c ${COMPOSE_FILE_NAME} ${STACK_NAME}"
sshScript remote: server, script: "deploy.sh"
}
}
}
}
}


  1. 由于我们需要在远程服务器执行任务,所以定义一个远程服务器的信息其中remote.identityFile就是我们上面在容器生成的密钥的地址;
  2. 定义一个call()方法,这个方法用于在各个项目的Jenkinsfile中调用,注意一定得叫call;
  3. 在call()方法中定义一个Pipeline;
  4. environment参数即是可变通用参数,通过传递参数Map来给定值,该Map是从各个项目中定义的传参;
  5. 接下来就是一顿步骤操作啦,“编译代码”这步骤需要填写上面我们在全局工具类设置的maven,“构建镜像”的构建脚本巧妙地利用wget从本远程仓库中拉取下来,”执行发版“的编排文件也是这么做,“init-server”步骤主要是初始化一个server对象,供“执行发版使用”。

从脚本看出来Jenkins将来要推崇的一种思维:配置即代码。

写完通用Pipeline脚本后,接下来我们就需要在各个项目的需要自动化部署的分支的根目录下新建一个Jenkinsfile脚本了:
9.png

接下来我来解释一下Jenkinsfile内容:
#!groovy

// 在多分支构建下,严格规定Jenkinsfile只存在可以发版的分支上

// 引用在jenkins已经全局定义好的library
library 'objcoding-pipeline-library'
def map = [:]

// 远程管理节点地址(用于执行发版)
map.put('REMOTE_HOST','xxx.xx.xx.xxx')
// 项目gitlab代码地址
map.put('REPO_URL','https://github.com/objcoding/docker-jenkins-pipeline-sample.git')
// 分支名称
map.put('BRANCH_NAME','master')
// 服务栈名称
map.put('STACK_NAME','vipay')

// 调用library中var目录下的build.groovy脚本
build(map)


  1. 通过library 'objcoding-pipeline-library'引用我们在Jenkins定义的全局库,定义一个map参数;
  2. 接下来就是将项目具体的参数保存到map中,调用build()方法传递给通用Pipeline脚本。

Shared Libraries共享库极大地提升了Pipeline脚本的通用性,避免了脚本过多带来的问题,也符合了一个优秀程序员的审美观,如果你是一个有追求的程序员,你一定会爱上它。

附上一张价值连城的手稿图:
10.jpg


原文链接:https://mp.weixin.qq.com/s/2M2RQN-_2wmWf4OslIpuaA

DockOne微信分享(一七八):基于Pipeline的CI/CD在趣头条的应用实践

DarkForces. 发表了文章 • 0 个评论 • 2981 次浏览 • 2018-06-28 10:33 • 来自相关话题

【编者的话】在今天的趣头条,随着业务需求的快速增长,部署与扩容的需求也越来越多,为更快的响应业务需求,业务容器化也随之加速。本次分享主要介绍在此业务场景下,部署在ECS的服务如何进行容器化的快速接入,使用基于Pipeline的Jenkins实现流程控制及部署, ...查看全部
【编者的话】在今天的趣头条,随着业务需求的快速增长,部署与扩容的需求也越来越多,为更快的响应业务需求,业务容器化也随之加速。本次分享主要介绍在此业务场景下,部署在ECS的服务如何进行容器化的快速接入,使用基于Pipeline的Jenkins实现流程控制及部署,并动态的适配多环境与多集群。

CI/CD 作为业务自动化部署流水线的重要一环,在容器化快速及频繁发布的需求下,迎来了新的挑战。传统项目中,使用Shell或Pipeline脚本,将编译好的代码上传至服务器并启动就算完成了,而在容器环境中,则涉及到更为复杂的流程。
# 流程概览
在初期,CI究竟是使用基于Shell的自由风格任务还是基于Pipeline的任务,做个简单对比来看看:
img-11.png

基于以上,最终还是选择了已当前流行的Pipeline为主要任务类型,并据此重新设计了任务流程。看图:
‫img1.jpg

代码:
      #! /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
[list]
[*]Code stages.groovy [/*]
[/list]


对每一个关键步骤都设置一个开关,便于调试的同时也更大的增加灵活性。
    // Triggers
SKIP_DOCKER = false
SKIP_KUBE = false
SKIP_COMPILE = false
SKIP_GIT = false
SKIP_TEST = false
SKIP_SONAR = true
SKIP_REPORT = false


可以在任务配置中通过定义变量来改变行为。
# 任务配置
每一个任务都可以通过变量进行定义,可接受的变量及其作用如下:
img-2.png

img-3.png

是不是非常复杂?看一眼实际任务配置:
img-4.png

img-5.png

任务的配置在开始构建时从CMDB获取,但实际工作中总会有一些看似比较合理的需求需要能支持,因此可以在任务配置中定义变量来覆盖CMDB的配置,如下图:
img-6.png

img-7.png

现在,新建Jenkins任务就非常容易了,模块化的函数配合灵活的变量定义,可以轻松应对大部分需求。
# Stage 1:Pre-Process
## 获取项目配置
项目配置信息直接写在Jenkins任务配置里简单方便,但项目变多时配置维护就变得复杂了,因此需要集中统一管理配置,方便维护的同时,也能将配置权限下放至项目开发者,配置变更也能更快速。

在每次构建的时候才去获取配置,确保拿到最新配置。

拿到配置后,使用readJSON将配置解析为相关变量供后续流程使用。
img-8.png

## 权限控制
Jenkins内置有多个权限控制方式,但在多项目+多用户下进行权限控制时,情况就变复杂了,其实也不算特别复杂,就是需要勾太多框框,随着项目与用户增多,难度呈指数级上升。

因此,在设计流程时,就完全抛弃了Jenkins内置的那几套,基于CMDB/GitLab进行权限控制,一个很简单的思路:

  • 如果你没权限访问代码,那么你可能也不能发布我的项目
  • 权限检查在任务预处理阶段进行,不通过则直接终止任务
  • 简单方便易于实现(且又能少只锅)
# Stage 2:Checkout & SonarQube## Checkout
  • 初始化,项目第一次构建自动进行初始化操作
  • 检查
- 检查Git Repo是否为空 - 检查是否选择了版本 - 检查是否需要在指定目录下进行Checkout - 检查发布环境与代码版本规则是否匹配
img-9.png
- 最后,输出代码相关信息,方便事后追溯## SonarQubeSonarQube是一个开源的代码质量管理系统,支持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终于跟容器有点关系了!
img-10.png
是不是很简单?确实很简单: - 查找并模版文件 - 在模版文件基础上加入项目信息,如 - 项目代码 - 为满足稀奇古怪的需求而特设的指令 - Build image - Push image
img-12.png
看到这里,也许你会明白为何不用插件非要不自量力的自己实现。# Stage 5:Deploy to Kubernetes部署至Kubernetes相对简单多了,替换deployment.yaml文件, apply 一下就完了。不信看这里:
img-13.png
等等,注意CronJob函数,难免会有些项目需要利用CronJob完成一些定时任务。需求多的时候,CronJob的管理相当麻烦为了(偷懒)减少不必要的麻烦,我们针对业务需求写了个小函数(CronJob)自动化处理定时任务。开发者在自己项目中提供一个文件,命名为 cronjob.json,在项目发布时,Pipeline检测到这个文件即进行处理,文件格式大致如下:
    [{"id":0,       "time": "00 01 [i] [/i] *",       "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:SonarQube跟Jenkins的集成,能否详细介绍一下,能否show一下Groovy代码。

A:这个比较简单,构建时将项目信息输入到sonar-project.properties文件中,再调用sonar-scanner命令即可。



Q: 这个Pipeline Jenkinsfile是多个在一起吗? 还是直接写的Groovy文件?

A:多个Groovy文件,按类型分函数,一个功能尽量只写一次。



Q:Jenkins的权限控制能否再细化一下?

A:我们这边权限实际上是在CMDB中完成的。构建时向CMDB发起查询请求,传递当前项目名称、选择的环境、用户名过去,CMDB判断当前用户是否有权限构建选定的环境,允许则返回项目配置信息,否则返回错误代码,这边收到后报错终止。



Q:SonarQube的权限控制及性能当面?

A:权限控制使用SonarQube提供的API,将项目跟GitLab中相应项目权限匹配起来,GitLab中可以查看这个项目代码,那么SonarQube中就能看到这个项目结果和Code。



Q: 你们是直接将SonarQube、GitLab/Jenkins的权限控制到一起了? 怎样做的统一?

A:使用LDAP认证。



Q:Sonar使用的sonar-scanner还是mvn sonar:sonar?

A:使用 SonarScanner。



Q:Kubernetes的services.yaml文件在哪里管理?

A:deployment & service & configmap之类文件都是提供Git进行版本控制,针对语言有模版,构建时进行替换。



Q:Pipeline有回滚机制吗,你们集成覆盖率测试了吗?

A:回滚机制暂时不打算通过Pipeline进行,后续在另外的平台实现。
覆盖率测试方面目前还没做。



Q: 你们的Pipeline触发策略是什么样的?

A:人工触发,因为有必须要人工选择的Git版本。为防止误发布,默认没有选定版本,不选则在预处理时报错终止。



Q:Pipeline这套机制的脚本如果出错了如何调试?

A:echo输出调试(手动滑稽)。



Q:Pipeline语法和使用上有什么参考链接吗?

A:http://www.groovy-lang.org/、https://www.w3cschool.cn/groovy/、https://jenkins.io/doc/book/pipeline/syntax/



Q:Git Checkout的时候,你们的Git SCM没有考虑隐私安全的事情吗,比如代码权限受限?

A:Jenkins使用了一个最小权限用户去GitLab上拉代码。安全方面,Jenkins所有节点都是可控的。



Q: 你们的各工具间,有没有做集成?比如使用Pipeline来操作Jira相关issue等?或其他问题管理工具。

A:我们这边目前还没集成Jira。如果有这需求肯定会对接起来。
至于其它的则根据需要在不同阶段进行上报。



Q:构建及部署都在容器中?要构建的文件或制品文件怎么存放与管理的?

A:Agent容器启动时挂载了一个目录,里面有全套附属文件及Jenkins home目录。build节点完成自己工作后,其它节点按需接手处理。



以上内容根据2018年6月26日晚微信群分享内容整理。分享人汝林,趣头条容器运维工程师。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

DockOne微信分享(一七八):基于Pipeline的CI/CD在趣头条的应用实践

DarkForces. 发表了文章 • 0 个评论 • 2981 次浏览 • 2018-06-28 10:33 • 来自相关话题

【编者的话】在今天的趣头条,随着业务需求的快速增长,部署与扩容的需求也越来越多,为更快的响应业务需求,业务容器化也随之加速。本次分享主要介绍在此业务场景下,部署在ECS的服务如何进行容器化的快速接入,使用基于Pipeline的Jenkins实现流程控制及部署, ...查看全部
【编者的话】在今天的趣头条,随着业务需求的快速增长,部署与扩容的需求也越来越多,为更快的响应业务需求,业务容器化也随之加速。本次分享主要介绍在此业务场景下,部署在ECS的服务如何进行容器化的快速接入,使用基于Pipeline的Jenkins实现流程控制及部署,并动态的适配多环境与多集群。

CI/CD 作为业务自动化部署流水线的重要一环,在容器化快速及频繁发布的需求下,迎来了新的挑战。传统项目中,使用Shell或Pipeline脚本,将编译好的代码上传至服务器并启动就算完成了,而在容器环境中,则涉及到更为复杂的流程。
# 流程概览
在初期,CI究竟是使用基于Shell的自由风格任务还是基于Pipeline的任务,做个简单对比来看看:
img-11.png

基于以上,最终还是选择了已当前流行的Pipeline为主要任务类型,并据此重新设计了任务流程。看图:
‫img1.jpg

代码:
      #! /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
[list]
[*]Code stages.groovy [/*]
[/list]


对每一个关键步骤都设置一个开关,便于调试的同时也更大的增加灵活性。
    // Triggers
SKIP_DOCKER = false
SKIP_KUBE = false
SKIP_COMPILE = false
SKIP_GIT = false
SKIP_TEST = false
SKIP_SONAR = true
SKIP_REPORT = false


可以在任务配置中通过定义变量来改变行为。
# 任务配置
每一个任务都可以通过变量进行定义,可接受的变量及其作用如下:
img-2.png

img-3.png

是不是非常复杂?看一眼实际任务配置:
img-4.png

img-5.png

任务的配置在开始构建时从CMDB获取,但实际工作中总会有一些看似比较合理的需求需要能支持,因此可以在任务配置中定义变量来覆盖CMDB的配置,如下图:
img-6.png

img-7.png

现在,新建Jenkins任务就非常容易了,模块化的函数配合灵活的变量定义,可以轻松应对大部分需求。
# Stage 1:Pre-Process
## 获取项目配置
项目配置信息直接写在Jenkins任务配置里简单方便,但项目变多时配置维护就变得复杂了,因此需要集中统一管理配置,方便维护的同时,也能将配置权限下放至项目开发者,配置变更也能更快速。

在每次构建的时候才去获取配置,确保拿到最新配置。

拿到配置后,使用readJSON将配置解析为相关变量供后续流程使用。
img-8.png

## 权限控制
Jenkins内置有多个权限控制方式,但在多项目+多用户下进行权限控制时,情况就变复杂了,其实也不算特别复杂,就是需要勾太多框框,随着项目与用户增多,难度呈指数级上升。

因此,在设计流程时,就完全抛弃了Jenkins内置的那几套,基于CMDB/GitLab进行权限控制,一个很简单的思路:

  • 如果你没权限访问代码,那么你可能也不能发布我的项目
  • 权限检查在任务预处理阶段进行,不通过则直接终止任务
  • 简单方便易于实现(且又能少只锅)
# Stage 2:Checkout & SonarQube## Checkout
  • 初始化,项目第一次构建自动进行初始化操作
  • 检查
- 检查Git Repo是否为空 - 检查是否选择了版本 - 检查是否需要在指定目录下进行Checkout - 检查发布环境与代码版本规则是否匹配
img-9.png
- 最后,输出代码相关信息,方便事后追溯## SonarQubeSonarQube是一个开源的代码质量管理系统,支持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终于跟容器有点关系了!
img-10.png
是不是很简单?确实很简单: - 查找并模版文件 - 在模版文件基础上加入项目信息,如 - 项目代码 - 为满足稀奇古怪的需求而特设的指令 - Build image - Push image
img-12.png
看到这里,也许你会明白为何不用插件非要不自量力的自己实现。# Stage 5:Deploy to Kubernetes部署至Kubernetes相对简单多了,替换deployment.yaml文件, apply 一下就完了。不信看这里:
img-13.png
等等,注意CronJob函数,难免会有些项目需要利用CronJob完成一些定时任务。需求多的时候,CronJob的管理相当麻烦为了(偷懒)减少不必要的麻烦,我们针对业务需求写了个小函数(CronJob)自动化处理定时任务。开发者在自己项目中提供一个文件,命名为 cronjob.json,在项目发布时,Pipeline检测到这个文件即进行处理,文件格式大致如下:
    [{"id":0,       "time": "00 01 [i] [/i] *",       "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:SonarQube跟Jenkins的集成,能否详细介绍一下,能否show一下Groovy代码。

A:这个比较简单,构建时将项目信息输入到sonar-project.properties文件中,再调用sonar-scanner命令即可。



Q: 这个Pipeline Jenkinsfile是多个在一起吗? 还是直接写的Groovy文件?

A:多个Groovy文件,按类型分函数,一个功能尽量只写一次。



Q:Jenkins的权限控制能否再细化一下?

A:我们这边权限实际上是在CMDB中完成的。构建时向CMDB发起查询请求,传递当前项目名称、选择的环境、用户名过去,CMDB判断当前用户是否有权限构建选定的环境,允许则返回项目配置信息,否则返回错误代码,这边收到后报错终止。



Q:SonarQube的权限控制及性能当面?

A:权限控制使用SonarQube提供的API,将项目跟GitLab中相应项目权限匹配起来,GitLab中可以查看这个项目代码,那么SonarQube中就能看到这个项目结果和Code。



Q: 你们是直接将SonarQube、GitLab/Jenkins的权限控制到一起了? 怎样做的统一?

A:使用LDAP认证。



Q:Sonar使用的sonar-scanner还是mvn sonar:sonar?

A:使用 SonarScanner。



Q:Kubernetes的services.yaml文件在哪里管理?

A:deployment & service & configmap之类文件都是提供Git进行版本控制,针对语言有模版,构建时进行替换。



Q:Pipeline有回滚机制吗,你们集成覆盖率测试了吗?

A:回滚机制暂时不打算通过Pipeline进行,后续在另外的平台实现。
覆盖率测试方面目前还没做。



Q: 你们的Pipeline触发策略是什么样的?

A:人工触发,因为有必须要人工选择的Git版本。为防止误发布,默认没有选定版本,不选则在预处理时报错终止。



Q:Pipeline这套机制的脚本如果出错了如何调试?

A:echo输出调试(手动滑稽)。



Q:Pipeline语法和使用上有什么参考链接吗?

A:http://www.groovy-lang.org/、https://www.w3cschool.cn/groovy/、https://jenkins.io/doc/book/pipeline/syntax/



Q:Git Checkout的时候,你们的Git SCM没有考虑隐私安全的事情吗,比如代码权限受限?

A:Jenkins使用了一个最小权限用户去GitLab上拉代码。安全方面,Jenkins所有节点都是可控的。



Q: 你们的各工具间,有没有做集成?比如使用Pipeline来操作Jira相关issue等?或其他问题管理工具。

A:我们这边目前还没集成Jira。如果有这需求肯定会对接起来。
至于其它的则根据需要在不同阶段进行上报。



Q:构建及部署都在容器中?要构建的文件或制品文件怎么存放与管理的?

A:Agent容器启动时挂载了一个目录,里面有全套附属文件及Jenkins home目录。build节点完成自己工作后,其它节点按需接手处理。



以上内容根据2018年6月26日晚微信群分享内容整理。分享人汝林,趣头条容器运维工程师。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

基于Jenkins Pipeline自动化部署

尼古拉斯 发表了文章 • 0 个评论 • 345 次浏览 • 2019-06-05 23:53 • 来自相关话题

最近在公司推行Docker Swarm集群的过程中,需要用到Jenkins来做自动化部署,Jenkins实现自动化部署有很多种方案,可以直接在jenkins页面写Job,把一些操作和脚本都通过页面设置,也可以在每个项目中直接写Pipeline脚本,但像我那么追 ...查看全部
最近在公司推行Docker Swarm集群的过程中,需要用到Jenkins来做自动化部署,Jenkins实现自动化部署有很多种方案,可以直接在jenkins页面写Job,把一些操作和脚本都通过页面设置,也可以在每个项目中直接写Pipeline脚本,但像我那么追求极致的程序员来说,这些方案都打动不了我那颗骚动的心,下面我会跟你们讲讲我是如何通过Pipeline脚本实现自动化部署方案的,并且实现多分支构建,还实现了所有项目共享一个Pipeline脚本。
#使用Jenkins前的一些设置

为了快速搭建Jenkins,我这里使用Docker安装运行Jenkins:
$ sudo docker run -it -d \
--rm \
-u root \
-p 8080:8080 \
-v jenkins-data:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$HOME":/home \
--name jenkins jenkinsci/blueocean

初次使用Jenkins,进入Jenkins页面前,需要密码验证,我们需要进入Docker容器查看密码:
$ sudo docker exec -it jenkins /bin/bash
$ vi /var/jenkins_home/secrets/initialAdminPassword

Docker安装的Jenkins稍微有那么一点缺陷,shell版本跟CentOS宿主机的版本不兼容,这时我们需要进入Jenkins容器手动设置shell:
$ sudo docker exec -it jenkins /bin/bash
$ ln -sf /bin/bash /bin/sh

由于我们的Pipeline还需要在远程服务器执行任务,需要通过SSH连接,那么我们就需要在Jenkins里面生成SSH的公钥密钥:
$ sudo docker exec -it jenkins /bin/bash
$ ssh-keygen -C "root@jenkins"

在远程节点的~/.ssh/authorized_keys中添加jenkins的公钥(id_rsa.pub)。

还需要安装一些必要的插件:

  1. Pipeline Maven Integration
  2. SSH Pipeline Steps

安装完插件后,还需要去全局工具那里添加Maven:
1.png

这里后面Jenkinsfile有用到。
#mutiBranch多分支构建

由于我们的开发是基于多分支开发,每个开发环境都对应有一条分支,所以普通的Pipeline自动化构建并不能满足现有的开发部署需求,所以我们需要使用Jenkins的mutiBranch Pipeline。如果你想和更多Jenkins技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

首先当然是新建一个mutiBranch多分支构建Job:
2.jpg

接着设置分支源,分支源就是你项目的Git地址,选择Jenkinsfile在项目的路径:
3.png

接下来Jenkins会在分支源中扫描每个分支下的Jenkinsfile,如果该分支下有Jenkinsfile,那么就会创建一个分支Job:
4.jpg

该Job下的分支Job如下:
5.png

这里需要注意的是,只有需要部署的分支,才加上Jenkinsfile,不然Jenkins会将其余分支也创建一个分支Job。
#通用化Pipeline脚本

到这里之前,基本就可以基于Pipeline脚本自动化部署了,但如果你是一个追求极致,不甘于平庸的程序员,你一定会想,随着项目的增多,Pipeline脚本不断增多,这会造成越来越大的维护成本,业务的极速增长难免会在脚本中修改东西,这就会牵扯太多Pipeline脚本的改动,而且这些脚本基本都相同,那么对于我这么优秀的程序员,怎么会想不到这个问题呢,我第一时间就想到通用化Pipeline脚本。所幸,Jenkins已经看出了我不断骚动的心了,Jenkins甩手就给我一个Shared Libraries。

Shared Libraries是什么呢?顾名思义,它就是一个共享库,它的主要作用是用于将通用的Pipeline脚本放在一个地方,其它项目可以从它那里获取到一个全局通用化的Pipeline脚本,项目之间通过不通的变量参数传递,达到通用化的目的。

接下来我们先创建一个用于存储通用Pipeline脚本的Git仓库:
6.png

仓库目录就不能随便乱添加了,Jenkins有一个严格的规范,下面是官方说明:
7.jpg

官方已经讲得很清楚了,大概意思就是vars目录用于存储通用Pipeline脚本,resources用于存储非Groovy文件。所以我这里就把Pipeline需要的构建脚本以及编排文件都集中放在这里,完全对业务工程师隐蔽,这样做的目的就是为了避免业务工程师不懂瞎几把乱改,导致出bug。

创建完Git仓库后,我们还需要在Jenkins的Manage Jenkins » Configure System » Global Pipeline Libraries中定义全局库:
8.jpg

这里的name,可以在jenkinsfile中通过以下命令引用:
@Library 'objcoding-pipeline-library'

下面我们来看通用Pipeline脚本的编写规则:
#!groovy

def getServer() {
def remote = [:]
remote.name = 'manager node'
remote.user = 'dev'
remote.host = "${REMOTE_HOST}"
remote.port = 22
remote.identityFile = '/root/.ssh/id_rsa'
remote.allowAnyHosts = true
return remote
}

def call(Map map) {

pipeline {
agent any

environment {
REMOTE_HOST = "${map.REMOTE_HOST}"
REPO_URL = "${map.REPO_URL}"
BRANCH_NAME = "${map.BRANCH_NAME}"
STACK_NAME = "${map.STACK_NAME}"
COMPOSE_FILE_NAME = "" + "${map.STACK_NAME}" + "-" + "${map.BRANCH_NAME}" + ".yml"
}

stages {
stage('获取代码') {
steps {
git([url: "${REPO_URL}", branch: "${BRANCH_NAME}"])
}
}

stage('编译代码') {
steps {
withMaven(maven: 'maven 3.6') {
sh "mvn -U -am clean package -DskipTests"
}
}
}

stage('构建镜像') {
steps {
sh "wget -O build.sh https://git.x-vipay.com/docker/jenkins-pipeline-library/raw/master/resources/shell/build.sh"
sh "sh build.sh ${BRANCH_NAME} "
}
}

stage('init-server') {
steps {
script {
server = getServer()
}
}
}

stage('执行发版') {
steps {
writeFile file: 'deploy.sh', text: "wget -O ${COMPOSE_FILE_NAME} " +
" https://git.x-vipay.com/docker/jenkins-pipeline-library/raw/master/resources/docker-compose/${COMPOSE_FILE_NAME} \n" +
"sudo docker stack deploy -c ${COMPOSE_FILE_NAME} ${STACK_NAME}"
sshScript remote: server, script: "deploy.sh"
}
}
}
}
}


  1. 由于我们需要在远程服务器执行任务,所以定义一个远程服务器的信息其中remote.identityFile就是我们上面在容器生成的密钥的地址;
  2. 定义一个call()方法,这个方法用于在各个项目的Jenkinsfile中调用,注意一定得叫call;
  3. 在call()方法中定义一个Pipeline;
  4. environment参数即是可变通用参数,通过传递参数Map来给定值,该Map是从各个项目中定义的传参;
  5. 接下来就是一顿步骤操作啦,“编译代码”这步骤需要填写上面我们在全局工具类设置的maven,“构建镜像”的构建脚本巧妙地利用wget从本远程仓库中拉取下来,”执行发版“的编排文件也是这么做,“init-server”步骤主要是初始化一个server对象,供“执行发版使用”。

从脚本看出来Jenkins将来要推崇的一种思维:配置即代码。

写完通用Pipeline脚本后,接下来我们就需要在各个项目的需要自动化部署的分支的根目录下新建一个Jenkinsfile脚本了:
9.png

接下来我来解释一下Jenkinsfile内容:
#!groovy

// 在多分支构建下,严格规定Jenkinsfile只存在可以发版的分支上

// 引用在jenkins已经全局定义好的library
library 'objcoding-pipeline-library'
def map = [:]

// 远程管理节点地址(用于执行发版)
map.put('REMOTE_HOST','xxx.xx.xx.xxx')
// 项目gitlab代码地址
map.put('REPO_URL','https://github.com/objcoding/docker-jenkins-pipeline-sample.git')
// 分支名称
map.put('BRANCH_NAME','master')
// 服务栈名称
map.put('STACK_NAME','vipay')

// 调用library中var目录下的build.groovy脚本
build(map)


  1. 通过library 'objcoding-pipeline-library'引用我们在Jenkins定义的全局库,定义一个map参数;
  2. 接下来就是将项目具体的参数保存到map中,调用build()方法传递给通用Pipeline脚本。

Shared Libraries共享库极大地提升了Pipeline脚本的通用性,避免了脚本过多带来的问题,也符合了一个优秀程序员的审美观,如果你是一个有追求的程序员,你一定会爱上它。

附上一张价值连城的手稿图:
10.jpg


原文链接:https://mp.weixin.qq.com/s/2M2RQN-_2wmWf4OslIpuaA

DockOne微信分享(一七八):基于Pipeline的CI/CD在趣头条的应用实践

DarkForces. 发表了文章 • 0 个评论 • 2981 次浏览 • 2018-06-28 10:33 • 来自相关话题

【编者的话】在今天的趣头条,随着业务需求的快速增长,部署与扩容的需求也越来越多,为更快的响应业务需求,业务容器化也随之加速。本次分享主要介绍在此业务场景下,部署在ECS的服务如何进行容器化的快速接入,使用基于Pipeline的Jenkins实现流程控制及部署, ...查看全部
【编者的话】在今天的趣头条,随着业务需求的快速增长,部署与扩容的需求也越来越多,为更快的响应业务需求,业务容器化也随之加速。本次分享主要介绍在此业务场景下,部署在ECS的服务如何进行容器化的快速接入,使用基于Pipeline的Jenkins实现流程控制及部署,并动态的适配多环境与多集群。

CI/CD 作为业务自动化部署流水线的重要一环,在容器化快速及频繁发布的需求下,迎来了新的挑战。传统项目中,使用Shell或Pipeline脚本,将编译好的代码上传至服务器并启动就算完成了,而在容器环境中,则涉及到更为复杂的流程。
# 流程概览
在初期,CI究竟是使用基于Shell的自由风格任务还是基于Pipeline的任务,做个简单对比来看看:
img-11.png

基于以上,最终还是选择了已当前流行的Pipeline为主要任务类型,并据此重新设计了任务流程。看图:
‫img1.jpg

代码:
      #! /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
[list]
[*]Code stages.groovy [/*]
[/list]


对每一个关键步骤都设置一个开关,便于调试的同时也更大的增加灵活性。
    // Triggers
SKIP_DOCKER = false
SKIP_KUBE = false
SKIP_COMPILE = false
SKIP_GIT = false
SKIP_TEST = false
SKIP_SONAR = true
SKIP_REPORT = false


可以在任务配置中通过定义变量来改变行为。
# 任务配置
每一个任务都可以通过变量进行定义,可接受的变量及其作用如下:
img-2.png

img-3.png

是不是非常复杂?看一眼实际任务配置:
img-4.png

img-5.png

任务的配置在开始构建时从CMDB获取,但实际工作中总会有一些看似比较合理的需求需要能支持,因此可以在任务配置中定义变量来覆盖CMDB的配置,如下图:
img-6.png

img-7.png

现在,新建Jenkins任务就非常容易了,模块化的函数配合灵活的变量定义,可以轻松应对大部分需求。
# Stage 1:Pre-Process
## 获取项目配置
项目配置信息直接写在Jenkins任务配置里简单方便,但项目变多时配置维护就变得复杂了,因此需要集中统一管理配置,方便维护的同时,也能将配置权限下放至项目开发者,配置变更也能更快速。

在每次构建的时候才去获取配置,确保拿到最新配置。

拿到配置后,使用readJSON将配置解析为相关变量供后续流程使用。
img-8.png

## 权限控制
Jenkins内置有多个权限控制方式,但在多项目+多用户下进行权限控制时,情况就变复杂了,其实也不算特别复杂,就是需要勾太多框框,随着项目与用户增多,难度呈指数级上升。

因此,在设计流程时,就完全抛弃了Jenkins内置的那几套,基于CMDB/GitLab进行权限控制,一个很简单的思路:

  • 如果你没权限访问代码,那么你可能也不能发布我的项目
  • 权限检查在任务预处理阶段进行,不通过则直接终止任务
  • 简单方便易于实现(且又能少只锅)
# Stage 2:Checkout & SonarQube## Checkout
  • 初始化,项目第一次构建自动进行初始化操作
  • 检查
- 检查Git Repo是否为空 - 检查是否选择了版本 - 检查是否需要在指定目录下进行Checkout - 检查发布环境与代码版本规则是否匹配
img-9.png
- 最后,输出代码相关信息,方便事后追溯## SonarQubeSonarQube是一个开源的代码质量管理系统,支持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终于跟容器有点关系了!
img-10.png
是不是很简单?确实很简单: - 查找并模版文件 - 在模版文件基础上加入项目信息,如 - 项目代码 - 为满足稀奇古怪的需求而特设的指令 - Build image - Push image
img-12.png
看到这里,也许你会明白为何不用插件非要不自量力的自己实现。# Stage 5:Deploy to Kubernetes部署至Kubernetes相对简单多了,替换deployment.yaml文件, apply 一下就完了。不信看这里:
img-13.png
等等,注意CronJob函数,难免会有些项目需要利用CronJob完成一些定时任务。需求多的时候,CronJob的管理相当麻烦为了(偷懒)减少不必要的麻烦,我们针对业务需求写了个小函数(CronJob)自动化处理定时任务。开发者在自己项目中提供一个文件,命名为 cronjob.json,在项目发布时,Pipeline检测到这个文件即进行处理,文件格式大致如下:
    [{"id":0,       "time": "00 01 [i] [/i] *",       "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:SonarQube跟Jenkins的集成,能否详细介绍一下,能否show一下Groovy代码。

A:这个比较简单,构建时将项目信息输入到sonar-project.properties文件中,再调用sonar-scanner命令即可。



Q: 这个Pipeline Jenkinsfile是多个在一起吗? 还是直接写的Groovy文件?

A:多个Groovy文件,按类型分函数,一个功能尽量只写一次。



Q:Jenkins的权限控制能否再细化一下?

A:我们这边权限实际上是在CMDB中完成的。构建时向CMDB发起查询请求,传递当前项目名称、选择的环境、用户名过去,CMDB判断当前用户是否有权限构建选定的环境,允许则返回项目配置信息,否则返回错误代码,这边收到后报错终止。



Q:SonarQube的权限控制及性能当面?

A:权限控制使用SonarQube提供的API,将项目跟GitLab中相应项目权限匹配起来,GitLab中可以查看这个项目代码,那么SonarQube中就能看到这个项目结果和Code。



Q: 你们是直接将SonarQube、GitLab/Jenkins的权限控制到一起了? 怎样做的统一?

A:使用LDAP认证。



Q:Sonar使用的sonar-scanner还是mvn sonar:sonar?

A:使用 SonarScanner。



Q:Kubernetes的services.yaml文件在哪里管理?

A:deployment & service & configmap之类文件都是提供Git进行版本控制,针对语言有模版,构建时进行替换。



Q:Pipeline有回滚机制吗,你们集成覆盖率测试了吗?

A:回滚机制暂时不打算通过Pipeline进行,后续在另外的平台实现。
覆盖率测试方面目前还没做。



Q: 你们的Pipeline触发策略是什么样的?

A:人工触发,因为有必须要人工选择的Git版本。为防止误发布,默认没有选定版本,不选则在预处理时报错终止。



Q:Pipeline这套机制的脚本如果出错了如何调试?

A:echo输出调试(手动滑稽)。



Q:Pipeline语法和使用上有什么参考链接吗?

A:http://www.groovy-lang.org/、https://www.w3cschool.cn/groovy/、https://jenkins.io/doc/book/pipeline/syntax/



Q:Git Checkout的时候,你们的Git SCM没有考虑隐私安全的事情吗,比如代码权限受限?

A:Jenkins使用了一个最小权限用户去GitLab上拉代码。安全方面,Jenkins所有节点都是可控的。



Q: 你们的各工具间,有没有做集成?比如使用Pipeline来操作Jira相关issue等?或其他问题管理工具。

A:我们这边目前还没集成Jira。如果有这需求肯定会对接起来。
至于其它的则根据需要在不同阶段进行上报。



Q:构建及部署都在容器中?要构建的文件或制品文件怎么存放与管理的?

A:Agent容器启动时挂载了一个目录,里面有全套附属文件及Jenkins home目录。build节点完成自己工作后,其它节点按需接手处理。



以上内容根据2018年6月26日晚微信群分享内容整理。分享人汝林,趣头条容器运维工程师。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。