前期介绍:
- 基于Python+unittest的接口自动化测试框架,打算使用Docker容器技术+jenkins持续集成的能力实现接口自动化测试的持续集成
- 前提:了解jenkins的使用
Docker简介
概念
- 虚拟化:一种资源管理技术(虚拟机、内存管理、硬盘分区管理)
- Docker是什么:
- 虚拟化技术的一种,虚拟容器技术,模拟一个极小的linux系统(dockerfile)
- 沙箱机制:基于一个exe文件创建的应用,都是相互独立的(隔离),比如一个iso,可以在vmware中创建多个虚拟机,这些虚拟机是相互独立的
- 镜像:类似创建centos的.iso镜像文件
- 容器:基于docker镜像创建出来的系统(相当于.iso镜像创建的linux系统)
- windows>>>虚拟技术(VMware软件)>>>.iso镜像文件>>>得到一个centos系统
- linux>>>虚拟技术(docker软件)>>>镜像文件(体积小)>>>得到一个centos系统
docker解决什么问题:
一个场景:假如写了一个网站,想要让其他人也能访问,那么需要配置相同的软件(数据库、web服务器、插件、库等),但是这个过程由于各种原因比如软件版本、操作系统版本等有很大概率会运行失败
docker安装
- 我们可以设置yum源为阿里云(速度更快)
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
- 我们可以安装docker社区版(docker-ce社区版免费)
yum -y install docker-ce docker-ce-cli containerd.io
- 安装后查看docker版本
docker -v
- 设置ustc镜像站点(指定注册中心地址)
vim /etc/docker/daemon.json
{
"registry-mirrors":["https://docker.mirrors.ustc.edu.cn"]
}
docker优点
- 快速的构建环境
- 资源占用很少
- 运维更简单了
- 一台机子可以创建N个容器,合理利用资源节约资源
docker应用场景
- 部署测试环境,生成环境,验收环境
- 微服务结构
- 自动化项目的部署
Docker常用命令
docker启停命令
- 启动docker服务:
systemctl start docker
- 停止docker服务:
systemctl stop docker
- 重启:
systemctl restart docker
- 查看docker状态:
systemctl status docker
- 查看docker版本:
docker -v
- 开机自动启动:
systemctl enable docker
docker镜像命令
jenkins镜像命令
docker pull qinhaili/new_enkins:haili
python镜像命令
docker pull qinhaili/python3:haili
- 查看镜像:
docker images
- 拉取镜像:
docker pull 镜像名称:标签
在这里找镜像(docker hub):https://hub.docker.com
如果拉取镜像的时候不加标签,默认拉取最新的镜像,标签为latest - 搜索镜像:
docker search 镜像名称
不能直接找到对应的详细版本信息,只能去网站上去找 - 删除镜像
- docker rmi 镜像名称:标签
- docker rmi -f 镜像名称:标签
- docker rmi 镜像id
- 修改镜像名称docker tag 老镜像名称::标签 新镜像名称:标签,案例:
docker tag python:3.10.7-alpine python3.10.7:haili
docker中的容器命令
- 创建容器:
- 交互式创建容器:
docker run -it python3.10.7:haili
- -i:表示以交互式的方式运行容器
- -t:分配一个命令行的client终端
- 创建容器后,会自动执行cmd里面的命令,查看cmd命令在这里:
docker image inspect 镜像名:标签
- 守护式创建容器:
docker run -di --name test 镜像名:标签 /bin/bash
- --name:为将要创建的容器起一个名称
- /bin/sh:在容器内运行的命令,指示容器使用Bash shell,当容器启动的时候,就会打开一个Bourne shell以供用户交互(这里边的命令会覆盖上述提到的cmd命令,如果这里没有指定,仍会默认执行cmd中的命令)
- 交互式创建容器:
Bourne shell 是 Unix 系统中的一种标准的命令行解释器,它通常是 Bash shell 的一个轻量级替代品,具有较少的功能和更少的依赖
-
查看运行中的容器:
docker ps
,查看所有运行中的容器:docker ps -a
-
删除容器:
docker rm 容器名称/id
-
进入容器:
docker exec -it docker_name /bin/sh
docker exec -it -u 0 docker_name /bin/sh
docker exec -it --user root docker_name /bin/sh
-
退出容器:
exit;
-
容器启动与停止:
- 启动:
docker start 容器名称(或者容器id)
- 停止:
docker stop 容器名称(或者容器id)
- 重启:
docker restart 容器名称(或者容器id)
- 杀掉:
docker kill 容器名称(或者容器id)
- 启动:
-
文件拷贝(宿主机文件和容器文件相互隔离)
- 语法:
docker cp 宿主机需要拷贝的容器或者目录 容器名称:容器目录
- 案例:
docker cp test.py test_docker:/mnt/
- 语法:
-
目录映射(宿主机文件和容器文件相互同步)
docker run -id -v /mnt/:/mnt/ --name=python52 python3.10.7:haili /bin/sh
Dockerfile
基于某个基础的镜像(从docker hub上拉取下来)来打自己的镜像(结合自己项目情况,安装了自己项目所需要的软件等的镜像)
Dockerfile语法
Dockerfile中不要写注释!!!,以下仅为说明演示使用
# 使用基础镜像(FROM 镜像名称:标签)
FROM ubuntu:latest
# 设置工作目录(指定workspace,也就是进入容器后要进入哪个目录中)
WORKDIR /app
# 复制当前目录下的所有文件到容器的 /app 目录中(我们可以将所需要的依赖使用pip freeze命令导出到req.txt文件中,然后放到/app目录中)
COPY . /app
# 也可以使用
ADD ./req.txt /app
# 二者的区别是ADD会自动解压,COPY仅仅是复制
# 安装相关依赖
RUN apt-get update && apt-get install -y python3 python3-pip && pip3 install -r req.txt
# 启动应用程序
CMD ["python3", "main.py"]
注:RUN
命令是在容器创建的时候执行的命令CMD
命令是在容器启动的时候执行的命令,但是如果启动容器的时候传了命令进入启动命令,那么这里的命令就不会执行了,启动容器的时候执行的代码当然是我们的脚本执行代码
参考资料:Dockerfile 指令详解 - 测试派
Dockerfile指令解释
打镜像的命令
创建 Docker 镜像的命令是 docker build
。下面是使用 docker build
命令打包镜像的基本语法:
docker build [OPTIONS] PATH | URL | -
其中:
OPTIONS
:可以使用一系列选项来配置镜像构建的行为,例如指定镜像名称、标签、使用的 Dockerfile 路径等。PATH | URL | -
:指定 Dockerfile 所在的路径,可以是本地目录的路径、远程 URL 或者-
(表示标准输入)。
以下是一些常用的选项:
-t, --tag
:为生成的镜像设置名称和标签。--file
:指定要使用的 Dockerfile 路径,默认为当前目录下的Dockerfile
。-f, --force-rm
:在构建过程中删除任何临时容器。--no-cache
:在构建过程中不使用缓存。-q, --quiet
:减少输出信息,只显示构建进度条。
例如,要在当前目录下的 Dockerfile 中构建一个名为 myimage
,标签为 latest
的镜像,可以使用以下命令:
docker build -t myimage:latest .
这将会在当前目录下的 Dockerfile 中构建镜像,并为其设置名称为 myimage
,标签为 latest
。
需要注意的是,在执行 docker build
命令时,需要确保当前目录下存在 Dockerfile 文件,而且名称中的字母必须为小写字母,否则会报错
Docker+jenkins实现接口自动化思路
安装python环境
- 准备一个python容器
- 自己手动打一个镜像(有项目执行依赖包的镜像)
- 编写Dockerfile用来打镜像,参考如下:
FROM python:3-alpine # 第一行非注释行必须是FROM
WORKDIR /app #设置容器的工作空间目录
ADD ./xxx.txt /app #讲宿主机的依赖包文件添加到镜像里面
RUN pip install -r xxx.txt #安装依赖包,RUN是在打镜像的过程中执行的命令,建议少用RUN
CMD ["python","main.py"] #创建容器后自动执行的命令,但是如果启动容器的时候传了命令进去,这个命令会被覆盖
- 根据自己创建的镜像,创建一个python容器执行项目(指定容器运行的时候执行的命令):
docker build -t 镜像名称:标签 Dockerfile所在的目录
.:表是当前目录
案例: docker build -t ApiTestFrame20240416 .
Jenkins拉取代码并执行
第一步:创建一个Jenkins容器:
docker run -id --name=apijenkins -p 8809:8080 -u=root -v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock jenkins/jenkins:latest-jdk17
将宿主机的docker(docker客户端) 和docker.sock(docker客户端与服务器通讯的文件)映射到jenkins容器,执行docker命令的时候想就相当于在宿主机执行docker命令
命令解析:
这条命令作用是用 Docker 启动一个名为 "apijenkins" 的容器,并在其中运行 Jenkins 服务。
docker run
: 这是 Docker 命令,用于创建并运行一个新的容器。-id
: 这是两个选项的结合。-i
选项告诉 Docker 在后台运行容器(detached mode),而-d
选项告诉 Docker 使用交互模式,即使没有连接到它。这两个选项的结合通常用于需要后台运行的交互式容器。--name=apijenkins
: 这个选项用于为容器指定一个名称,即将创建的容器的名称为 "apijenkins"。-p 8809:8080
: 这个选项指定了端口映射,将主机上的 8809 端口映射到容器内的 8080 端口。这样,在主机上通过访问 8809 端口就可以访问到 Jenkins 服务。-u=root
: 这个选项指定了容器内执行命令时使用的用户身份,这里指定为 root 用户。-v /usr/bin/docker:/usr/bin/docker
: 这个选项用于将主机上的/usr/bin/docker
目录挂载到容器内的/usr/bin/docker
目录,这样容器内的应用程序就可以访问主机上的 Docker 可执行文件。-v /var/run/docker.sock:/var/run/docker.sock
: 这个选项用于将主机上的 Docker 守护进程的 Unix 套接字(socket)挂载到容器内的相同路径,这样容器内的应用程序就可以通过 Docker API 与主机上的 Docker 守护进程进行通信。jenkins/jenkins:latest-jdk17
: 这是要使用的 Docker 镜像的名称和标签。这里是从名为 "jenkins/jenkins" 的镜像中拉取标签为 "latest-jdk17" 的版本。
综上所述,该命令将创建一个名为 "apijenkins" 的容器,使用 "jenkins/jenkins:latest-jdk17" 镜像,并在容器内运行 Jenkins 服务。该容器将主机上的 8809 端口映射到容器内的 8080 端口,允许通过浏览器访问 Jenkins 服务。同时,该容器内的应用程序可以通过挂载主机上的 Docker 可执行文件和 Docker 守护进程的 Unix 套接字来与 Docker 进行交互。
第二步:jenkins构建后执行命令创建python容器
上一步创建号jenkins容器并且启动后,就可以在浏览器中访问jenkins页面,新建一个item,设置好代码仓库等必要配置后,进入item,找到item名称/Configure/Build Steps
,在Execute shell中添加如下代码:
start.sh这个文件需要在项目中创建一个start.sh文件,文件中添加以下命令用于参照指定的python镜像来创建python容器并且运行测试代码:
docker run --rm -w=$WORKSPACE --volumes-from=apijenkins apitestframe20240416
命令解析:
docker run
: 用于创建并运行一个新的容器。--rm
: 这个选项指定了容器退出时自动删除容器。这意味着当容器退出后,Docker 将自动删除该容器的文件系统。这对于临时性的任务非常有用,可以避免容器堆积在系统中。-w=$WORKSPACE
: 这个选项指定了容器的工作目录。$WORKSPACE
是一个环境变量,其值将被替换为当前宿主机的工作目录。这样,在容器内执行的命令将在指定的工作目录中执行。--volumes-from=apijenkins
: 这个选项指定了容器使用来自另一个名为 "apijenkins" 的容器挂载的卷。这意味着容器将共享 "apijenkins" 容器中挂载的卷,使得容器间可以共享数据。 (apijenkins是上述自己打的python镜像)apitestframe20240416
: 这是要运行的容器镜像的名称或 ID。Docker 将使用这个镜像来创建并运行一个新的容器。
总体而言,这行命令将创建并运行一个基于镜像 "apitestframe20240416" 的新容器。该容器将在当前宿主机的工作目录中运行,并共享名为 "apijenkins" 容器中挂载的卷。容器运行完毕后将会自动删除。
第三步:构建
做好上边工作之后,就可以去build我们的item了,构建完成后会自动生成HTML报告,但是在实际使用过程中发现生成的html报告没有样式,后来查阅后可以通过插件的方式来解决:
- 安装两个插件:startup trigger和groovy
- 在item配置选项中,设置两个地方:
- 勾选Build Triggers中的Build when job nodes start
- Build Steps中添加Execute system Groovy script,然后添加以下代码就可以了:
System.setProperty("hudson.model.DirectoryBrowserSupport.CSP","")
如果插件安装不下来(网络原因、版本兼容问题等等),也可以用下面这种方式,只不过这种方式需要每次都先执行一遍:找到manage jenkins/tools and actions/script consol中执行上述代码
总结
面试问题
如何实现持续集成?
面试过程中首要回答是逻辑清晰的思路,如果面试官追求细节问题再去回答,不要事无巨细就去把所有知道的细节都输出
通过Jenkins+Docker方式实现:
- 将自动化测试框架代码传到git仓库
- 创建jenkins容器
- 通过jenkins拉取测试代码
- 创建python容器,将jenkins拉取到的代码映射到python容器中执行
- 执行完成之后,自动删除python容器,在jenkins和邮件中查看测试报告
拓展(待补充)
Docker是一个C/S架构的应用
客户端位置:/usr/bin/
docker通讯文件:docker.sock,位置:/var/run
查看日志:docker logs 容器名称
Docker+jenkinsPipeline 运行 python 自动化 - 测试派