支持各平台:windows、linux、docker,
见官网,比较详细
作用范围分为全局和局部凭据
类型可以分为:
合格的声明式流水线需要stages 和step 、post指令,来表明jenkins处于那个阶段,执行什么命令、执行结果。
jenkins的生命周期:构建、测试、部署, Jenkinsfile是整个生命周期的管理工具,可以说是粘合剂。
构建Build:一般包括代码的组装、编译和打包
测试Test:测试一般由其他插件提供测试结果和测试记录,报告和可视化工具;如junit
部署Deploy:当构建和测试阶段都成功执行完,该阶段才能执行
# currentBuild.result 获取当前构建的结果
pipeline {
agent any
stages {
stage('Deploy') {
when {
expression {
currentBuild.result == null || currentBuild.result == 'SUCCESS'
}
}
steps {
sh 'make publish'
}
}
}
}
def singlyQuoted = 'Hello World'
echo '!!! ${singlyQuoted}'
结果:!!! Hello World
变量名 | 含义 |
---|---|
BUILD_ID | 构建ID |
BUILD_NUMBER | 构建号 |
BUILD_TAG | 等于字符串:“jenkins- ${JOB_NAME}- ${BUILD_NUMBER}” |
BUILD_URL | 构建结果的URL |
EXECUTOR_NUMBER | 用于识别当前构建的执行者的唯一编号 |
JAVA_HOME | jdk设置的系统变量 |
JENKINS_URL | 服务器的完整URL:https://example.com:port/jenkins/ |
JOB_NAME | 构建job名称 |
NODE_NAME | 构建节点名称 |
WORKSPACE | 工作空间的绝对路径 |
用法:echo “Running ${env.BUILD_ID} ON ${env.JENKINS_URL}”
# 上面全局变量,下面stage内的为局部变量
pipeline {
agent any
environment {
CC = 'clang'
}
stages {
stage('Example') {
environment {
DEBUG_FLAGS = '-g'
}
steps {
sh 'printenv'
}
}
}
}
pipeline {
agent any
environment {
// 使用 returnStdout
CC = """${sh(
returnStdout: true,
script: 'echo "clang"'
)}"""
// 使用 returnStatus
EXIT_STATUS = """${sh(
returnStatus: true,
script: 'exit 1'
)}"""
}
stages {
stage('Example') {
environment {
DEBUG_FLAGS = '-g'
}
steps {
sh 'printenv'
}
}
}
}
# 用于Amazon Web 服务(AWS
environment {
AWS_ACCESS_KEY_ID = credentials('jenkins-aws-secret-key-id')
AWS_SECRET_ACCESS_KEY = credentials('jenkins-aws-secret-access-key')
}
environment {
BITBUCKET_COMMON_CREDS = credentials('jenkins-bitbucket-common-creds')
}
# 实际Jenkins配置了3个环境变量
BITBUCKET_COMMON_CREDS 格式为 username:password
BITBUCKET_COMMON_CREDS_USR 仅含用户名
BITBUCKET_COMMON_CREDS_PSW 仅含密码
SSH User Private Key:提供key
Certificate:提供PKCS#12证书
Docker client certificate:用于处理docker主机证书的认证
# ssh 示例
# 可选 passphraseVariable 和 usernameVariable ,可删除
withCredentials(bindings: [sshUserPrivateKey(credentialsId: 'jenkins-ssh-key-for-abc', \
keyFileVariable: 'SSH_KEY_FOR_ABC', \
passphraseVariable: '', \
usernameVariable: '')]) {
// some block
}
# certficate示例
# 可选 aliasVariable 和 passwordVariable ,可删除
withCredentials(bindings: [certificate(aliasVariable: '', \
credentialsId: 'jenkins-certificate-for-xyz', \
keystoreVariable: 'CERTIFICATE_FOR_XYZ', \
passwordVariable: 'XYZ-CERTIFICATE-PASSWORD')]) {
// some block
}
parameters {
string(name: 'Greeting', defaultValue: 'Hello', description: 'How should I greet the world?')
}
post {
always {
junit '**/target/*.xml'
}
failure {
mail to: [email protected], subject: 'The Pipeline failed :('
}
}
选择windows 、linux节点
# stash 允许捕获与包含模式配置文件,以便再同一流水线重用。一旦流水线执行完成,就会从Jenkins master中删除在暂存文件
# unstash 会从Jenkins master中取回命名的stash到流水线的当前工作区
pipeline {
agent none
stages {
stage('Build') {
agent any
steps {
checkout scm
sh 'make'
stash includes: '**/target/*.jar', name: 'app'
}
}
stage('Test on Linux') {
agent {
label 'linux'
}
steps {
unstash 'app'
sh 'make check'
}
post {
always {
junit '**/target/*.xml'
}
}
}
stage('Test on Windows') {
agent {
label 'windows'
}
steps {
unstash 'app'
bat 'make check'
}
post {
always {
junit '**/target/*.xml'
}
}
}
}
}
pipeline遵循groovy语法
# 下面语句功能相同
git url: 'git://example.com/amazing-project.git', branch: 'master'
git([url: 'git://example.com/amazing-project.git', branch: 'master'])
# 参数可省略
sh 'echo hello' /* short form */
sh([script: 'echo hello']) /* long form */
stage('Build') {
/* .. snip .. */
}
stage('Test') {
parallel linux: {
node('linux') {
checkout scm
try {
unstash 'app'
sh 'make check'
}
finally {
junit '**/target/*.xml'
}
}
},
windows: {
node('windows') {
/* .. snip .. */
}
}
}
Multibranch Pipeline 项目类型能够 在同一个项目的不同分支上实现不同的Jenkinsfile;
Jenkins 自动的扫描指定的存储库并为包含Jenkinsfile
的仓库的每个分支创建合适的项目
默认情况下, Jenkins 不会自动的重新索引分支添加或删除的仓库(除非使用 组织文件夹), 所以周期性地重新索引有助于配置多分支流水线:
agent {
docker { image 'node:7-alpine' }
}
挂载到容器外~/.m2
agent {
docker {
image 'maven:3-alpine'
args '-v $HOME/.m2:/root/.m2'
}
}
使用多个容器,对不同的stage用不同的环境
pipeline {
agent none
stages {
stage('Back-end') {
agent {
docker { image 'maven:3-alpine' }
}
steps {
sh 'mvn --version'
}
}
stage('Front-end') {
agent {
docker { image 'node:7-alpine' }
}
steps {
sh 'node --version'
}
}
}
}
使用Dockerfile构建新容器
Dockerfile
FROM node:7-alpine
RUN apk add -U subversion
# 如下,Dockerfile放入源仓库根目录
agent { dockerfile true }
Docker 流水线可以"在后台"运行一个容器 , 而在另外一个容器中工作。 利用这种sidecar 方式, 流水线可以为每个流水线运行 提供一个"干净的" 容器。
node {
checkout scm
/*
* In order to communicate with the MySQL server, this Pipeline explicitly
* maps the port (`3306`) to a known port on the host machine.
*/
docker.image('mysql:5').withRun('-e "MYSQL_ROOT_PASSWORD=my-secret-pw" -p 3306:3306') { c ->
/* Wait until mysql service is up */
sh 'while ! mysqladmin ping -h0.0.0.0 --silent; do sleep 1; done'
/* Run some tests which require MySQL */
sh 'make check'
}
}
示例:
下面的示例使用 withRun公开的项目, 它通过
id 属性具有可用的运行容器的ID。使用该容器的 ID, 流水线通过自定义 Docker 参数生成一个到inside()
方法的链。
node {
checkout scm
docker.image('mysql:5').withRun('-e "MYSQL_ROOT_PASSWORD=my-secret-pw"') { c ->
docker.image('mysql:5').inside("--link ${c.id}:db") {
/* Wait until mysql service is up */
sh 'while ! mysqladmin ping -hdb --silent; do sleep 1; done'
}
docker.image('centos:7').inside("--link ${c.id}:db") {
/*
* Run some tests which require MySQL, and assume that it is
* available on the host name `db`
*/
sh 'make check'
}
}
}
node {
checkout scm
def customImage = docker.build("my-image:${env.BUILD_ID}")
customImage.inside {
sh 'make test'
}
}
# 甚至可以直接通过push,dockerhub 或私有仓库, tag为可选参数
node {
checkout scm
def customImage = docker.build("my-image:${env.BUILD_ID}")
customImage.push('latest')
}
# 指定dockerfile的路径,构建镜像
node {
checkout scm
def testImage = docker.build("test-image", "./dockerfiles/test")
testImage.inside {
sh 'make test'
}
}
# 使用其他名称的文件构建镜像,如dockerfiles,-f覆盖默认的dockerfile
node {
checkout scm
def dockerfile = 'Dockerfile.test'
def customImage = docker.build("my-image:${env.BUILD_ID}", "-f ${dockerfile} ./dockerfiles")
}
注意:inside() 和 build() 不能正确的在Docker集群服务器中工作;会提示
cannot create /…@tmp/durable-…/pid: Directory nonexistent
需要先在Jenkins配置证书:swarm-certs,再通过url访问docker服务器地址
node {
checkout scm
docker.withServer('tcp://swarm.example.com:2376', 'swarm-certs') {
docker.image('mysql:5').withRun('-p 3306:3306') {
/* do things */
}
}
}
一般需要配置证书,如不需证书,删除’credentials-id’参数就好了
node {
checkout scm
docker.withRegistry('https://registry.example.com', 'credentials-id') {
docker.image('my-custom-image').inside {
sh 'make test'
}
}
}
共享库的目录结构
(root)
+- src # Groovy source files
| +- org
| +- foo
| +- Bar.groovy # for org.foo.Bar class
+- vars
| +- foo.groovy # for global 'foo' variable
| +- foo.txt # help for 'foo' variable
+- resources # resource files (external libraries only)
| +- org
| +- foo
| +- bar.json # static helper data for org.foo.Bar
# src 类似Java源目录结构。当执行流水线时,该目录被添加到类路径下
# var 目录定义可流水线访问的全局变量的脚本。每个*.groovy文件的基名都应该是Groovy标识符;*.txt, 为*.groovy文件的帮助文件
# resources 目录允许从外部库中使用的libraryResource步骤来加载非Groovy文件
全局共享库设置:Manage Jenkins » Configure System » Global Pipeline Libraries
库的使用:
@Library('my-shared-library') _
/* Using a version specifier, such as branch, tag, etc */
@Library('[email protected]') _
/* Accessing multiple libraries with one statement */
@Library(['my-shared-library', 'otherlib@abc1234']) _
# 或
library 'my-shared-library'
# 指定主分支master
library 'my-shared-library@master'
简单库的编写
# vars/log.groovy
def info(message) {
echo "INFO: ${message}"
}
def warning(message) {
echo "WARNING: ${message}"
}
# 使用
# Jenkinsfile, 必须在script里面使用这种类型的全部变量
@Library('utils') _
pipeline {
agent none
stage ('Example') {
steps {
script {
log.info 'Starting'
log.warning 'Nothing to do!'
}
}
}
}