我们通常所说的测试环境包括网络、服务器等基础硬件环境和运行之上的软件环境(应用软件、数据库等)。笔者所在部门,硬件、网络环境是由运维部门提供维护。这样省去了很多维护工作,也便于管理。目前京东已经从虚拟机过渡到Docker容器。
当测试环境的应用很多时,我们要做的不仅仅是安装这些基础软件、随意部署,而是应该按照一定的规则和目录结构管理。一台服务器上可能会部署多个应用时,可以按应用拆分Nginx、Tomcat 配置文件。
笔者在安装应用时,每加入一个应用会定义一个Nginx 配置文件,用include 关键字将应用配置导入Nginx 配置。代码示例4.4.1 为Nginx 示例文件。
代码示例4.4.1
#Nginx 要开启的进程数 worker_processes 8; error_log /export/servers/nginx/logs/nginx_error.log warn; #存放Nginx 进程id pid /export/servers/nginx/run/nginx.pid; #worker 进程的最大打开文件数,如果不设置,默认为操作系统设置的文件数 worker_rlimit_nofile 65535; #处理连接的设置 events { #用于复用客户端线程的轮询方法,Linux 2.6+使用epoll,FreeBSD 4.1+使用kqueue use epoll; #一个worker 进程同时打开的最大连接数 worker_connections 65535; } http { #为节约篇幅,中间部分配置省略 error_page 400 401 402 403 404 405 408 410 412 413 414 415 500 501 502 503 506 = http://www.jd.com/error2.aspx; include domains/*; } |
在domain 目录下建立应用配置文件,如代码示例4.4.2 所示。
代码示例4.4.2
#用于配置负载均衡,这里只配置异常处理策略。 upstream tomcat_demo.jd.net { server 127.0.0.1:1602 weight=10 max_fails=2 fail_timeout=30s; } #配置 server{ listen 80; server_name demo.jd.net ; access_log /export/servers/nginx/logs/demo.jd.net/demo.jd.net_access.log main; error_log /export/servers/nginx/logs/demo.jd.net/demo.jd.net_error.log warn; error_page 411 = @my_error; location @my_error {} root /export/App/ demo.jd.net/; location / { proxy_next_upstream http_500 http_502 http_503 http_504 error timeout invalid_header; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://tomcat_ demo.jd.net; expires 0;} location /logs/ {autoindex off; } } |
这样的结构方便管理,当应用安装后只需运行nginx –s reload 即可在不影响其他应用访问的情况下加载新的应用。
Tomcat 只需要安装一套。如代码示例4.4.3 所示为配置文件Server.xml 示例。
代码示例4.4.3
<?xml version='1.0' encoding='utf-8'?> <Server port="1802" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <Listener className="org.apache.catalina.core.JasperListener" /> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" /> <Listener className="org.apache.catalina.mbeans. GlobalResourcesLifecycleListener" /> <GlobalNamingResources> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <Service name="Catalina"> <!--Connector port-对外服务端口、maxParameterCount-最大的参数数量、 connectionTimeout-连接超时时间(单位毫秒)、URIEncoding-字符集编码--> <Connector port="1602" maxParameterCount="1000" protocol="HTTP/1.1" redirectPort="8443" maxSpareThreads="750" maxThreads="1000" minSpareTHreads="50" acceptCount="1000" connectionTimeout="20000" URIEncoding="utf-8"/> <Engine name="Catalina" defaultHost="localhost" jvmRoute="s1"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> <!--配置tomcat 虚拟主机,appBase-应用所在目录,unpackWARs-是否解压war 包,autoDeploy- 如果有新应用时自动载入应用--> <Host name="localhost" appBase="webapps" unpackWARs="false" autoDeploy="false" xmlValidation="false" xmlNamespaceAware="false"> </Host> </Engine> </Service> </Server> |
对应的应用配置文件conf/Catalina/localhost/ROOT.xml 示例,如代码4.4.4 所示。
代码示例4.4.4
<?xml version="1.0" encoding="UTF-8"?> <Context path="/" docBase="/export/App/demo.jd.net" > </Context> |
软件只需要解压到/export/App 对应应用目录中。
我们在启动脚本中使用相同的tomcat 软件,如代码示例4.4.5 所示为start.sh 启动脚本示例。
代码示例4.4.5
#!/bin/bash export CATALINA_HOME=/export/servers/tomcat6.0.33 export CATALINA_BASE=/export/Domains/demo.jd.net/server1 export CATALINA_PID=$CATALINA_BASE/work/catalina.pid export LANG=zh_CN.UTF-8 ###JAVA export JAVA_HOME=/export/servers/jdk1.6.0_25 export JAVA_BIN=/export/servers/jdk1.6.0_25/bin export PATH=$JAVA_BIN:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin: /usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/bin export CLASSPATH=.:/lib/dt.jar:/lib/tools.jar export JAVA_OPTS="-Djava.library.path=/usr/local/lib -server -Xms256m -Xmx768m -XX:MaxPermSize=768m -Djava.awt.headless=true -Dsun.net.client.defaultConnectTimeout=60000 -Dsun.net .client.defaultReadTimeout=60000 -Djmagick.systemclassloader=no -Dnetworkaddress.cache.ttl=300 -Dsun.net.inetaddr.ttl=300 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALIN A_BASE/logs -XX:ErrorFile=$CATALINA_BASE/logs/java_error_%p.log" export JAVA_HOME JAVA_BIN PATH CLASSPATH JAVA_OPTS $CATALINA_HOME/bin/startup.sh -config $CATALINA_BASE/conf/server.xml |
4.5 测试环境自动化运维
线上生产环境有专业的运维管理,一般不允许直接登录服务器操作,版本发布有严格的流程规范。测试环境属于研发测试活动中的基础设施,出于成本考虑,服务器较少,一台服务器上可能会部署多个应用,使用方式多样化、发布频繁,因此不易于管理。测试环境的准备以及使用中遇到问题的解决占用了测试活动的很多时间,影响测试效率。一般最基础的方式是使用手工部署:手工打包、上传、管理服务,串行操作很费时间。这些操作完全可以用自动化的方式解决。
4.5.1 测试环境管理平台
在手工维护和使用一些自动化工具(如Jenkins)管理服务器和测试环境时,会发现一些问题。如果服务器、应用很多,会不方便统一管理。一般每个业务线、每个应用应该有专属的测试服务器。如果应用任意部署,则会因为应用间相互依赖,导致跨多个应用的业务流不能串联,延误测试进度。在开发工程师提测后,需要知道提测代码对应的分支、版本。部署后需要知道服务器上部署的应用信息,以方便核对测试代码是否和提测版本一致。测试工程师需要知道:(1)有哪些测试服务器可以使用;(2)服务器的当前状态;(3)服务器资源不足时是否能提前通知;(4)测试服务器上部署了哪些应用,应用的运行状态。
我们结合现有技术,设计了一套完整的测试环境管理平台解决方案。测试环境管理平台主要包括测试服务器的分配,服务器内存、硬盘空间等资源监控及预警、应用的编译打包、一键部署,定时自动部署、部署验证及回滚功能。系统整体架构如图4.5.1 所示。
它主要包括系统管理模块、远程控制模块、应用编译打包模块、应用包管理模块、定时任务管理模块。处理流程包括手工一键部署流程(图4.5.2)和定时自动部署流程(图4.5.3)。
手工一键部署流程:用户设置部署应用的分支、版本号、构建参数触发构建,系统根据软件包特征查询之前有没有构建过,如果构建过,系统则通过远程控制模块通知服务下载软件包,直接部署,跳过编译构建流程。如果没有构建过,系统则通知编译中心打包构建,构建后将软件包上传到云存储中,然后通知服务器下载软件包并部署。
用户在定时任务管理模块配置定时部署任务(站点、服务器、构建参数、触发时间)。任务到达触发时间后自动触发,通知软件包构建模块执行构建任务。软件包构建模块返回构建任务编号,部署控制模块通过构建任务编号查询构建状态。软件包构建模块构建完成后将软件包提交给软件包管理模块。然后部署控制模块进行部署操作。部署完成后,部署控制模块通知测试模块进行BVT(Build Velification Test,冒烟测试)测试。如果测试通过,则部署任务完成;如果测试失败则通知回滚模块进行软件包回滚并再次执行BVT 测试,记录测试结果,回滚完成。
本文选自《京东系统质量保障技术实战》第四章,本站经机械工业出版社和作者的授权。
版权声明:51Testing软件测试网获机械工业出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。