当我们构建好Docker镜像并利用多套容器共同组合成应用程序,建立起持续交付通道,了解了如何将新创建的镜像纳入到生产或者测试环境当中之后,新的问题来了——我们该如何测试自己的Docker容器?

测试的策略多种多样,反映了各种各样的测试性格:天真型,懒人省事型,超前理想主义型,完美主义处女座型……那么你是哪一型?

下面我们就对其各自的方案利弊进行逐一分析。

“天真”型方案

大多数人会将此作为默认方案。其利用CI服务器实现任务执行。在这项方案中,开发人员利用Docker作为软件包管理器,其实际效果优于jar/rpm/deb方案。CI服务器对应用程序代码进行编译,而后执行测试(包括单元、服务及功能等)。Docker中的build可复用以生成新的镜像,由此生成的镜像不仅包含应用程序的“二进制代码”,同时亦拥有运行时所必需的依赖性及配置。

不过为了实现应用程序的可移植性,我们需要放弃开发与测试的可移植能力。在这种情况下,我们无法在CI之外重新建立同样的开发与测试环境。为了创始这样一套新的测试环境,我们需要设置测试工具(正确版本与插件)、配置运行时与操作系统设定,同时获取相同版本的测试脚本与测试数据。

为了解决上述难题,我们需要考虑以下方案。

应用&测试容器方案

现在我们尝试创建单一捆绑包,其中应用程序“二进制代码”中包含全部必需的软件包、测试工具(包括对应版本)、测试工具插件、测试脚本以及其它各类测试环境元素。

这套方案的优势包括:

测试环境自身拥有可重复性——我们能够在CI、开发、分段或者生产环境当中使用完全相同的测试工具实现完全相同的测试效果。
我们能够立足特定时间点捕捉测试脚本,所以可将其复用于任意环境。
我们不需要对测试工具进行二次设置与配置——其已经成为镜像中的组成部分。

但这种方式也存在着显著弊端:

镜像体积直线增长——这是因为其中包含有测试工具、必要软件包、测试脚本甚至是测试数据。
特定测试配置可能对镜像运行时环境造成污染,甚至引入不必要的依赖性(集成测试中需要用到)。
我们还需要考虑如何处理测试结果与记录日志;如何将其导出以及向哪里导出。

通过以下经过简化的 Dockerfile,我们可以了解上述方案的整个流程。

FROM "<bases image>":"<version>"WORKDIR "<path>"# install packages required to run app and tests
RUN apt-get update && apt-get install -y \"<app runtime> and <dependencies>" \  # add app runtime and required packages"<test tools> and <dependencies>" \     # add testing tools and required packages&& rm -rf /var/lib/apt/lists/*# copy app files
COPY app app
COPY run.sh run.sh# copy test scripts
COPY tests tests# copy "main" test command
COPY test.sh test.sh# ... EXPOSE, RUN, ADD ... for app and test environment# main app command
CMD [run.sh, "<app arguments>"]# it's not possible to have multiple CMD commands, but this is the "main" test command
# CMD [/test.sh, "<test arguments>"]

毫无疑问,应该有更好的容器内测试方案可供选择。

测试感知型容器方案

目前,Docker承诺以“Build -> Ship -> Run”这一简单操作完成镜像构建、发布至注册表并在其它位置运行等任务。不过恕我直言,其中还缺少了Test这一重要环节。正确且完整的流程应该是Build -> Test -> Ship -> Run。

下面让我们看看能够为Docker命令提供“测试友好”型语法与扩展的Dockerfile是如何建立而成的。当然,其中并不涉及真正的语法,只是我个人更偏好这样表述。我定义出了自己的“理想”版本(真的只是理想版本,仅供大家借鉴其中的思想,小数注),大家应该能够看出其中可用于实践的指导思路。

ONTEST [INSTRUCTION]

首先定义一条特殊的ONTEST指令,其与现有ONBUILD指令非常相似。ONTEST指令会向镜像添加一条触发指令,其在随后镜像接受测试时自动执行。任意build指令都可被注册为触发条件。

ONTEST指令可由一条新的docker test命令进行识别。

docker test [OPTIONS] IMAGE [COMMAND] [ARG...]

事实上,docker test命令的语法与docker run命令非常相似,二者只存在一项区别:前者会自动生成一套新的“可测试”镜像,甚至为其提供<image name>:<image tag>-test 标签(向原始镜像标签中添加‘test’标签)。此可测试镜像将由初始应用镜像生成,执行全部build操作,于ONTEST命令后进行定义并执行ONTEST CMD(或者ONTEST ENTRYPOINT)。其中若测试发生错误,docker test命令应当返回一段非零代码。此测试结果应当被写入至自动生成且指向/var/tests/results文件夹的VOLUME。

下面我们来看看经过修改的Dockerfile——其中包含新的ONTEST指令。

FROM "<base image>":"<version>"WORKDIR "<path>"# install packages required to run app
RUN apt-get update && apt-get install -y \"<app runtime> and <dependencies>" \  # add app runtime and required packages&& rm -rf /var/lib/apt/lists/*# install packages required to run tests
ONTEST RUN apt-get update && apt-get install -y \"<test tools> and <dependencies>"    \     # add testing tools and required packages&& rm -rf /var/lib/apt/lists/*# copy app files
COPY app app
COPY run.sh run.sh# copy test scripts
ONTEST COPY tests tests# copy "main" test command
ONTEST COPY test.sh test.sh# auto-generated volume for test results
# ONTEST VOLUME "/var/tests/results"# ... EXPOSE, RUN, ADD ... for app and test environment# main app command
CMD [run.sh, "<app arguments>"]# main test command
ONTEST CMD [/test.sh, "<test arguments>"]


如何实现“测试感知容器”

我们相信,Docker应该会将docker-test作为容器管理生命周期中的组成部分。当下我们都需要更为简便的解决方案,因此我在这里提出一套接近于理想情况的实现办法。

如之前所提到,Docker拥有ONBUILD这样一条非常实用的指令。该指令允许我们在已经成功的build之上触发另一build指令。其基本思路是在运行docker-test命令的同时,使用ONBUILD指令。

以下为docker-test命令的执行流程:

  1. docker-test将在应用程序Dockerfile当中搜索ONBUILD指令,而后……

  2. 利用初始Dockerfile生成一条临时的Dockerfile.test

  3. 执行docker build -f Dockerfile.test [OPTIONS] PATH,其中包含受docker build命令支持的其它选项:-test将自动被添加至tag选项当中。

  4. 如果构建成功,则执行 docker run -v ./tests/results:/var/tests/results [OPTIONS] IMAGE:TAG-test [COMMAND] [ARG...]

  5. 移除Dockerfile.test文件

那么,为什么不创建一个无需配合ONBUILD指令的Dockerfile.test文件?

这是因为,为了测试正确的镜像(及标签),我们需要保证FROM始终在测试目标的image:tag中得到更新。

不过前面提到的方案仍然存在局限——其不适用于“onbuild”镜像(即用于自动化构建应用的镜像),例如Maven:onbuild。

下面来看一条简单的docker-test命令实现流程。其中强调了一大重要概念:docker-test命令应当能够处理build与run命令选项,同时能够妥善处理错误状况。

#!/bin/bash
image="app"
tag="latest"echo "FROM ${image}:${tag}" > Dockerfile.test &&
docker build -t "${image}:${tag}-test" -f Dockerfile.test . &&
docker run -it --rm -v $(pwd)/tests/results:/var/tests/results "${image}:${tag}-test" &&
rm Dockerfile.test

让我们把注意力集中在最值得关注的重要部分。

集成测试型容器方案

假设我们的应用程序由数十甚至数百项微服务构建而成,同时假设我们已经拥有一套自动化CI/CD通道,其中每项微服务都由CI进行构建与测试,并在之后被部署到某种环境当中(例如测试、分段或者生产环境)。听起来不错,对吧?我们的CI会对各项微服务进行分别测试——运行单元与服务测试(或者API合同测试)。甚至有可能进行微集成测试——即将测试运行在特设的子系统之上(例如使用docker compose)。

但这又会带来一些新问题:

实际集成测试或者长期运行测试该如何完成(例如性能与压力测试)?
弹性测试该如何实现(例如‘混乱猴子’测试)?
如何实现安全扫描?
那些需要耗费较长时间且运行在完整操作系统之上的测试与扫描要如何完成?

应该有一种更好的办法来替代这种直接将新的微服务版本交付至生产环境的作法,我们也需要更为密切的监控手段。

应当存在一类特殊的集成测试容器。这些容器将仅包含测试工具与测试元素:测试脚本、测试数据、测试环境配置等等。为了简化此类容器的编排与自动化流程,我们应当定义并遵循某些约定并使用元数据标签(Dockerfile中的LABEL指令)。

集成测试标签

test.type – 测试类型,负责定义integration; 可属于 integration, performance, security, chaos 或者其它任意文本之一; 此标签代表其属于一套集成测试容器
test.results – 用于存放测试结果的VOLUME ; 默认位置为 /var/tests/results
test.XXX -任何其它相关元数据,仅使用test.后缀名作为标签名称

集成测试容器

集成测试容器其实就是一种常规Docker容器,其中不包含任何应用程序逻辑及代码。它的惟一用途就是创建可重复且可移植的测试流程。以下为建议纳入集成测试容器的内容:

测试工具 - Phantom.js, Selenium, Chakram, Gatling, …
测试工具运行时 - Node.js, JVM, Python, Ruby, …
测试管理配置 – 环境变量, 配置文件, 引导脚本, …
测试 -作为经过编译的软件包或者脚本文件存在
测试数据 – 任何用于测试的数据文件类型: json, csv, txt, xml, …
测试启动脚本 -用于运行测试的部分“main”启动脚本,仅负责创建test.sh并借此启动该测试工具。

集成测试容器应当运行在全部微服务都已经部署到位的运营环境之下,包括测试、分段或者生产环境。这些容器可与其它服务采取完全一致的部署方式。其利用同样的网络层,因此能够访问多项其它服务;使用选定的服务发现方法(通常为DNS)。在实际集成测试当中,我们必须对多项服务进行访问——旨在模拟并验证自身系统是否能够在多种不同环境下正常运行。将集成测试纳入应用服务容器不仅会增加容器自身体积,同时亦会在各服务之间带来不必要的依赖性。因此,我们将所有依赖性都限制在集成测试容器当中。一旦测试(以及相关测试工具)被打包在该容器内,我们亦可在包括开发者设备在内的任意环境下重复运行同样的测试流程。大家还能够实现回滚,即根据需要运行任意集成测试容器版本。

文章来源:TERRA NULLIUS

把好最后一道关,Docker容器测试全探索相关推荐

  1. docker容器测试技巧

    (1)Dockerfile设置常驻状态 在Dockerfile最后增加命令,让容器sleep,防止执行任务进程失败后退出容器 CMD sleep 6000 (2)安装辅助工具 先查看容器系统版本,这里 ...

  2. 【华为云技术分享】Docker容器+Phoronix-Test-Suite测试X86和ARM的ffmpeg转码性能

    [摘要] 如何使用phoronix-test-suite跑ffmpeg转码性能测试,主要测试X86和ARM的.中间使用Docker容器方便操作过程. Phoronix Test Suite是一款性能测 ...

  3. 渗透测试-Docker容器

    Docker 初步认识 Docker是时下热门的容器技术,相信作为一名开发人员,你一定听说过或者使用过,很多人会把Docker理解为一个轻量级虚拟机,但其实Docker与虚拟机(VM)是两种不同的计算 ...

  4. Go 语言测试在开发中的最佳实践 | 使用 Docker 容器进行测试

    前言 最近看到很多 Go 语言测试的教程都非常水,只讲了测试最基本的用法,几乎没有涉及到在开发中如何去设计一个很出色的测试.这篇博客将会带领大家一步一步完成一个出色的 Go-Test 思考 Go 语言 ...

  5. docker容器配置网络流量测试

    第一步 运行一个镜像: docker run -itd [REPOSITORY]:[TAG] /bin/bash 第二步 进入此镜像的容器 docker exec -ti [NAMES] /bin/b ...

  6. docker容器内安装ifconfig netstat ping vim 等测试工具的方法

    首先,确保docker容器能联网 ① centos使用yum进行安装 ② Ubuntu/debian等使用apt-get进行安装 安装ifconfig.netstat命令 apt-get instal ...

  7. 【云原生】第十一篇--基于Docker容器DevOps应用方案

    基于Docker容器DevOps应用方案 企业业务代码发布系统 一.企业业务代码发布方式 1.1 传统方式 1.2 容器化方式 二.企业业务代码发布逻辑图 三.企业业务代码发布工具及流程图 3.1 工 ...

  8. docker.11-基于Docker容器DevOps应用方案 企业业务代码发布系统

    基于Docker容器DevOps应用方案 企业业务代码发布系统 一.企业业务代码发布方式 1.1 传统方式 以物理机或虚拟机为颗粒度部署 部署环境比较复杂,需要有先进的自动化运维手段 出现问题后重新部 ...

  9. 初识docker《部署docker容器虚拟化平台》

    目录 1.Docker 概述 1.1 Docker 介绍 1.2 Docker 容器技术和虚拟机对比 1.3 Docker 架构 1.4 Docker 特性 1.5 Docker 版本简单介绍 2.部 ...

最新文章

  1. “Jupyter的杀手”:Netflix发布新开发工具Polynote
  2. centos7输入shell找不到命令_反弹shell原理与实现
  3. 记录一次因为懒惰而吃亏的事情
  4. IIS和APACHE共用80端口的方法
  5. 长期趋势的测定方法-时距扩大法和移动平均法
  6. 最全的ios系统导出微信聊天记录生成词云教程
  7. jmeter通过百度翻译平台接口实现翻译
  8. 如何使用计算机上合并计算方法,Excel2019中合并计算的使用方法
  9. 视频特征提取常用范式总结
  10. kal虚拟机统下安装open-vmware-tools
  11. AI 开发者被疯抢,华为做了什么?
  12. matlab 错误使用*
  13. 经纬度和高德地图计算两点距离面积
  14. 如何通过网络ActiveSync同步
  15. 最大化参数 火车头_火车头使用正则匹配模式采集数据
  16. git clone 出现fatal: unable to access ‘https://github.com/xxx: Failed to connect to github.com
  17. vue中怎么根据不同的(分屏模式)调整【自定义不同视频布局】?
  18. 启航——三十而立四十不惑的程序员
  19. 手动添加bean对象,交给spring管理
  20. 编写python程序输出数学表达式_Python基本编程题

热门文章

  1. 重新制作Docker镜像
  2. 能涨薪200%进大厂的那些测试人,到底掌握了哪些技能?
  3. excel线性拟合的斜率_邵励治的机器学习 2 / 100 天:「简单线性回归」
  4. PAT甲级1004 (DFS,树的父子节点)
  5. 计算机控制pud,控制系统状态空间实施方案计算机控制技术课程实施方案
  6. 阶乘末尾蓝桥杯java_Java实现第九届蓝桥杯阶乘位数
  7. 利用深度学习从单个损伤和斑点中识别植物病害
  8. 【java】JApplet类相关方法的使用
  9. php 压缩html css,PHP实现动态压缩js与css文件的方法
  10. mysql sum 慢_故障分析 | MySQL 优化案例 - select count(*)