10月21日,杭州云栖大会-技术&可持续发展论坛,注册有礼 了解详情
写点什么

开源容器引擎商业应用质量保障之道

2018 年 2 月 06 日

阿里巴巴集团在中国开源年会上正式开源了其酝酿已久的容器 pouch 项目,为开源容器引擎家族又添加一名新成员。当前很多云服务提供商在其服务中添加了开源容器引擎,但其测试方式往往只是通过 devops 进行简单的功能测试,甚至未经测试直接使用开源社区的二进制发行版本。这使得很多缺陷遗漏到下游用户手中。开源引擎在商用时如何保障质量呢?本文通过多个类型的测试来系统的阐述容器引擎质量保障方案。

功能测试

适合场景:

容器功能验证是最基本的质量保障方式,适合于所有使用容器引擎的场景。功能测试中需要建立特性树,覆盖容器引擎常用的命令,如 attach、build、commit、cp、create、diff、events、exec、export、history、images 等。同时还需要尽可能多的覆盖到每一个命令中的选项,如 create --hostname。从对外接口来分类,容器引擎的接口分为命令行接口和 rest api 接口。

通常做法:

直接使用开源社区中的自动化测试程序。但社区用例通常采用 container in container 的方式执行功能测试,这样做的好处是可以最大限度的保障测试环境的一致性。不足之处在于,因为采用了容器嵌套,被测试的容器引擎是 container in container 中的容器中的引擎,而不是主机中的容器引擎。这会导致容器引擎和宿主机适配的缺陷可能遗漏到下游。

优秀实践:

针对社区测试的不足,解决的方法是将整体的测试执行从容器中移植到宿主机中,将测试执行方式由 container in container 转变为 container in host。具体的做法是,首先将 container in container 中的测试镜像对应的 Dockerfile 中的环境配置工作移植到主机中,之后使用"go test -c -o ${test_binary}"命令将社区源码用例在容器中编译为二进制后在主机中直接运行。这样做的好处是,被测容器引擎是宿主机中的容器引擎,而不是 container in container 中容器嵌套中的引擎,保证了被测对象的准确性。

压力测试

适合场景:

压力测试适用于业务中可能遇到大量用户请求的场景。当主机遇到大量请求时,会导致主机资源负载的增加。基本的功能测试只能验证容器引擎的功能是否正常,却无法保证容器引擎的各种操作在宿主机高负载的情况下仍然能够成功执行。通过压力测试可以触发一些在软件设计中未考虑到的隐藏较深的缺陷。

通常做法:

业界的压力测试主要使用开源测试套 (如 stress、fio 等) 对被测对象持续加压。这种方式的问题是加压方式比较单一,无法模拟出真实业务的压力场景。某些业务(如用户争抢优惠资源)往往会在几秒钟内会有短时间的压力峰值,之后会趋于平缓。对于这种业务,通常的压力测试方法是无法覆盖到的。

优秀实践:

将宿主机的加压方式分为 3 中,即 CPU 加压、内存加压和 IO 加压。同时可以结合各种业务场景设计对应的加压模型。常见的加压模型有阶梯压力、周期性稳定压力、随机脉冲压力、长期稳定压力。对于短时间内的压力峰值的场景,可以使用随机脉冲加压方式进行模拟,从而保证了加压方式更贴近于真实的场景。

  • CPU 负载加压:使宿主机 CPU 资源占有率达到 30%~100%。
  • 内存负载加压:通过频繁 malloc/free 操作实现宿主机内存的频繁操作,使内存占用率达到 30%~80%。
  • IO 加压:使用 fio 工具可以实现对多种 IO 类型 (sync, mmap, libaio, posixaio, SG v3, splice, null, network, syslet, guasi 等) 进行加压。

长时间稳定性测试

适合场景:

长时间稳定性测试适用于需要长久运行容器并且业务不能中断的业务场景。功能测试无法验证系统能否稳定运行较长的时间,一些隐藏较深的缺陷会在系统运行一段时间后爆发,如文件句柄泄露、各状态间锁冲突等。需要对容器引擎进行长时间稳定性测试,执行时间通常在 7 天以上。

通常做法:

将业务部署到容器中,同时模拟用户请求,观察业务运行一段时间。不足之处在于,业务本身只能覆盖与本业务最相关的部分接口,无法有效覆盖所有接口,并且无法模拟出容器各种状态频繁切换的场景。因此无法触发一些容器状态切换时锁冲突等深层缺陷。

优秀实践:

列举容器所有状态,并遍历状态切换的所有路径。从一个状态切换到另一个状态有多种方式。例如从 running 状态切换到 exited 状态可以使用 stop 命令或 kill 命令,而每一个命令又对应着多种命令选项。容器状态迁移的方式如下图所示,在执行测试时首先批量启动若干容器,之后通过随机算法频繁的随机切换容器的状态来达到触发深层缺陷的目的。

安全测试

适合场景:

与私有云相比,公有云对安全性要求较高。需要针对该场景进行安全加固。该项安全测试主要是针对基于 runc 的容器引擎,runv 的加固方式不在其中。

通常做法:

执行开源社区已有的容器安全测试套来确认环境的安全性。不足之处在于社区中只包含了通用的安全检测点,无法针对自有的特定环境进行安全加固的验证。

优秀实践:

将容器安全测试分为安全合规测试和安全渗透测试。

1. 安全合规测试

安全合规专项测试排查涉及到账号管理、文件管理、密码和密钥管理、端口占用、日志管理等内容。因安全合规测试涉及内容较多,下面只列举出部分例子,其余部分在此不再敖述,感兴趣的读者可以阅读网络安全的书籍。

  • 账号管理:应用账号不能写死在代码中;需要单独接口进行账号权限认证。
  • 文件管理:禁止存在无主文件;文件权限需要最小化处理,配置文件权限不高于 644,执行文件权限不高于 744。
  • 密码和密钥管理:密钥不可硬编码到代码中;禁止使用不安全的加密算法 (DES、RSA、MD2 等);登录 hub 时需要对密码进行加密 (aes 加密)。
  • 端口占用:通过 nmap 程序获取容器引擎所占用的端口,确认是否有多余的端口。
  • 日志管理:需要提供日志防爆功能,防止恶意用户进行不断操作产生大量日志导致磁盘占满;daemon 日志中不能包含 debug 信息;日志中不能存在明文敏感数据。

安全扫描测试:通过 govet ineffassign go ast scanner golint 等工具可以对源码进行扫描。

除了以上源码扫描工具,还有一些其他开源或商业扫描工具可以使用。如
Nessus(扫描安全漏洞)、Retina(扫描安全漏洞) 、Bitdefender(病毒扫描) 、Avira AntiVir Server(病毒扫描)、Kaspersky Endpoint Security(病毒扫描)、McAfee VirusScan Enterprise(病毒扫描)、Symantec Endpoint Protection(病毒扫描)、TrendMicro OfficeScan(病毒扫描)、Nmap(端口检查)。

模糊测试 (Fuzz testing):针对容器引擎的特点进行 fuzz 建模,通过 peach 和 Codenomicon 工具可以实现容器引擎接口和 api 测试,通过测试工具将生成的随机数据发送给引擎进行系统验证。

2. 安全渗透测试

该项工作需要阅读源代码找到潜在的安全漏洞,同时需要及时同步社区中已经发现的 cve 漏洞,并进行版本升级。cvedetails 网站收集了各开源社区的 cve 信息,在对 cve 进行排查时,不仅需要排查容器引擎的社区,还需要排查和其有交互的开源组件、编程语言库、编译器等,如 golang 语言

性能测试

适合场景:

性能测试适用于对性能要求较高、需要进行性能调优的容器引擎使用场景。

通常做法:

分别在宿主机和容器中执行常用的性能测试套(如 lmbench),将测试结果进行对比。不足之处在于其无法覆盖到容器特有的性能参数,如启动时间、占用内存值等。

优秀实践:

通过对不同容器引擎以及容器与物理机虚拟机进行各关键指标的对比,可以找到项目的性能优化点。
容器引擎涉及到的性能指标主要有:

  • 容器启动时间

测试方法:

复制代码
<pre data-anchor-id="q9tp">

$ time ${container_engine} run ${image} echo 0

复制代码
  • 容器占用内存值

测试方法:

复制代码
<pre data-anchor-id="5bvc">

$ smem ${container_pid}

复制代码

smem 工具会获取三个主要的内存指标,在此选取 PSS 值,这是为了便于测试多个容器使用的内存总量。

  • 主机最大容器承载量

测试方法:不断创建新的空载容器,同时使用如下命令获取当前容器数量,直至主机资源耗尽。

复制代码
<pre data-anchor-id="tqyr">

$ ${container_engine} info

复制代码
  • 容器 CPU 性能

测试方法:测试计算素数直到某个最大值所需要的时间。

复制代码
<pre data-anchor-id="65g7">

$ sysbench --test=cpu --cpu-max-prime=${max_prime_value} run

复制代码
  • 容器内存性能

测试方法:每次读写 8KB,直到 10GB 读取完成。

复制代码
<pre data-anchor-id="ylor">

$ sysbench --test=memory --memory-block-size=8K --memory-total-size=10G run

复制代码
  • 容器磁盘 IO 性能

测试方法:使用 sysbench --test=fileio 或 dd 命令进行验证。

  • 容器网络性能

测试方法:利用 netperf 测试套验证。

开源测试

适合场景:

适用于基于开源容器引擎二次开发的容器使用场景。

通常做法:

继承开源社区的测试用例,同时针对自研特性设计测试用例。不足之处在于无法有效利用社区资源进行容器引擎的质量保障。

优秀实践:

可以借助开源社区进一步完善质量保障,具体体现为:

  • 上报缺陷

当软件在自己开发环境中发现缺陷时,可以查看社区中是否有其他人报过相同的缺陷。如果没有,可以在 github 中提交一个 issue 来跟踪,引导社区来解决缺陷,从而减少自身团队的投入。

  • 提交测试用例

对于和自身平台有强相关性的用例可以贡献给社区,可以使社区在发布版本时预先验证某项功能,从而达到测试前移并减少自身项目工作量的目的。

  • 排除社区已知缺陷

社区代码缺陷通常存放在 issue 中,很多高版本发现的缺陷在低版本中同样存在,需要进行人工排查,将 issue 中高版本的缺陷对应的 patch 合入到低版本的商用容器引擎中。

内核测试

适合场景:

容器引擎的运维系统往往包含着不同内核版本的宿主机,需要针对不同内核版本验证容器依赖的内核特性。

通常做法:

验证某个单一的内核版本中容器依赖的内核特性后,通过灰色发布的方式进行快速试错。不足之处在于快速试错采用的是线上的环境,如遇到问题可能会导致大面积服务中断。

优秀实践:

容器引擎通常需要运行在 3.10 或以上版本的内核中,这类内核中包含着 cgroup、namespace、capability、seccomp、union fs 等容器依赖的内核特性,需要对这些底层的内核特性进行充分的验证才能保证容器引擎的质量。

Ltp 是一款内核开源测试套。里面包含很多内核特性的测试用例,如 cgroup 测试用例 namespace 测试用例。需要在验证容器引擎的同时,运行 ltp 中容器相关的内核特性测试用例。

故障注入测试

适合场景:

该项测试适用于对容错能力要求较高的场景。故障注入测试可以验证容器引擎的容错能力,从而减少故障对业务的影响。

通常做法:

执行一段时间的长稳测试,将所有已遇到的故障记录下来,录入故障模式库。这种方法较为被动,需要在故障出现时才能梳理出来,无法在故障发生前消除故障带来的影响。

优秀实践:

根据每一个容器引擎命令梳理出程序的控制流,在控制流中的每一个节点中增加典型的故障注入方式,确保不遗漏可能的故障点,从而保证容器引擎的容错能力。常用的故障类型包括但不限于 CPU、内存、磁盘、网络等。

下面列举了部分故障供读者参考:

  • CPU 故障:将容器绑定到某 CPU 核后强制将该 CPU 核下线;主机 CPU 高负载时尝试启动容器;容器内部运行高负载程序时主机不会卡死。
  • 内存故障:试图在容器中耗尽主机内存;使用—restart=always 选项启动容器后在容器内部不断执行 out of memory 的操作;操作系统可用内存低时仍然可以启动容器。
  • 磁盘故障:磁盘占满时尝试启动 docker 容器;容器运行中时 umount graph 所在的磁盘分区。
  • 网络故障:容器网桥意外下线;ip 资源耗尽;加大网络延迟,提高网络丢包率;分配给容器一个已被占用的 ip 地址。
  • 其他故障:宿主机异常断电;随机杀掉系统进程;cgroup 文件夹被 umount;系统进程数量达到最大值时启动容器。

结尾

本文展示了多种容器引擎的专项测试方法,但测试只是验证其质量的方式。好的软件是设计出来的,而不是测试出来的。在加强容器测试的同时也需要企业去关注开发流程的质量和规范性。只有开发和测试共同努力才能有效的把控容器软件的质量。

作者简介

孙远,阿里巴巴测试开发专家,目前在阿里巴巴从事阿里容器 pouch 技术的质量保障工作。工作涉及到功能测试、性能测试、压力测试、稳定性测试、安全测试、测试管理、工程能力构建等内容。参与编写了《Docker 进阶与实战》,曾多次受邀在中国软件测试大会、中国开源年会、中国质量大会发表演讲。先前曾先后就职于美国风河系统公司和华为技术有限公司。

刘璐,阿里巴巴资深测试开发工程师,目前在阿里巴巴从事阿里容器 pouch 技术的质量保障工作。曾任职甲骨文高级测试开发工程师 (Solaris 方向),有多年的系统软件测试经验。

2018 年 2 月 06 日 19:271309

评论

发布
暂无评论
发现更多内容

为什么感觉假期还没开始就快要结束了?

脑极体

【LeetCode】 第三大的数Java题解

HQ数字卡

算法 LeetCode 10月日更

阿里巴巴《Java权威面试指南(全彩版)》来袭,冲击“金九银十”有望了

云流

Java 程序员 架构 面试 后端

“区块链+政务”纵深发展 链上共识提升服务效能

CECBC区块链专委会

【Flutter 专题】37 图解 Flutter 基本动画 (二)

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 10月日更

《Go 开发指南》-快速安装 Go 环境

看山

Effective-go 10月日更

全到哭!Github一夜爆火被各大厂要求直接下架的Java面试题库真香

程序员小毕

Java spring 程序员 架构 面试

项目管理中常见的十个问题

石云升

项目管理 管理 引航计划 内容合集 10月日更

架构实战营模块9作业

喻高咏        

架构实战营

这篇阿里扫地僧所写关于SpringCloudAlibaba的笔记真香!

Java 白

Java 面试 程序人生 编程语言 架构、

惊艳!阿里出产的MyCat性能笔记,带你领略什么叫细节爆炸

Java 白

Java 架构 面试 程序人生 编程语言

Jupyter Notebook从入门到精通,TensorFlow一个计算机视觉示例 易筋 ARTS 打卡 Week 68

John(易筋)

ARTS 打卡计划

Python代码阅读(第32篇):随机返回列表中的一个元素

Felix

Python 编程 Code Programing 阅读代码

点击量破百万!阿里内产微服务进阶讲义,简直是Java开发者的福音

Java 白

Java 编程 架构 面试 程序人生

美团大佬的Java性能调优实战手册,上线当天 下载量破百万!

Java 白

Java 编程 架构 程序人生

不愧是阿里巴巴内部Spring Boot实战文档,这细节讲解,神了

胧月

Java spring 架构 面试 微服务

私有云部署系列之动态IP获取(前期准备)

稻草鸟人

Python 私有云

起飞!这份技术点拉满的ELk+Lucene笔记,可能价值百万

Java 白

Java 架构 面试 程序人生 编程语言

008云原生之Serverless架构

穿过生命散发芬芳

云原生 10月日更

0 基础架构入门 - 5(微博评论的高性能高可用计算架构)

felix

架构实战营 0 基础架构入门

Web安全应急响应小记

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 应急响应

不吹不黑!阿里内部强推微服务容器化参考指南真香

程序员小毕

Java 架构 容器 面试 微服务

NodeJs 全栈创建多文件断点续传

devpoint

前端 upload 引航计划 大前端领域 10月日更

阿里内部“SpringCloudAlibaba学习笔记”全彩第三版开源

云流

Java spring 架构 面试 微服务

架构实战营模块 8 作业指导

华仔

架构实战营

【Spring源码分析】带你正视一下Spring祖容器之BeanFactory的原理与功能分析(1)

李浩宇/Alex

spring 容器 spring源码 10月日更 BeanFactory

新技术|基于信号特征的语音编码器Lyra Android实践

轻口味

android 音视频 引航计划 10月日更

促进DeFi、CeFi融合的Pledge,或成为首个与上市企业合作的DeFi协议

股市老人币圈新

6. python 查漏补缺,namedtuple 命名元组,双向队列 deque,Counter 计数器,可排序字典

梦想橡皮擦

10月日更

Netflix实用API设计(上)

俞凡

架构 netflix API 10月日更

Netflix实用API设计(下)

俞凡

架构 netflix API 10月日更

数据cool谈(第1期)数据库寻路,开源有态度

数据cool谈(第1期)数据库寻路,开源有态度

开源容器引擎商业应用质量保障之道-InfoQ