导读 当我们构建好Docker镜像并利用多套容器共同组合成应用程序,建立起持续交付通道,了解了如何将新创建的镜像纳入到生产或者测试环境当中之后,新的问题来了——我们该如何测试自己的Docker容器?测试的策略多种多样,反映了各种各样的测试性格:天真型,懒人省事型,超前理想主义型,完美主义处女座型……那么你是哪一型?下面我们就对其各自的方案利弊进行逐一分析。
“天真”型方案

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

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

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

应用&测试容器方案

现在我们尝试创建单一捆绑包,其中应用程序“二进制代码”中包含全部必需的软件包、测试工具(包括对应版本)、测试工具插件、测试脚本以及其它各类测试环境元素。但这种方式也存在着显著弊端:
镜像体积直线增长——这是因为其中包含有测试工具、必要软件包、测试脚本甚至是测试数据。
特定测试配置可能对镜像运行时环境造成污染,甚至引入不必要的依赖性(集成测试中需要用到)。
我们还需要考虑如何处理测试结果与记录日志;

如何将其导出以及向哪里导出,通过以下经过简化的 Dockerfile,我们可以了解上述方案的整个流程。

FROM "":""

WORKDIR ""

# install packages required to run app and tests
RUN apt-get update && apt-get install -y /
" and " / # add app runtime and required packages
" and " / # 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, ""] # it's not possible to have multiple CMD commands, but this is the "main" test command
# CMD [/test.sh, ""]


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

测试感知型容器方案

目前,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命令非常相似,docker test会自动生成一套新的“可测试”镜像,执行全部build操作,于ONTEST命令后进行定义并执行ONTEST CMD(或者ONTEST ENTRYPOINT)。其中若测试发生错误,docker test命令应当返回一段非零代码。此测试结果应当被写入至自动生成且指向/var/tests/results文件夹的VOLUME。

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

FROM "":""

WORKDIR ""

# install packages required to run app
RUN apt-get update && apt-get install -y /
" and " / # 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 /
" and " / # 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, ""] # main test command
ONTEST CMD [/test.sh, ""]

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

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

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

docker-test将在应用程序Dockerfile当中搜索ONBUILD指令后,利用初始Dockerfile生成临时的Dockerfile.test,再执行docker build -f Dockerfile.test [OPTIONS] PATH,其中包含受docker build命令支持的其它选项:-test将自动被添加至tag选项当中。
如果构建成功,则执行 docker run -v ./tests/results:/var/tests/results [OPTIONS] IMAGE:TAG-test [COMMAND] [ARG...] 移除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合同测试)。甚至有可能进行微集成测试——即将测试运行在特设的子系统之上但这又会带来一些新问题:

实际集成测试或者长期运行测试该如何完成(例如性能与压力测试)?

弹性测试该如何实现(例如‘混乱猴子’测试)?

如何实现安全扫描?

那些需要耗费较长时间且运行在完整操作系统之上的测试与扫描要如何完成?

应当存在一类特殊的集成测试容器。这些容器将仅包含测试工具与测试元素:测试脚本、测试数据、测试环境配置等等。为了简化此类容器的编排与自动化流程,我们应当定义并遵循某些约定并使用元数据标签(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并借此启动该测试工具。

集成测试容器应当运行在全部微服务都已经部署到位的运营环境之下,这些容器可与其它服务采取一致的部署方式。在实际集成测试当中,我们必须对多项服务进行访问来测试多种不同环境下是否能正常运行。将集成测试纳入应用服务容器不仅会增加容器自身体积,同时亦会在各服务之间带来不必要的依赖性。因此,我们将所有依赖性都限制在集成测试容器当中。

Docker 容器测试全探索的更多相关文章

  1. 浩若烟海事半功倍|利用Docker容器技术构建自动化分布式web测试集群Selenium Grid

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_195 "世界上有那么多城市,城市里有那么多的酒馆,可她,却偏偏走进了我的-",这是电影<卡萨布拉卡> ...

  2. 史上最全面的Docker容器引擎使用教程

    目录 1.Docker安装 1.1 检查 1.2 安装 1.3 镜像加速 1.4 卸载Docker 2.实战Nginx 3.Docker命令小结 4.DockerFile创建镜像 4.1 Docker ...

  3. Docker容器CPU限制选项测试

    目录 Docker容器CPU限制选项测试 参考 实验环境 --cpu-shares选项 测试 结论 --cpus选项 测试 结论 --cpuset-cpus选项 测试 结论 Docker容器CPU限制 ...

  4. 关于Docker在测试方面的应用

    Docker 火了很长一段时间了,前段时间简单的学习和试玩了一下子,发现他对测试很有价值,觉得有必要再次深入研究. 这里标记一些较好的学习网址,用作参考: InfoQ上面有系列的文章: 深入浅出Doc ...

  5. 【原创】Docker容器及Spring Boot微服务应用

    Docker容器及Spring Boot微服务应用 1 什么是Docker 1.1 Docker的出现 问题一:项目实施环境复杂问题 传统项目实施过程中经常会出现“程序在我这跑得好好的,在你那怎么就不 ...

  6. 运行 Docker 容器时的安全风险:别丢了你的套接字

    我们都遇到过这种情况:你只是想尝试一段命令行,但安装进程却如同抵押贷款申请那般繁琐.如果不是强制要求完成这么多步骤,你的开发环境会被永远不会再使用的库弄乱.自然, Docker 来了以后,你惊异地发现 ...

  7. 利用谷歌开源工具cAdvisor 结合influxdb存储+Grafana前端展示进行Docker容器的监控

    一.Docker 监控方式 1.利用docker 的 docker stats API 命令: docker stats [容器ID/容器名称] [root@docker ~]# docker sta ...

  8. 如何快速部署 Prometheus?- 每天5分钟玩转 Docker 容器技术(85)

    上一节介绍了 Prometheus 的核心,多维数据模型.本节演示如何快速搭建 Prometheus 监控系统. 环境说明 我们将通过 Prometheus 监控两台 Docker Host:192. ...

  9. 如何用 Graylog 管理日志?- 每天5分钟玩转 Docker 容器技术(93)

    上一节已经部署好了 Graylog,现在学习如何用它来管理日志. 首先启动测试容器. docker run -d \ --log-driver=gelf \ --log-opt gelf-addres ...

随机推荐

  1. oneM2M标准发展神速 实现万物联网的愿景

    http://m2m.iot-online.com/news/2013102224849.html oneM2M则将负责解决独立于接取网路中通用的M2M服务层的关键需求:使其可更方便地嵌入于各种软硬体 ...

  2. IBatis一对多嵌套查询

    1)类 public class AppData { // public int ModuleId { get; set; } public int DataId { get; set; } publ ...

  3. paramiko模块使用

    paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,fabric和ansible内部远程管理就是使用paramiko来实现. #!/usr/bin/env pyt ...

  4. Python QQ群

    微信公众号:Python中文社区 Python初级技术交流QQ群:152745094Python高级技术交流QQ群:273186166Python网络爬虫组QQ群:206241755PythonWeb ...

  5. Set接口

    Set接口也是Collection接口的子接口,Set接口中不能加入重复的元素 Set接口的常用子类 1.散列的存放:HashSet HashSet是Set接口的一个子类,主要的特点是:里面不能存放重 ...

  6. Iframe 在项目中的使用总结

    参考:http://www.cnblogs.com/MaxIE/archive/2008/08/13/1266597.html 问题一:首先我们用iframe加载页面,第一个需要解决的问题是高度自适应 ...

  7. 设计模式学习——策略模式(Strategy Pattern)

    0. 前言 最近在重构公司的一个项目的时候,在抽取DES加密重复部分代码的时候,突然间想起了策略模式,感觉策略模式好像可以应用上,于是重新学习了下策略模式.注:在DES加密中,有DES和TDES算法, ...

  8. JAVA JLabel自定义子类无法显示

    import java.awt.*; import java.util.Scanner; import javax.swing.*; public class Test_16_13 extends J ...

  9. ASP.NET 生命周期

    学习资料:http://www.cnblogs.com/OceanEyes/archive/2012/08/13/2635657.html

  10. acpi和btrfs-安装opensuse时的选项

    g-------------------- 关于GPL和LGPL和QPL等 读书笔记:采用LGPL的代码,一般情况下它本身就是一个第三方库(别忘了LGPL最早的名字就是Library GPL),这时候 ...