Jenkens Pipeline
Contents
jenkins pipeline 分为 Scripted Pipeline 和 Declarative Pipeline,Scripted Pipeline 是最早基于 groovy 实现的 pipeline 语法,Declarative Pipeline 是后面推出的声明式 pipeline 语法,两个最大的区别就是 Declarative Pipeline 整体比较简洁,学习起来也比 groovy 要快的多。Declarative Pipeline 的编程模型是 Declarative programming,而 Scripted Pipeline 是 Imperative_programming。 Declarative Pipeline 要预定义脚本结构,语法也比较严格一些,Scripted Pipeline 其实就是一行一行的脚本,一般执行到那才知道有没有问题。
1 2 3 4 5 6 7 8 9 10 |
Jenkinsfile (Scripted Pipeline)
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
} |
1 2 3 4 5 6 7 8 9 10 11 |
Jenkinsfile (Declarative Pipeline)
pipeline {
agent { docker 'maven:3-alpine' }
stages {
stage('Example Build') {
steps {
sh 'mvn -B clean verify'
}
}
}
} |
最终还是选择使用了 Declarative Pipeline,因为比较简洁,而且能满足所有的需求。在使用 Declarative Pipeline 可以先看一下 官方语法文档 和 官方例子仓库。
maybe help
git parameter
Declarative Pipeline 一样可以定义参数化构建,有一些情况你可能不想把 jenkinsfile 和代码的仓库放到一下,但是你要 checkout code,所以需要定义 gitParameter 来拉指定分支或者 tag 的代码。这个有一个问题要先执行一次才能在 jenkins 的界面上拉分支和 tag
1 2 3 4 5 6 7 8 9 10 11 |
parameters {
gitParameter defaultValue: 'origin/master',
name: 'BRANCH_TAG',
type: 'PT_BRANCH_TAG',
useRepository: "<git_url>",
quickFilterEnabled: 'true',
listSize: '10',
description: 'pre 和 prd 环境使用 tag 发布',
branchFilter: 'origin.*/(.*)',
tagFilter: '*'
} |
定义环境变量
1 2 3 4 |
environment {
PROJECT="${JOB_NAME}"
DATE=sh(returnStdout: true, script: 'date "+%Y-%m-%d %H:%M:%S"').trim()
} |
checkout scm
1 2 3 4 5 6 |
container('go') {
checkout scm: [$class: 'GitSCM',
userRemoteConfigs: [[url: "<git_url>", credentialsId: 'gitlab-admin-ssh']],
branches: [[name: "${params.BRANCH_TAG}"]]],
poll: false
} |
获取 git 版本信息
因为发布的时候可以选择 分支和 tag,所以在参数化构建的时候定义 BRANCH_TAG 不能直接作为 tag 来使用,可以使用 git 命令来获取 tag 信息
1 2 3 |
script {
VERSION=sh(returnStdout: true, script: 'git describe --candidate=1 --tags').trim()
} |
if else
1 2 3 4 5 6 7 |
script {
if (env.BUILD_IMAGE == "false"){
sh "docker pull ..."
} else {
sh "docker build ..."
}
} |
git
在 pipeline 中要使用其他的 git 仓库,下面会 clone 其他的仓库到 _chart 目录。
1 2 3 |
dir('_chart') {
git branch: "<git_branch>", url: "<git_url>", credentialsId: 'gitlab-admin-ssh'
} |
在使用的时候想把最后部署到 k8s 的所有 yaml 文件做一个备份,并记录一下用户名,下面的例子是怎么获取执行的用户名和如何在 credentials 中拿到 gitlab 的用户名和密码。
1 2 3 4 5 6 7 8 9 10 11 |
wrap([$class: 'BuildUser']) {
script {
withCredentials([usernamePassword(credentialsId: 'zhengjiajin-gitlab', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD')]) {
sh("""export GIT_AUTHOR_EMAIL=******
export GIT_AUTHOR_NAME=*******
git add ${JOB_NAME}/${ENV}/${BUILD_ID}/_deploy.yaml
git commit -m '${BUILD_USER_ID} prompt ${JOB_NAME}:${VERSION} to ${ENV} in ${DATE}'
git push https://${GIT_USERNAME}:${GIT_PASSWORD}@<git_url>""")
}
}
} |
post
发布的时候可能想有一个通知,可以使用 post 语句, git log --pretty=format:"%h - %an, %ar : %s" -n 1' 可以显示当前 git 最后一个 commit 信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
post {
always {
container('go') {
wrap([$class: 'BuildUser']) {
script {
text=sh(returnStdout: true, script: 'git log --pretty=format:"%h - %an, %ar : %s" -n 1').trim()
endAt=sh(returnStdout: true, script: 'date "+%Y-%m-%d %H:%M:%S"').trim()
end=sh(returnStdout: true, script: 'date "+%s"').trim()
result=currentBuild.result
duration= (end as int)-(start as int)
}
sh """curl -i -X POST -H "Content-type: application/json" -d '
{
"operator": "${BUILD_USER_ID}",
"serviceName":"${JOB_NAME}",
"startAt":"${startAt}",
"endAt":"${endAt}",
"text": "${text}",
"duration":"${duration}s",
"jobAddress": "${JOB_URL}",
"status":"${result}"
}' ${url}"""
}
}
}
} |
load
Declarative Pipeline 好像并不支持 load 其他 pipeline 的能力,Scripted Pipeline 是可以 load 其他的 pipeline 的,在实际使用的时候遇到一个问题就是 k8s 的 yaml 和 jenkins 都需要一些学习曲线,用户完全不关心,这个时候可以把 pipeline 放到另一个仓库中作为 code 来管理,然后使用 load 加载 pipeline。下面的例子是通过 gitlab raw 的 API 获取 Declarative Pipelines 并加载执行,另外把想要在 jenkins 上修改的变量 echo 到了 _Jenkinsfile 顶部,比较 hack。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
node("jenkins-go"){
stage("load declarative jenkinsfile"){
container('go') {
withCredentials([string(credentialsId: 'gitlab-token', variable: 'TOKEN')]) {
sh """
set +vx
echo "def GIT_URL = '<GIT_URL>'
// 指定部署文件的仓库(jenkinsfile 和 k8s yaml 文件)
def CHART_GIT_BRANCH = 'master'
def CHART_GIT_URL = '<git_url>'" > _Jenkinsfile
curl -H "PRIVATE-TOKEN: ${TOKEN}" "https://<git_url>/api/v4/projects/6082/repository/files/jobs%2F${JOB_NAME}%2FJenkinsfile/raw?ref=master">>_Jenkinsfile
"""
}
}
}
load "_Jenkinsfile"
} |
需要完整的例子可以发邮件给我。
Author zhengjiajin
LastMod 2019-09-25