使用Jenkins的Swarm插件动态扩展CI环境

目录
  1. 构建Jenkins Server
  2. 构建Jenkins Slave

作者:杨冬 欢迎转载,也请保留这段声明。谢谢!
出处:https://andyyoung01.github.io/http://andyyoung01.16mb.com/

在将CI环境容器化以后,可以使整套环境更加容易从一个主机迁移到另一台主机上。然而随着项目的扩展,CI服务器的容量渐渐达到极限,所以可以动态增加CI服务器的容量是十分必要的。如果持续集成环境使用的是Jenkins的话,可以通过其Swarm插件来增加slave节点的数量。

对于中小型项目,使用一个Jenkins Server作为持续集成环境完全可以满足需要。只是随着项目的扩展,开发人员逐渐增多,Jenkins的工作负载逐渐增大,此台服务器的容量也渐渐达到极限。如下图所示:
“单台Jenkins Server,无法动态扩展”
一个很好的解决方案是,随着开发人员的加入,同时增加Jenkins slave节点的数量,每加入一个开发人员的同时,都增加一个worker node,如下图:
“随着开发人员的增加动态扩展CI”
上面这种方式使用了Jenkins Swarm的插件,它允许安装了Jenkins Swarm Server插件的master可以连接到slave节点上,并且运行任务。下面来看一下整套环境的构建过程。

构建Jenkins Server

我们将使用Jenkins的官方镜像作为基础镜像,加入了一个Plugin ID为swarm的插件,赋予了运行该镜像后的容器可以访问其所在主机的Docker socker的能力。

Dockerfile
1
2
3
4
5
6
7
8
9
10
11
FROM jenkins:2.7.2
# install-plugins. Here only install swarm plugin. You can install whichever plugins you need.
RUN /usr/local/bin/install-plugins.sh swarm
# Use `grep -w ^docker /etc/group` to find out the group id of docker on your host. Assign it to DOCKER_GROUPID_ON_HOST variable.
ARG DOCKER_GROUPID_ON_HOST=980
USER root
RUN groupadd -g ${DOCKER_GROUPID_ON_HOST} docker
RUN addgroup -a jenkins docker
USER jenkins

使用命令docker build -t jenkins_server_swarm .进行构建。
构建完成后得到了一个名为jenkins_server_swarm的镜像。该镜像中的jenkins用户由于加入了docker用户组,并且该用户组的docker组id与主机上的docker组ID相同,因此该镜像可以通过将主机上的docker.sock挂载进入容器中的docker.sock而具有访问权限,从而可以通过此容器化的Jenkins服务器构建Docker镜像。

注意:如果计划在Jenkins Docker容器内部运行docker的话,容器中的docker组id必须和容器所在主机的组id相同。如果这样做,这会带来潜在的迁移性的问题(因为各个不同主机上的docker组id也许会不同)。
另外一个解决方案:给jenkins用户分配免密码的sudo权限(通过echo “jenkins ALL=NOPASSWD: ALL” >> /etc/sudoers实现),然后容器中的所有命令前加sudo命令。这样便解决了镜像的移植性的问题。

使用如下命令运行容器:

1
2
3
4
5
6
docker run --name jenkins_server_swarm -p 8080:8080 \
-p 50000:50000 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $HOME/jenkins:/var/jenkins_home \
-d \
jenkins_server_swarm

上面代码需要注意的是,确保主机上的$HOME/jenkins目录可以由容器中的jenkins用户访问(jenkins用户的uid是1000)。如果在主机上用户的uid也是1000的话,这就没有问题。
访问http://host-ip:8080,第一次访问需要初始密码,按照页面的提示找到初始密码后登陆,进行一些初始配置。然后进入插件管理页面,可以看到Swarm插件已经安装:
{% asset_img 3.png “Jenkins Server with swarm plugin”%}

构建Jenkins Slave

下面的Dockerfile创建了一个安装了Jenkins Swarm client plugin的镜像:

Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM ubuntu:16.04
# Add jenkins_slave user and group
# Use `grep -w ^docker /etc/group` to find out the group id of docker on your host. Assign it to DOCKER_GROUPID_ON_HOST variable.
ARG DOCKER_GROUPID_ON_HOST=980
RUN groupadd -g ${DOCKER_GROUPID_ON_HOST} jenkins_slave
RUN useradd -d /home/jenkins_slave -s /bin/bash -m jenkins_slave -u 1000 -g jenkins_slave
RUN echo jenkins_slave:jpass | chpasswd
RUN apt-get update && apt-get install -y default-jre wget unzip
RUN wget -O /home/jenkins_slave/swarm-client-1.22-jar-with-dependencies.jar https://repo.jenkins-ci.org/releases/org/jenkins-ci/plugins/swarm-client/2.2/swarm-client-2.2-jar-with-dependencies.jar
COPY startup.sh /usr/bin/startup.sh
RUN chmod +x /usr/bin/startup.sh
USER jenkins_slave
ENTRYPOINT ["/usr/bin/startup.sh"]

上面代码的第11行下载了swarm-client的插件;第12行将一个启动脚本添加进镜像。

JENKINS/Swarm插件的官方地址:https://wiki.jenkins-ci.org/display/JENKINS/Swarm+Plugin

下面是启动脚本的代码:

startup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
if [ -z "$JENKINS_SERVER" ]; then
echo 'please provide IP address using "-e JENKINS_SERVER=ipaddress" option'
exit 1
fi
if [ -z "$JENKINS_USERNAME" ]; then
echo 'please provide username using "-e JENKINS_USERNAME=username" option'
exit 1
fi
if [ -z "$JENKINS_PASSWORD" ]; then
echo 'please provide password using "-e JENKINS_PASSWORD=password" option'
exit 1
fi
JENKINS_PORT=${JENKINS_PORT:-8080}
JENKINS_LABELS=${JENKINS_LABELS:-swarm}
JENKINS_HOME=${JENKINS_HOME:-$HOME}
echo "Starting up swarm client with args:"
echo "$@"
echo "and env:"
echo "$(env)"
set -x
java -jar /home/jenkins_slave/swarm-client-1.22-jar-with-dependencies.jar -fsroot "$JENKINS_HOME" -labels "$JENKINS_LABELS" -master http://$JENKINS_SERVER:$JENKINS_PORT -username "$JENKINS_USERNAME" -password "$JENKINS_PASSWORD" $@
sleep infinity

脚本2-13行判断是否从Docker命令行设置了环境变量JENKINS_SERVER,JENKINS_USERNAME,JENKINS_PASSWORD的值,这三个变量分别指定Jenkins master服务器的IP地址,登陆Jenkins服务器的用户名及密码,如果没有设置程序立即退出;14-16行允许通过docker命令行设置另外的环境变量,如果命令行没有指定则使用默认值;18-21行显示一些debug的信息;22行是将执行的命令都显示出来;23行是使用swarm-client命令行工具连接到Jenkins master上;最后一行确保容器一直运行。
使用命令docker build -t jenkins_swarm_slave .进行镜像构建。使用下面的命令启动容器:

1
2
3
4
5
docker run --name jenkins_swarm_slave \
-e JENKINS_SERVER=192.168.71.131 \
-e JENKINS_USERNAME=yourUserName \
-e JENKINS_PASSWORD=yourPassWord \
jenkins_swarm_slave

现在你已经在这台机器上设置了Jenkins slave,可以在其上运行任务了。当设置Jenkins job时,可以指定lable为swarm,这会将任务的执行位置限制在有swarm的lable的节点上。当然可以设置不同的lable来进一步控制任务的执行位置。