一、本文目的
- 在前面的文章中,所有的测试例子都是本地的、围绕着单个开发者的(就是说,如何让本地开发者使用Docker来测试本地网站或者引用程序)。现在来看看在多开发者的持续集成测试场景中如何使用Docker
- Docker很擅长快速创建和处理一个或多个容器。这个能力显然可以为持续集成测试这个概念提供帮助。在测试场景里,用户需要频繁安装软件,或者部署到多台宿主机上,运行测试,再清理宿主机为下一次运行做准备
- 在持续集成环境里,每天要执行好几次安装并分发到宿主机的过程。这为测试生命周期增加了构建和配置开销。打包和安装也消耗了很多时间,而且这个过程很恼人,尤其是需求变化频繁或者需要复杂、耗时的处理步骤进行清理的情况下
- Docker让部署以及这些步骤和宿主机的清理遍历开销很低。为了演示这一点,我们将使用Kenkins CI构建一个测试流水线:首先,构建一个运行Dokcer的Kenkins服务器。为了更有意思些,我们会让Dokcer递归地运行在Docker内部
- 一旦Jenkins运行起来,将展示最基础的单容器测试运行,最后将展示多容器的测试场景
备注
备注
- 除了Jenkins,还有许多其他的持续集成工具,包括Strider和Drone.io这种直接利用Docker的工具,这些工具都是真正基于Docker的。另外,Jenkins也提供了一个插件,这样就可以不用使用我们将要看到的Dokcer-in-Docker这种方式了。使用Docker插件可能更简单,但我觉得使用Docker-in-Docker这种方式很有趣
本文的代码、文件链接
二、构建带有Jenkins的Docker容器
①创建工作目录
- 与以往一样,创建一个jenkins目录,用来作为下面所有工作环境的主目录
mkdir jenkins
cd jenkins
②创建Dockerfile和脚本
- 第一步:在jenkins目录下创建一个Dockerfile,用来下面构建镜像,内容如下:
touch Dockerfile
vim Dockerfile
FROM jenkins/jenkins:lts
MAINTAINER https://blog.csdn.net/qq_41453285
ENV REFRESHED_AT 2020-07-27
USER root
RUN apt-get -qq update && apt-get install -qq sudo
RUN echo "jenkins ALL=NOPASSWD: ALL" >> /etc/sudoers
RUN wget http://get.docker.com/builds/Linux/x86_64/docker-latest.tgz
RUN tar -xvzf docker-latest.tgz
RUN mv docker/* /usr/bin/
USER jenkins
RUN /usr/local/bin/install-plugins.sh junit git git-client ssh-slaves greenballs chucknorris ws-cleanup
- 第二步:在jenkins目录下创建一个dockerjenkins.sh的脚本,并赋予可执行权限,脚本的内容如下:
touch dockerjenkins.sh
vim dockerjenkins.sh
chmod 0755 dockerjenkins.sh
#!/bin/bash
# First, make sure that cgroups are mounted correctly.
CGROUP=/sys/fs/cgroup
[ -d $CGROUP ] ||
mkdir $CGROUP
mountpoint -q $CGROUP ||
mount -n -t tmpfs -o uid=0,gid=0,mode=0755 cgroup $CGROUP || {
echo "Could not make a tmpfs mount. Did you use -privileged?"
exit 1
}
# Mount the cgroup hierarchies exactly as they are in the parent system.
for SUBSYS in $(cut -d: -f2 /proc/1/cgroup)
do
[ -d $CGROUP/$SUBSYS ] || mkdir $CGROUP/$SUBSYS
mountpoint -q $CGROUP/$SUBSYS ||
mount -n -t cgroup -o $SUBSYS cgroup $CGROUP/$SUBSYS
done
# Now, close extraneous file descriptors.
pushd /proc/self/fd
for FD in *
do
case "$FD" in
# Keep stdin/stdout/stderr
[012])
;;
# Nuke everything else
*)
eval exec "$FD>&-"
;;
esac
done
popd
docker daemon &
exec java -jar /opt/jenkins/jenkins.war
③构建镜像
- 第一步:输入下面的命令创建一个新镜像,镜像的名字为dongshao/dockerjenkins
sudo docker build -t dongshao/dockerjenkins .
- 构建的时间会很长,我这边构建了半个小时,最终的结果如下所示:
sudo docker images
④运行容器
- 第一步:基于上面的镜像,我们输入下面的命令创建一个新容器:
- -d:将容器以守护进程的模式在宿主机中运行
- -p:将Docker容器的8080端口映射到宿主机的8080端口上
- --name:容器的名字取名为jenkins
- --privileged:启动Docker的特权模式
- 最后一个参数:上面创建的镜像的名称
sudo docker run -d -p 8080:8080 --name jenkins --privileged -d dongshao/dockerjenkins
- 备注(--privileged选项):让Docker运行在--privileged特权模式会有一些安全风险。在这种模式下运行容器对Docker宿主机拥有root访问权限。确保已经对Docker宿主机进行了恰当的安全保护,并且只在确实可信的域中使用特权访问Docker宿主机,或者仅在有类似信任的情况下运行容器
- 第二步:查看一下新创建的容器:
# 查看当前正在运行的容器
sudo docker ps
访问Jenkins
- 第一步:现在我们就可以去访问jenkins主页了,输入“ip:8080”即可进入。进入之后会让你输入密码(见第二步)
- 第二步:初次进入需要输入密码,可以从Docker的日志容器中查看,如下所示日志的信息很多,内容大致为:
- 上面的:Jenkins服务运行时打印的日志
- 中间的:我们需要的密码()
sudo docker logs -f jenkins
- 第三步:将上面图片中中间所指的密码输入进去即可
- 第四步:之后会选择让你安装插件,选择默认的插件即可,选择之后进入下面的界面
- 第八步:重启之后刷新网页,输入上面创建的用户名和密码即可登录成功
三、创建新的Jenkins作业
- 上面Jenkins服务器已经运行起来了,现在我们可以来创建一个Jenkins作业了
- 第一步:点击主页中的“create new jobs”创建新作业
- 第二步:进入之后添加任务的名称(此处命名为“Docker_test_job”),并选择第一个,然后点击“确定”去到下一个界面
- 第四步:进入之后勾选“使用自定义的工作空间”,并填入下面的内容作为Directory(目录),这个目录是运行Jenkins的工作空间
/tmp/jenkins-buildenv/${JOB_NAME}/workspace
- 第五步:接着往下滑动,选择"Git",并添加下面的Github仓库链接,这个仓库包含了一些基于Ruby的RSpec测试
https://github.com/jamtur01/docker-jenkins-sample.git
- 第六步:接着往下滑动,在“增加构建步骤”中选择“执行shell”,跳到下一个画面
- 第七步:来到这个画面之后,把下面的脚本(jenkins_single_shell_step)输入进去,该脚本用来启动测试和Docker。内容如下:
- 1.使用包含上面Git仓库的Dockerfile创建一个新的Docker镜像(旋转到第八步看解析,再回到此处继续查看,此处不讲解)
- 2.创建一个包含Jenkins工作空间(就是签出Git仓库的地方)的目录,会把这个目录挂载到Docker容器,并在这个目录里执行测试
- 3.然后创建容器,并且运行了测试。在容器里,把工作空间挂载到/opt/project目录。之后执行命令切换到这个目录,并执行rake spec来运行RSPec测试
- 上面容器启动之后我们就可以拿到容器的ID
- Docker在启动容器时支持--cidfile选项,这个选项会让Docker截获容器ID并将其存到--cidfile选项指定的文件里,如--cidfile=/tmp/containerid.txt
- 4.使用docker attach命令进入容器,得到容器执行时输出的内容
- 5.使用docker wait命令,该命令会一直阻塞,直到容器里的命令执行完成才会返回容器退出时的返回码。变量RC捕获到容器退出时的返回吗
- 6.清理环境,删除刚刚创建的容器
- 7.使用容器的返回码退出,这个返回码应该就是测试执行结果的返回码。Jenkins依赖这个返回码得知作业的测试结果是成功哈市失败
# 脚本名为jenkins_single_shell_step
# 1.构建用于此作业的镜像
IMAGE=$(docker build . | tail -1 | awk '{ print $NF }')
# 2.构建挂载到Docker的目录
MNT="$WORKSPACE/.."
# 3.在Docker里执行编译测试
CONTAINER=$(docker run -d -v "$MNT:/opt/project/" $IMAGE /bin/bash -c 'cd /opt/project/workspace && rake spec')
# 4.进入容器,这样可以看到输出的内容
sudo docker attach $CONTAINER
# 5.等待程序退出,得到返回码
RC=$(docker wait $CONTAINER)
# 6.删除刚刚用到的容器
docker rm $CONTAINER
# 7.使用刚才的返回码退出整个脚本
exit $RC
- 第九步:接着点击“增加构建后操作步骤”,加入一个“Publish JUnit test result report”(公布JUint测试结果报告)的动作
- 第十步:接着上面,在“测试报告(XML)”中输入下面的内容,spec/reports/目录是ci_reporter gem的XML输出的位置,找到这个目录会让Jenkins处理测试的历史结果和输出结果
spec/reports/*.xml
- 第十二步:回到Jenkins主页中,就可以看到这个新作业了
四、运行Jenkins作业
- 上面我们创建了一个Jenkins作业,现在可以来运行这个作业了
- 第一步:点击这个作业
- 第二步:来到这个作业的界面中,之后点击左侧的“立即构建”按钮
- 备注:第一次测试时,可能会因为构建新的镜像而等待较长一段时间。但是,下次运行测试时,因为Docker已经准备好镜像了,执行速度会快很多
- 第三步:点击“构建历史”,就会出现这个作业
- 第四步:之后点击那个圆点,然后再点击“任务”的名称就会查看这个测试运行的详细信息
- 第六步:点击“控制台输出”可以查看作业已经执行的命令
- 很遗憾,运行到这里错误了,不知道为什么,查看了控制台的输出,发现是脚本错了,脚本执行到第3步的时候命令出错,也不知道什么原因,后来在脚本的docker命令之前加上sudo还是执行失败
- 就先到这里吧,不搞了