Jenkinsfile 使用说明(2)
文章目录1. 编写业务相关的 Jenkinsfile2. 入参及环境变量的配置2.1 配置说明2.2 配置后的界面展示3. 定义一个 kubernetes 的 agent3.1 基于 docker in docker 构建3.2 基于 kaniko 构建镜像4. 拉取代码 & 执行编译4.1 拉取代码4.2 执行编译5. 构建 & 推送 docker 镜像6. 总结7. 碎碎念8.
文章目录
经过前一篇文章的介绍以后,大家对于声明式的 jenkinsfile 有了一定程度的了解。现在可以开始动手写一个专属于自己服务的 jenkinsfile 文件。
注:解放双手,从写 jenkinsfile 开始。写不了吃亏,写不了上当。
1. 编写业务相关的 Jenkinsfile
思考一下编写一个 Jenkinsfile 需要几个部分,然后逐个实践一下,属于自己服务的 jenkinsfile 就完成了。
注:以下是笔者总结的几个基础部分,如有不同的建议欢迎评论。
接下来将会就每一个部分详细的介绍和说明。逐个介绍完成之后,将会提供一个完整的 jenkinsfile 的 demo。
2. 入参及环境变量的配置
2.1 配置说明
此处主要示范 入参以及 环境变量如何配置,所以选择最简单的 agent 的方式进行示例。
注:某些 jenkins 集群,配置 agent 为 any 无法执行,所以此处选择了 label 的方式。
pipeline {
agent {
label 'node' // 此处需要自己选择合适的 node
}
parameters {
string(name: 'branch', defaultValue: 'master', description: 'the branch')
}
environment {
BASE_USER_CREDENTIALS = credentials('harbor') //配置正确的 harbor 用户
}
stages {
stage('input') {
steps {
echo "${env.branch}"
}
}
stage('environment') {
steps {
echo "${BASE_USER_CREDENTIALS_USR}"
echo "${env.BUILD_NUMBER}" //内置环境变量
}
}
}
}
注:在 steps 块中执行多行 sh 时,有两种方式,
"""
(三个双引号)和'''
(三个单引号),区别在于双引号里面的引用的变量会被计算展开。
2.2 配置后的界面展示
- 配置了 parameters 后在触发编译时,需要填写该参数的值。
-
使用 credentials 获取环境变量
3. 定义一个 kubernetes 的 agent
问:为什么使用 kubernetes 配置?
答:从可操作性的角度上分析,kubernetes 的方式更方便。每次构建的时候都是基于配置生成的一个崭新的环境,构建结束后环境会自动销毁。即使多次构建也不会互相干扰。(ps 虽然写起来有一些复杂
Kubernetes 的容器集,是独立于 jenkins slave 的机器,为了让定义的 kubernetes agent 能够正常运行,需要包含以下三个部分
- 配置完成的 jnlp 容器 (jenkins 的 slave)
- 支持编译特定语言的容器(比如,go 、 c++)
- 能够将二进制打包为 docker 镜像的容器(比如, docker in docker 、kaniko)
以下分别介绍公司内部可以用的 docker in docker 和 kaniko。
3.1 基于 docker in docker 构建
如上图,可以在 Container 中直接运行一个 Docker Daemon,然后 Container 中的 Docker CLI 工具操作容器。
注:这种方式下,容器中的 Docker Daemon 完全独立于外部,具有良好的隔离特性。看起来,Container 类似一个 VM,但是 DinD 的作者自己也不是很推荐。
主要还是安全问题。DinD 需要以特权模式启动,这种嵌套会带来潜在的安全风险。
以下是一份 docker in docker 容器集的配置
metadata:
labels:
label-name: jenkins-demo
spec:
imagePullSecrets:
- regcred
containers:
- name: jnlp
resources:
limits:
cpu: 0.45
memory: 450Mi
requests:
cpu: 0.45
memory: 450Mi
- name: streaming
image: hub.xxxx.co/ubuntu:golang-1.16 //配置正确的 hub 地址
imagePullPolicy: Always
command:
- cat
tty: true
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
- name: docker
image: hub.xxx.co/compiling:1.1.11-cache //配置正确的 hub 地址
imagePullPolicy: IfNotPresent
command:
- cat
tty: true
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
securityContext:
privileged: true
env:
- name: DOCKER_HOST
value: tcp://localhost:2375
- name: dind
image: docker:18.05-dind
resources:
limits:
cpu: 0.5
memory: 550Mi
requests:
cpu: 0.5
memory: 500Mi
securityContext:
privileged: true
args:
- "--mtu=1450"
volumeMounts:
- name: dind-storage
mountPath: /var/lib/docker
volumes:
- name: dind-storage
emptyDir: {}
3.2 基于 kaniko 构建镜像
Google 发布了“ Kaniko ”,一种用于在未授权容器或 Kubernetes 集群中构建容器镜像的开源工具。虽然 Kaniko 也是根据用户给定的 Dockerfile 构建镜像,但是并不依赖于 Docker 守护进程,而是在用户空间中完全执行每个命令,并对更改的文件系统做快照。
以下是一份 kaniko 的容器集的配置
metadata:
labels:
label-name: jenkins-demo
spec:
imagePullSecrets:
- regcred
containers:
- name: jnlp
resources:
limits:
cpu: 0.45
memory: 450Mi
requests:
cpu: 0.45
memory: 450Mi
- name: streaming
image: hub.xxxx.co/ubuntu:golang-1.16 //配置正确的 hub 地址
imagePullPolicy: Always
command:
- cat
tty: true
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
securityContext:
privileged: true
env:
- name: DOCKER_HOST
value: tcp://localhost:2375
- name: kaniko
image: gcr.io/kaniko-project/executor:v1.7.0-debug
command:
- cat
tty: true
resources:
limits:
cpu: 2
memory: 2000Mi
requests:
cpu: 2
memory: 2000Mi
volumeMounts:
- name: jenkins-docker-cfg
mountPath: /kaniko/.docker
volumes:
- name: jenkins-docker-cfg
secret:
secretName: regcred
items:
- key: .dockerconfigjson
path: config.json
4. 拉取代码 & 执行编译
4.1 拉取代码
git 命令,带有四个参数
- branch:执行拉取的分支
- credentialsID:访问该仓库的认证
- url: 拉取仓库的git地址
- changelog:是否打印信息
有了执行环境之后,接下来的一步就是「拉取代码 & 执行编译」,以下是一个拉取代码部分 jenkinsfile 的示例。
environment {
BITBUCKET = 'bitbucket-ssh-access'
}
stages {
stage('pull code') {
steps {
container('streaming') {
buildName "#${env.BUILD_NUMBER}"
git branch: "${env.branch}", credentialsId: "${env.BITBUCKET}", url: 'ssh://git@git.xxxx.co/service.git' //配置正确的 git 地址
}
}
}
}
4.2 执行编译
此处编译的示例使用的 golang ,其他语言的后面系列文章会继续完善。在执行编译前需要将 go 的环境变量再次抛出。以下是执行编译部分 jenkinsfile 的示例
stage('excuting script') {
steps {
container('streaming') {
sh """
export PATH="$PATH:/usr/lib/go-1.16/bin"
export GOPROXY=https://mirrors.aliyun.com/goproxy/
make build // 代码库内已经完成了 makefile 文件的编写
"""
}
}
}
5. 构建 & 推送 docker 镜像
有了步骤 4 中编译的二进制结果,剩下的就是将二进制结果制作成镜像同时推送到 docker hub。至此你将收获一个完整的自动化构建 jenkinsfile 的完整版本。
注:不论是 docker in docker 还是 kaniko 都使用挂载 emptyDir 的方式,来实现容器间数据的共享。
以下是执行构建、推送 docker 镜像的部分 jenkinsfile 示例。
environment {
// credentials for other service, you can find it at:
// Manager Jenkins -> Manger Credentials
BASE_USER_CREDENTIALS = credentials('harbor1')
DOCKER_USER_CREDENTIALS = credentials('harbor2')
}
stage ('Build Image') {
steps {
container('docker') {
sh """#!/bin/bash
set -xeu
docker -v
//配置正确的 hub 地址
docker login hub.xxxx.co -u \'${env.DOCKER_USER_CREDENTIALS_USR}\' -p \'${env.DOCKER_USER_CREDENTIALS_PSW}\'
make image_dev
//配置正确的 hub 地址
docker login hub.xxxx.co -u \'${env.BASE_USER_CREDENTIALS_USR}\' -p \'${env.BASE_USER_CREDENTIALS_PSW}\'
make publish_dev
"""
}
}
}
6. 总结
以上最小可以使用的 jenkinsfile 的每一个部分的详细介绍。最后将它们组合在一起,展示一个完整的🌰:
pipeline {
agent {
kubernetes {
yaml '''
metadata:
labels:
label-name: jenkins-demo
spec:
imagePullSecrets:
- regcred
containers:
- name: jnlp
resources:
limits:
cpu: 0.45
memory: 450Mi
requests:
cpu: 0.45
memory: 450Mi
- name: streaming
image: hub.xxxx.co/ubuntu:golang-1.16 //配置正确的 hub 地址
imagePullPolicy: Always
command:
- cat
tty: true
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
- name: docker
image: hub.xxxx.co/compiling:1.1.11-cache //配置正确的 hub 地址
imagePullPolicy: IfNotPresent
command:
- cat
tty: true
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
securityContext:
privileged: true
env:
- name: DOCKER_HOST
value: tcp://localhost:2375
- name: dind
image: docker:18.05-dind
resources:
limits:
cpu: 0.5
memory: 550Mi
requests:
cpu: 0.5
memory: 500Mi
securityContext:
privileged: true
args:
- "--mtu=1450"
volumeMounts:
- name: dind-storage
mountPath: /var/lib/docker
volumes:
- name: dind-storage
emptyDir: {}
'''
}
}
environment {
// credentials for other service, you can find it at:
// Manager Jenkins -> Manger Credentials
BASE_USER_CREDENTIALS = credentials('harbor1') //配置正确的 hub 地址
DOCKER_USER_CREDENTIALS = credentials('harbor2') //配置正确的 hub 地址
BITBUCKET = 'bitbucket-ssh-access'
}
stages {
stage('pulling code') {
steps{
container('streaming') {
buildName "#${env.BUILD_NUMBER}"
git branch: "${env.branch}", credentialsId: "${env.BITBUCKET}", url: 'ssh://git@git.xxxxx.co/service.git' //配置正确的 hub 地址
}
}
}
stage('excuting script') {
steps {
container('streaming') {
sh """
export PATH="$PATH:/usr/lib/go-1.16/bin"
export GOPROXY=https://mirrors.aliyun.com/goproxy/
make build
"""
}
}
}
stage ('Build Image') {
steps {
container('docker') {
sh """#!/bin/bash
set -xeu
docker -v
//配置正确的 hub 地址
docker login hub.xxxx.co -u \'${env.DOCKER_USER_CREDENTIALS_USR}\' -p \'${env.DOCKER_USER_CREDENTIALS_PSW}\'
make image_dev
//配置正确的 hub 地址
docker login hub.xxxx.co -u \'${env.BASE_USER_CREDENTIALS_USR}\' -p \'${env.BASE_USER_CREDENTIALS_PSW}\'
make publish_dev
"""
}
}
}
}
}
7. 碎碎念
马上就是元旦了,希望大家都能万事胜意。
-
要在最快乐的年纪活的精彩且迷人。
-
愿听我碎碎念念的人,都可以陪我岁岁年年。
-
你的人生要自己去经历,所以是甜是苦,都不要辜负。
8. 参考资料
更多推荐
所有评论(0)