1. Jenkins是什么?
某百科的解释是:
Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。
这个解释大体上是靠谱的,Jenkins的核心作用就是一个CI(持续集成)工具。CI的概念是:持续集成指的是,频繁地(一天多次)将代码集成到主干。持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。而Jenkins能够完成这些自动化构建、测试的大部分工作。
Jenkins的前身是Hudson。这其中的渊源涉及到Oracle收购Java引起的版权纷争。有兴趣的可以看附录里面的相关链接。
2. 为什么用Docker
为什么用Docker运行Jenkins?个人感觉Docker通过镜像封装,可以屏蔽大量的搭建运维环境的琐碎操作。运维人员可以将Jenkins看成一个独立软件,而不需要关心其中的细节,例如Java运行环境怎么配置、Jenkins目录放在哪儿等等问题。使用Docker可以简单的配置几个运行参数,就可以迅速的启用Jenkins,大大降低了搭建的难度。
3. 搭建目标
根据目前项目的需求,搭建这个Jenkins环境需要能够支持几个功能:
- 能够进行Docker镜像构建,运行;
- 能够支持Nodejs类型项目;
- 能够支持Java Maven类型项目;
4. 搭建步骤
根据上面的需求,直接先上最后的docker-compose脚本,后面会逐步解读:
1version: '2'
2services:
3 jenkins:
4 image: jenkins/jenkins:2.60.3
5 volumes:
6 # let container use same timezone as host
7 - /etc/localtime:/etc/localtime
8 - /etc/timezone:/etc/timezone
9 # jenkins home
10 - /opt/docker/jenkins/jenkins.home:/var/jenkins_home
11 # JDK used for compiling Java project
12 - /usr/local/jdk1.8.0:/usr/local/jdk1.8.0
13 # Maven used for compiling maven project
14 - /usr/local/maven:/usr/local/maven
15 # node.js 6
16 - /usr/local/nodejs6:/usr/local/nodejs6
17 # node.js 8
18 - /usr/local/nodejs8:/usr/local/nodejs8
19
20 # Maven cache directory
21 - /home/sinopoweradmin/.m2:/var/jenkins_home/.m2
22 # Map docker cmd on host to container. used for docker image building
23 #- /var/run/docker.sock:/var/run/docker.sock
24 - /usr/bin/docker:/usr/bin/docker
25 - /usr/lib/x86_64-linux-gnu/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7
26 # Map ssh config into docker
27 - /home/sinopoweradmin/.ssh:/var/jenkins_home/.ssh
28 ports:
29 # main port
30 - "8080:8080"
31 # used for cluster mode
32 - "50000:50000"
33 restart: always
4.1 Docker容器的时区
默认的Docker镜像中时区设置多数是UTC,与我们本地的时间(UTC+8)不一致。这会导致在Jenkins中显示的时间与本地时间有8小时的时差。为了解决这个问题,可以通过将本地时区文件映射到容器中解决:
1 - /etc/localtime:/etc/localtime
2 - /etc/timezone:/etc/timezone
4.2 JDK 8
Jenkins镜像中有JDK(用来运行Jenkins本身)。但是这个版本的JDK是OpenJDK 1.8。而我一般使用的是Oracle的JDK1.8。因此选择了在本地安装JDK1.8,然后挂载到镜像中去。
1# JDK used for compiling Java project
2 - /usr/local/jdk1.8.0:/usr/local/jdk1.8.0
4.3 Maven
在Jenkins中可以直接安装Maven。但是因为GFW的原因,安装会比较慢,而且有可能失败。所以我选择和Java一样的方式在本地安装然后挂载到容器中。
1 # Maven used for compiling maven project
2 - /usr/local/maven:/usr/local/maven
4.4 Nodejs
Node.js的安装方法类似:
1 # node.js 6
2 - /usr/local/nodejs6:/usr/local/nodejs6
3 # node.js 8
4 - /usr/local/nodejs8:/usr/local/nodejs8
这里挂载了两个版本的Node.js。
4.5 Jenkins Home和Maven Cache
通过挂载本地目录,将Jenkins Home和Maven Cache都映射到宿主机上,而不是让Jenkins在容器内部管理。这样就可以保证升级版本不会丢失数据了。
1 # jenkins home
2 - /opt/docker/jenkins/jenkins.home:/var/jenkins_home
3 # Maven cache directory
4 - /home/sinopoweradmin/.m2:/var/jenkins_home/.m2
4.6 Docker
要在Jenkins内部使用Docker构建镜像、运行docker命令,就需要将宿主机的docker命令映射到容器中。所幸docker是一个C/S架构的软件,docker命令本身并不实际执行工作,只是负责将命令发送到Docker的服务程序中执行。因此我们只需要将docker命令本身映射到容器中即可。然后通过添加-H
参数指定宿主机作为Docker服务主机即可执行docker相关任务。具体的以后会讲解。
1 # Map docker cmd on host to container. used for docker image building
2 #- /var/run/docker.sock:/var/run/docker.sock
3 - /usr/bin/docker:/usr/bin/docker
4 - /usr/lib/x86_64-linux-gnu/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7
4.7 ssh
1 # Map ssh config into docker
2 - /home/sinopoweradmin/.ssh:/var/jenkins_home/.ssh
这一段关于ssh的配置是将运行docker用户主目录中的.ssh目录映射到Jenkins容器中。这样做的好处是两者共享了同样的ssh密钥以及known_hosts信息:只要能够在宿主机上通过SSH证书登录的主机也就可以在Jenkins容器中登录。(有关SSH证书无密码登录的内容请参考以前的文章)。
5. 运行
使用docker-compose
运行就可以启动Jenkins了。
5.1 初始化密码
Jenkins第一次运行的时候会自动生成初始化密码。通过docker logs -f jenkins_jenkins_1
查看日志可以找到这个密码。或者进入JENKINS_HOME中找到相关文件也可以找到这个密码。
6. 一些说明
- Jenkins镜像推荐不要选用Alpine版本的镜像,有时候会出现一些兼容性问题。例如出现docker命令无法执行的问题。
- 关于如何在Jenkins中创建、执行Job以后会继续写博文说明。