测试环境docker化—基于ndp部署模式的docker基础镜像制作

叁叁肆2018-09-21 10:57

本文来自网易云社区

作者:孙婷婷


背景
我所在测试项目组目前的测试环境只有一套,在项目版本迭代过程中,开发或产品偶尔会在测试环境进行数据校验,QA人数在不断增加,各个人员在负责不同模块工作时也会产生脏数据,导致QA在功能测试和接口测试过程中需要清理测试环境增加工作量,同时QA组在进行异常测试等多维度质量保障时也希望有多套环境进行数据隔离。但目前测试环境多套隔离操作麻烦,每隔离一套环境需要修改大量配置、数据库重新建表到调试可用,在开发的帮助下至少需要3天的时间,在这种场景下,我们借鉴组内大数据QA的思路和探索路线,考虑尝试引入docker技术来解决测试环境问题。
在实践测试环境docker化的过程中,考虑到项目的部署流程都已经迁移至运维的ndp平台,由于项目属于多模块项目,同时为尽量保证docker化后的测试环境能与现有生产环境的配置和结构保持一致,我们设计借鉴ndp的发布配置和模式进行docker化后的测试环境部署。

ndp部署流程
经过学习、对比和摸索,了解到ndp的部署流程基本如下图所示(基本都是自己摸索,未专门请求运维同事,如果运维部的同事发现有错误,欢迎指正(*^▽^*))
  1. 用户在ndp管理平台配置代码地址、构建文件build.xml、部署定制配置(主要配置端口号、内存分配、应用名、应用入口等)
  2. 当点击项目构建时,ndp服务器会拉取代码,然后按照编写的构建文件build.xml对项目模块进行ant构建,模块构建完成后进行模块打包
  3. 当点击项目部署时,将打包模块分发至部署服务器,进行项目部署
基于以上背景,考虑设计docker化的环境发布接口为1个compile容器+多个deploy模块容器接口,首先启动一个compile容器完成所有模块的编译,并启动一个httpServer发布端口号,然后逐个启动deploy容器,拉取打包模块完成整个项目部署。因此,首先需要设计compile和deploy两类基础镜像。

基础编译镜像compile
  1. 我们的镜像使用Dockerfile制作,首先安装项目编译需要的软件,包括jdk(注意是jdk不是jre)、ant、maven,其中,maven需要配置公司的依赖仓库,因此可以通过COPY将公司的settings.xml放入镜像中相应位置;
  2. 容器通过git下载代码时需要ssh权限,可以通过找一台服务器生成一个ssh-key,公钥放入git上相关项目的deploy-key中获取下载权限,私钥通过COPY放入镜像root下的.ssh文件中;
  3. 机器首次git clone代码时git会提示“Are you sure you want to continue connecting (yes/no)?,由于需要容器运行后自动下载代码编译,中间不需要任何人工操作,则需要去除这条提示,通过网上搜索,解决办法是可以修改/etc/ssh_config文件中的配置来跳过此处询问,如下所示去掉文件中“StrictHostKeyChecking”前的“#”。可以事先修改好配置,通过COPY替换镜像中相应文件即可。
#   CheckHostIP yes
#   AddressFamily any
#   ConnectTimeout 0
    StrictHostKeyChecking no
#   IdentityFile ~/.ssh/identity
将以上操作通过Dockerfile命令方式写入后运行docker build就可以生成我们定制的compile镜像, 创建容器时通过挂载的方式将项目各模块的build.xml加载到容器中,指定容器运行代码为一个entry.sh文件,该entry.sh主要实现代码拉取、各模块ant构建和最后启动一个httpServer的功能,启动httpServer后compile容器即发布成功!

基础部署镜像javaappp和tomcat
由于项目中模块基本都是javaapp和javaweb项目,我们就考虑制作了两个镜像,一个为javaapp镜像,专门用于部署javaapp模块,对应于ndp上的应用类型为java app;一个为tomcat镜像,专门用于部署java web模块,对应于ndp上的应用类型为java web。

a. javaapp镜像
  1. javaapp镜像主要用于运行javaapp应用,只需要有jre环境即可,因此首先安装jre;
  2. 将现有测试环境服务器部署模块中生成的config文件放入自定义路径下,该文件用于定制化jvm参数、内存分配、应用名、端口号等,对应ndp上模块-配置-发布配置页面内容,如下图
            3. 将现有测试环境服务器部署模块中的appCtrl.sh通过COPY放置在自定义路径下,该文件为调用config参数后启动java的项目启动文件,需要启动项目时只需运行./appCtrl.sh start即可,具体其他功能可学习该文件。
创建容器时通过挂载的方式将entry.sh文件加载到容器中,该entry.sh主要实现从compile容器拉取部署模块、修改config配置(增加特定入口main方法)和启动appCtrl.sh的功能,启动模块后该模块容器即发布成功!
b. tomcat镜像
  1. 由于web项目需要使用tomcat,镜像首先安装jre和tomcat
  2. 将现有测试环境服务器部署模块中的default_tomcat文件放入自定义路径下,该文件用于定制化内存分配、应用名、端口号等,对应ndp上模块-配置-发布配置页面内容
  3. 修改tomcat中server.xml,主要是将docBase的路径指定为后续打包模块的存放路径,比如我是指定为"/usr/local/compressed"(由于一个容器中只会运行一个模块,所以此处可固定填写)
  4. 将现有测试环境服务器部署模块中的用于tomcat服务启动的tomcat脚本文件放入自定义路径下,该文件类似于javaapp镜像中的appCtrl.sh文件((需删除java、修改start-stop-daemon路径))。同时由于该文件调用了init-functions和rotatelogs,需修改init-functions的调用路径为系统文件路径,并在自定义路径下加入rotatelogs用于日志切割
创建容器时通过挂载的方式将entry.sh文件加载到容器中,该entry.sh主要实现从compile容器拉取部署模块、修改配置和启动tomcat的功能,启动模块后该模块容器即发布成功!

总结  
此部署结构和镜像一方面对标了ndp的环境部署方式;另一方面,部分jar包会被其他其他模块依赖,但基于安全原因未上传至仓库,而是先打包后给其他模块使用,此时集中在一个容器中打包则不需要在各个模块编译的时候重复打包依赖jar包;同时保证各个模块属于同一个版本的代码,保证每套环境部署时各个模块的版本一致性。
从目前实践结果来看,本组项目已基本完成各个模块的容器发布,只要一套环境发布的各个配置文件、build.xml、entry.sh整理好,即可实现三行命令发布一套环境的需求,大大缩减了测试环境部署时间。故在这里写出来给有需要的小伙伴参考,也希望有类似经历的同事可以多提建议,多多指教。

有实践就会有坑,此处简单罗列镜像制作过程中的各种奇怪的坑,以避免伙伴们重复踩坑!
1. 在tomcat镜像制作过程中,使用的基础镜像是docker-library中的tomcat的Dockerfile,但是该镜像在执行过程中会再安装一遍jdk,在安装后删除导致build到一半时找不到jdk,解决方法:删除重新安装的代码。
2. ndp上build.xml中的执行工具mvn的名称默认为服务器中的mvn名称“mvnJDK7”,需要修改为我们安装在镜像中的mvn名称,一般为“mvn”。
3. 注意修改各COPY到镜像中的可执行文件的执行权限,如rotatelogs/config/default-tomcat等
4. 在compile+deploy结构中,我最终在compile容器中起了一个httpServer,各deploy通过wget获取编译后的文件夹,但是若文件夹中有index.html,wget会默认读取index.html及index.html中的链接文件,这样就违背了我希望获取所有文件的预期,最后解决办法是先将文件夹压缩,通过wget获取后再解压
5. 容器入口使用entry.sh运行,最后运行完./tomcat start或./appCtrl start后会退出容器,原因是docker容器中的前台线程结束即会退出。解决办法,可以在脚本最后添加命令“tail -f /dev/null”使线程始终挂起。

网易云容器服务为用户提供了无服务器容器,让企业能够快速部署业务,轻松运维服务。容器服务支持弹性伸缩、垂直扩容、灰度升级、服务发现、服务编排、错误恢复及性能监测等功能, 点击可免费试用

网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区