对应英文文档:https://jenkins.io/doc/book/pipeline/docker/
本系列主贴直达:https://testerhome.com/topics/11265
许多组织都是用 Docker 来统一编译和测试环境,提供一个发布应用的有效机制。从 Pipeline 2.5 版本或者更高,Pipeline 内嵌支持同 Jenkinsfile 内 Docker 交互。
本章覆盖了使用 Jenkinsfile 内 Docker 基本使用,并不包括 Docker 的使用。关于 Docker 使用,请参考https://docs.docker.com/get-started/。
Pipeline 较早被设计使用 Docker images 作为执行环境,执行一个单独的 stage 或者整个 Pipeline,意味着用户可以定义他们的 Pipeline 需要使用的工具,不必手动配置代理。实践上,任何工具都能被打包到 Docker container 中,能被一个 Jenkinsfile 容易使用。
当 Pipeline 执行的时候,Jenkins 自动开启特定的 container,执行里面定义的 steps。
许多编译工具会下载外部依赖,并把它们缓存在本地。因为 containers 初始化的时候是干净的文件系统,这能导致较小的 Pipelines,因此他们并不能充分利用硬盘缓存的优势。
Pipeline 支持添加定制化参数,参数能被传入到 Docker 中,允许用户指定特定的 Docker Volumes 去挂载,Volumes 能被用来缓存代理上的数据。下面的例子将在 Pipeline 运行的时候,缓存~/.m2,可以避免重复下载依赖。
注意:实测表明
使用本地机器的 maven repo,不用再单独下载的技巧,要点在于
(1).启动 docker 的时候就要传入 repo
(2).启动编译命令的时候,要再传一次 repo,否则 mvn 会单独下载依赖的包
现在非常普遍,代码依赖多个,不同的技术。例如一个库既有 Java-based 的后端 API 实现,也有 JavaScript 基础的前端实现。组合 Docker 和 Pipeline,允许 Jenkinsfile 通过 agent{}在不同阶段使用多种技术。
对于那些需要特定执行环境的项目,Pipeline 同样支持在 Dockerfile 中创建和运行容器 (container)。同前面使用” off-the-shell” 容器相反,使用代理{dockerfile true}语法将创建新的 image,而不是从 Docker Hub 拉取。
重新使用前面的例子,用一个定制化的 Dockerfile。
Dockerfile
把这个提交到源代码库的根目录,Jenkinsfile 被改变去构建一个基于这个 Dockerfile 的容器,用这个容器运行定义好的 steps。
agent { dockerfile true}语法支持许多其他选项,关于这些选项详见Pipeline Syntax部分。
Using a Dockerfile with Jenkins Pipeline
注意:笔者添加。
其他一些使用说明,请参见:https://github.com/jenkinsci/pipeline-model-definition-plugin/wiki/Syntax-Reference
其实本例的目的:仅仅只是制作了一个新的 docker image,完全可以自己手动做,也可以使用 linux shell 脚本和 docker 配合使用做出来,不一定非要通过 Jenkins 的插件做。此方法的一个不好的地方就是:自己设置生成的 image 的名字以后,通过参数加进去,最终会出来两个一样的 docker image,因为再生成的时候,必须要设置一个名字,哪怕是随机的名字。
参数如下:
agent { dockerfile true }
agent {
dockerfile {
additionalBuildArgs '-t node-svn:7-alpine'
}
}
默认情况下,Pipeline 假设任何配置的代理都能运行基于 Docker 的 Pipeline。对于 Jenkins 环境,有 macOS,Windows 或者其他不能运行 Docker 代理,默认设置可能有问题。Pipeline 在 Manage Jenkins 页面 (manage Jenkins-->Configuration) 上提供一个全局选项。
注意:测试表明
此 label 只是为了区分在哪个 node 上运行,本例运行的 node label 为:linux,其实换成 master 应该也可以,如果不设置,就会寻找一个默认的本地的符合条件的 node 执行。
在 Pipeline 中使用 Docker 是运行服务/一套测试的一个有效方式,类似于 sidecar 模式,Docker Pipeline 能在后台运行容器。使用 sidecar 方法,对于每一次 Pipeline 运行,Pipeline 能有一个干净的容器。
考虑一个依赖于本地 MySQL 数据库的集成测试套件。使用插件docker-workflow插件实现的 withRun 方法,一个能运行 MySQL 作为 sidecar 的 Jenkinsfile 文件:
注意:本例笔者运行失败。
(1).本地必需安装有 mysqladmin 工具,否则执行失败。
(2).docker run -d -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 mysql:5 这样启动以后,确实发现 container 里面的 mysql 启动成功,但是如果使用 docker run -d -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 mysql:5 /bin/sh 进去以后,发现 mysql 没有启动,或者说启动失败。
示例可以更进一步,同时使用两个容器。一个” sidecar” 运行 MySQL,另一个用 Docker container links 提供执行环境。
上面的示例使用 withRun 暴露的对象,withRun 有运行的容器 ID。用容器 ID,Pipeline 能创建一个链接,通过传递客制化的 Docker 参数到 inside() 方法。
Id 属性对于查看正在运行容器的 log 同样有用:
注意:笔者实测,
执行的 sh 命令都是在 container 里面执行的。所以起了两个 container。
创建一个 Docker image,插件 docker-workflow 同样提供一个build()方法创建新的 image,在 Pipeline 运行的时候,从代码库中的 Dockerfile 文件也能创建 image。
使用docker.build(“my-image-name”))语法的一个主要好处:脚本是的 Pipeline 能使用返回值用于后面的 Docker Pipeline 调用,例如:
返回值能被用来保存 Docker image 到 Docker Hub 或者私有的 Registry,通过push()方法,例如:
Image 的 tag 属性常用方法是latest标记。push()方法接受一个可选的tag参数,允许 Pipeline 用不同的标记存储customImage,例如:
笔者注:
此类制作 image,完全可以 shell 和 docker 独立做,如有必要,可以来此参照执行。
默认情况下,插件 docker-workflow 会和本地的 Docker 交互,典型的是通过/var/run/docker.sock。
选择一个不是非默认 Docker server,例如 Docker Swarm,withServer()方法可以使用。
通过传递一个 URI,可选的 Docker Server Certificate Authentication 认证信息,方法如下:
注意:inside()和build()将不能同 Docker Swarm server 正常工作。
对于函数inside()正常执行,Docker server 和 Jenkins 代理必须使用同样的文件系统,以便工作空间能被挂载。
现在 Jenkins 插件和 Docker CLI 都不能自动检测远端 server 运行的 case;一个典型的现象就是嵌套sh命令出现错误,例如
当 Jenkins 检测到代理运行在 Docker 容器中的时候,它将自动传递--volumes-from参数到inside容器,确保它能同代理共享工作空间。
另外,一些 Docker Swarm 版本并不支持定制化的 Registry。
默认情况下,docker-workflow 插件使用默认的 Docker Registry—Docker Hub。
为了使用定制化的 Docker Registry,脚本是的 Pipeline 用户可以用 withRegistry 方法去包含 steps,传递定制化的 Registry URL,例如:
对于需要认证的 Docker Registry,从 Jenkins 主页上添加用户名/密码项,并使用认证 ID 作为withRegistry()的第二个参数。
注意:此类是制作 docker image 然后保存到私有的 registry,可以 shell 和 docker 实现,如有必要,来此参照制作。
本系列主贴直达:https://testerhome.com/topics/11265