作为持续集成的利器Jenkins已经得到了广泛地应用,仅仅作为一个工具,Jenkins已然有了自己的生态圈,支持其的plugin更是超过1300+。在实际中如何使用以及如何更好地使用jenkins,一直是大家在实践并讨论的。本系列文章将会从如何使用jenkins方面对一些细节进行总结和整理,这篇文章将会介绍如何在jenkins的容器中进行镜像的构建。
原因
镜像的构建docker build需要damon进程的支持,如果构建者自身本身就在容器之中,这个就是很久之前讨论的很多的docker in docker的情况。而是用更多的方式则是利用docker用于socket通信的socket文件,这篇文章将会详细的介绍这种方式。
准备
这种方式对目前常见的版本一般来说影响不大,这篇文章使用1.13.1的版本进行验证。
宿主机的docker版本:
[root@host154 tools]# docker version
Client:
Version: 1.13.1
API version: 1.26
Go version: go1.7.5
Git commit: 092cba3
Built: Wed Feb 8 08:47:51 2017
OS/Arch: linux/amd64
Server:
Version: 1.13.1
API version: 1.26 (minimum version 1.12)
Go version: go1.7.5
Git commit: 092cba3
Built: Wed Feb 8 08:47:51 2017
OS/Arch: linux/amd64
Experimental: false
[root@host154 tools]#
启动jenkins在镜像之中
直接使用docker run或者使用docker-compose或者其他方式,将jenkins启动在容器之中,比如:
[root@host154 tools]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
46cc37b371cb liumiaocn/jenkins:2.73.3 "run.sh" About a minute ago Up About a minute 0.0.0.0:38080->8080/tcp tools_jenkins_1
[root@host154 tools]#
宿主机docker设定
宿主机docker的daemon进程需要设定如下两个选项:
-H tcp://0.0.0.0:4243
-H unix:///var/run/docker.sock
其实这个就是用于保证远程和本地两者都可以使用的方式。docker.sock这个文件,则是用于进程间通信用的,从其类型上的s可以清楚地看到这一点
[root@host154 tools]# ls -l /var/run/docker.sock
srw-rw----. 1 root root 0 Jan 12 06:26 /var/run/docker.sock
[root@host154 tools]#
#
宿主机的docker build确认
由于镜像中的docker build最终还是借用于宿主机的docker build能力,所以在容器中构建镜像成功之前,最好先确认宿主机可以进行正常的docker build,比如我们将alpine镜像中加上时区设定的tzdata
[root@host154 tools]# cat Dockerfile
FROM alpine
RUN apk update && apk add tzdata
[root@host154 tools]#
镜像构建
[root@host154 tools]# docker build -t alpine-tz:latest .
Sending build context to Docker daemon 3.072 kB
Step 1/2 : FROM alpine
---> 3fd9065eaf02
Step 2/2 : RUN apk update && apk add tzdata
---> Running in 917d72bd3737
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
v3.7.0-50-gc8da5122a4 [http://dl-cdn.alpinelinux.org/alpine/v3.7/main]
v3.7.0-49-g06d6ae04c3 [http://dl-cdn.alpinelinux.org/alpine/v3.7/community]
OK: 9044 distinct packages available
(1/1) Installing tzdata (2017c-r0)
Executing busybox-1.27.2-r7.trigger
OK: 7 MiB in 12 packages
---> 42cd12f65952
Removing intermediate container 917d72bd3737
Successfully built 42cd12f65952
[root@host154 tools]#
构建之后的确认
[root@host154 tools]# docker images |grep alpine
alpine-tz latest 42cd12f65952 4 minutes ago 6.69 MB
alpine latest 3fd9065eaf02 2 days ago 4.14 MB
[root@host154 tools]#
至此说明宿主机的docker build是正常的,如果受困于内网/外网/代理等问题,可以将RUN的那句去掉,因为主要是为了验证能否进行docker build。
拷贝docker文件到镜像之中
为了使得在jenkins容器中能够正常地构建镜像,需要将docker文件先拷贝到镜像之中,使之用于作为客户端将指令传递给宿主机的docker守护进程,这可能是最方便的方法之一。
[root@host154 ~]# which docker
/usr/bin/docker
[root@host154 ~]# docker cp /usr/bin/docker tools_jenkins_1:/usr/bin/docker
[root@host154 ~]#
结果确认
[root@host154 ~]# docker exec -it tools_jenkins_1 sh
/ # which docker
/usr/bin/docker
/ # docker version
Client:
Version: 1.13.1
API version: 1.26
Go version: go1.7.5
Git commit: 092cba3
Built: Wed Feb 8 08:47:51 2017
OS/Arch: linux/amd64
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
/ #
镜像构建
事前准备
将确认成功的dockerfile拷贝到镜像之中
[root@host154 tools]# docker cp Dockerfile tools_jenkins_1:/tmp
[root@host154 tools]#
拷贝确认
[root@host154 tools]# docker exec -it tools_jenkins_1 sh
/ # cd /tmp
/tmp # ls Dockerfile
Dockerfile
/tmp #
有很多种方法都可以构建成功,这里举出比较常用的两种方式:
构建:方法1
最清晰明了的方式是通过-H指定,可以做如下指定即可:
/tmp # docker -H tcp://192.168.163.154:4243 build -t alpine-tz-docker:latest .
Sending build context to Docker daemon 2.136 MB
Step 1/2 : FROM alpine
---> 3fd9065eaf02
Step 2/2 : RUN apk update && apk add tzdata
---> Using cache
---> 42cd12f65952
Successfully built 42cd12f65952
/tmp #
构建:方法2
如果因为各种原因,比如同一份代码,不同地方出现,而又不希望修改,总之不希望出现-H在命令之中,那可以使用DOCKER_HOST环境变量解决这个问题
/tmp # export DOCKER_HOST=tcp://192.168.163.154:4243
/tmp # docker build -t alpine-tz-docker:latest .
Sending build context to Docker daemon 2.136 MB
Step 1/2 : FROM alpine
---> 3fd9065eaf02
Step 2/2 : RUN apk update && apk add tzdata
---> Using cache
---> 42cd12f65952
Successfully built 42cd12f65952
/tmp #
至此,在容器中构建镜像已经成功,接下来就比较简单了,只要保证jenkins能够使用这个能力即可,再有问题,基本就是jenkins的设定和使用方式的问题了。
Jenkins镜像构建方式
jenkins上需要安装docker的镜像,具体的集成方式在基础篇5中有了详细的说明,不再赘述。
Jenkinsfile
构建时最直接的方式可以使用pipeline创建一个stage,再其中直接使用sh来执行上述执行的docker build命令即可,比如
node {
stage('镜像构建'){
sh "cd /tmp/; docker -H tcp://192.168.163.154:4243 build -t alpine-tz-docker:latest ."
}
}
构建结果
构建日志
从jenkins的构建日志中可以清楚地看到docker build的结果
Started by user root
[Pipeline] node
Running on Jenkins in /data/jenkins/workspace/docker-imagebuild
[Pipeline] {
[Pipeline] stage
[Pipeline] { (????)
[Pipeline] sh
[docker-imagebuild] Running shell script
+ cd /tmp/
+ docker -H tcp://192.168.163.154:4243 build -t alpine-tz-docker-1:latest .
Sending build context to Docker daemon 2.136 MB
Step 1/2 : FROM alpine
---> 3fd9065eaf02
Step 2/2 : RUN apk update && apk add tzdata
---> Using cache
---> 42cd12f65952
Successfully built 42cd12f65952
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
或者使用docker image也可以看到刚刚构建成功的镜像,日志中显示的????似乎是stage名称的中文支持不好,建议使用英文。
其他方式
除了设定DOCKER_HOST,还可以使用jenkins提供的docker-workflow,原理都是一样,设定方法不同而已,比如上述写法可以改成:
node {
stage('镜像构建'){
withDockerServer([uri: 'tcp://192.168.163.154:4243']) {
docker.build "alpine-tz-docker:latest","/tmp"
}
}
}
总结
这篇文章介绍了如何在容器中构建镜像以及jenkins中如何构建镜像。