使用Docker运行Jenkins服务(一)

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脚本,后面会逐步解读:

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
27
28
29
30
31
32
33
version: '2'
services:
jenkins:
image: jenkins/jenkins:2.60.3
volumes:
# let container use same timezone as host
- /etc/localtime:/etc/localtime
- /etc/timezone:/etc/timezone
# jenkins home
- /opt/docker/jenkins/jenkins.home:/var/jenkins_home
# JDK used for compiling Java project
- /usr/local/jdk1.8.0:/usr/local/jdk1.8.0
# Maven used for compiling maven project
- /usr/local/maven:/usr/local/maven
# node.js 6
- /usr/local/nodejs6:/usr/local/nodejs6
# node.js 8
- /usr/local/nodejs8:/usr/local/nodejs8

# Maven cache directory
- /home/sinopoweradmin/.m2:/var/jenkins_home/.m2
# Map docker cmd on host to container. used for docker image building
#- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
- /usr/lib/x86_64-linux-gnu/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7
# Map ssh config into docker
- /home/sinopoweradmin/.ssh:/var/jenkins_home/.ssh
ports:
# main port
- "8080:8080"
# used for cluster mode
- "50000:50000"
restart: always

4.1 Docker容器的时区

默认的Docker镜像中时区设置多数是UTC,与我们本地的时间(UTC+8)不一致。这会导致在Jenkins中显示的时间与本地时间有8小时的时差。为了解决这个问题,可以通过将本地时区文件映射到容器中解决:

1
2
- /etc/localtime:/etc/localtime
- /etc/timezone:/etc/timezone

4.2 JDK 8

Jenkins镜像中有JDK(用来运行Jenkins本身)。但是这个版本的JDK是OpenJDK 1.8。而我一般使用的是Oracle的JDK1.8。因此选择了在本地安装JDK1.8,然后挂载到镜像中去。

1
2
# JDK used for compiling Java project
- /usr/local/jdk1.8.0:/usr/local/jdk1.8.0

4.3 Maven

在Jenkins中可以直接安装Maven。但是因为GFW的原因,安装会比较慢,而且有可能失败。所以我选择和Java一样的方式在本地安装然后挂载到容器中。

1
2
# Maven used for compiling maven project
- /usr/local/maven:/usr/local/maven

4.4 Nodejs

Node.js的安装方法类似:

1
2
3
4
# node.js 6
- /usr/local/nodejs6:/usr/local/nodejs6
# node.js 8
- /usr/local/nodejs8:/usr/local/nodejs8

这里挂载了两个版本的Node.js。

4.5 Jenkins Home和Maven Cache

通过挂载本地目录,将Jenkins Home和Maven Cache都映射到宿主机上,而不是让Jenkins在容器内部管理。这样就可以保证升级版本不会丢失数据了。

1
2
3
4
# jenkins home
- /opt/docker/jenkins/jenkins.home:/var/jenkins_home
# Maven cache directory
- /home/sinopoweradmin/.m2:/var/jenkins_home/.m2

4.6 Docker

要在Jenkins内部使用Docker构建镜像、运行docker命令,就需要将宿主机的docker命令映射到容器中。所幸docker是一个C/S架构的软件,docker命令本身并不实际执行工作,只是负责将命令发送到Docker的服务程序中执行。因此我们只需要将docker命令本身映射到容器中即可。然后通过添加-H参数指定宿主机作为Docker服务主机即可执行docker相关任务。具体的以后会讲解。

1
2
3
4
# Map docker cmd on host to container. used for docker image building
#- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker
- /usr/lib/x86_64-linux-gnu/libltdl.so.7:/usr/lib/x86_64-linux-gnu/libltdl.so.7

4.7 ssh

1
2
# Map ssh config into docker
- /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以后会继续写博文说明。

附录A. 附录

热评文章