多分支测试环境自动化部署

发表于:2020-5-07 11:48

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:51Testing教研团队    来源:51Testing软件测试网原创

  背景
  现在公司内使用的是K8S进行服务部署,内网测试环境也提供了K8S环境。团队内多人同时开发多个需求,必然会出现多个需求同时测试的情况。而部署到内网K8S测试环境,一次只能部署一个服务。如果将多个需求分支合并到一个分支上去,势必会相互影响,而且使用公司的TDC服务每次更新都要人工处理,效率偏低。为了解决这个问题,我在公司内网物理机上,针对静态网站和直出网站分别搭建了多分支的测试环境,并配合Gitlab CI自行自动化部署,减少人工部署耗时。
  实践路线
  目前手上有两个项目,一个是正常的静态网站,一个是服务端直出的网站。它们在部署上是有不同的,静态网站我们开发完打包好静态文件部署到服务器上配置好Nginx访问指定目录访问就行了。而服务端直出的项目则需要启动一个服务,并配置Nginx将请求转发到对应的服务上。
  因此针对上述情况我们需要事情如下:
  1.根据不同的分支输出对应的静态文件或者启动不同的服务;
  2.通过配置Nginx规则来实现通过访问URL上的信息将请求转发到对应的文件或服务;
  3.配置Gitlab CI并编写自动化脚本进行自动部署。
  如何区分不同分支
  静态网站
  针对静态网站,我们最终是将其部署在服务器上的某个目录中,通过Nginx转发进行访问。如果我们能够将不同分支打包到不同的目录下,并通过·Nginx配置进行访问就能实现访问。
  一个项目中每个人开发需求都会取一个唯一的分支名,而在Gitlab执行CI时会提供CI_COMMIT_REF_SLUG这个字段,这个字段的值是分支名称的值全转成小写并将除0-9和a-z的其他字符转换成-后获得的,可以用在URL中。
  这样我们只需在执行自动化脚本时,将CI_COMMIT_REF_SLUG当做参数传入打包脚本,在指定目录下新建对应名称的目录,并将打包文件通过过去变算是完成第一阶段的工作了。
  服务端直出网站
  服务端渲染的网站需要启动服务去吐出页面,因此我们的Nginx配置也是指向对应的服务。问题是项目的端口号是固定的。如果我们每个分支都人工修改项目端口号,一则可能上线时会忘记更改回来;二则还要人工确认对应端口是否被占用。显然是不合理的。
  刚好公司项目都上了K8S,都是用Docker进行部署。Docker的特性里有一条便是将容器内的端口暴露给外部,利用这个特性,我们可以在不改变项目启动端口的情况下,对外暴露不同的访问端口了:
 docker run  --name $CI_COMMIT_REF_SLUG -P -d <image>:$CI_COMMIT_REF_SLUG
  这里我们关注参数-P,这代表随机指定一个系统端口给当前容器。
  但是我们在测试时是需要修改bug的,每次修改完提交重新部署,肯定是希望能够维持已有端口而不是每次提交都变动。那我们可以每次重启服务的时候,先去获取已有服务的端口号:
 HOSTPORT=$(docker inspect --format='{{(index (index .NetworkSettings.Ports "3000/tcp") 0).HostPort}}' $CI_COMMIT_REF_SLUG)
  这样一来不同分支启动服务暴露不同端口的问题也就解决了。
  Nginx规则配置
  静态网站
  平时我们配置Nginx的server_name的时候,一般都是指定对应域名。但我们是可以在里面使用正则去匹配子域名的:
   server {
  listen       80;
  server_name  ~^(.+)?\.static\.test\.com$;
  set $www_root $1;
  root /data/vhosts/static.test.com/$www_root/;
  }
  以上是我静态项目的Nginx配置示例。我的静态网站在测试环境最终访问的链接是:
 http://$CI_COMMIT_REF_SLUG.static.test.com
  根据上面的正则表达式,Nginx在接到请求时,拿到了我们的分支别名后,将请求转发到项目目录下的指定分支目录了。
  服务端直出网站
  服务端直出网站的配置和静态网站的思路是一样的,只是把访问目录改成了访问服务而已:
   server {
  listen  80;
  server_name ~^(.+)?.server.test.com$;
  root html;
  ...
  set $port $1;
  location ~ / {
  proxy_pass  http://127.0.0.1:$port;
  ...
  }
  }
  最终的访问地址是:
 http://$port.server.test.com
  whistle规则
  因为实际生产中两个项目都是在客户端内部打开的,所以其实在测试时给出的两个网址和客户端配置的并不相同。这里可以用whistle配置规则进行转换,而且还能够支持HTTPS,非常的方便:
   https://static.test.com http://$CI_COMMIT_REF_SLUG.static.test.com
  https://server.test.com http://$port.server.test.com
  甚至使用了whistle之后服务端直出网站都可以不用配置Nginx,直接通过IP访问对应的服务就可以了:
 https://server.test.com http://ip:$port
  部署脚本
  静态网站
  静态网站部署脚本相对简单,只需对代码进行打包,然后同步到对应的文件夹即可:
   #!/bin/sh
  CI_COMMIT_REF_SLUG="$1"
  BUILD_COMMAND="yarn install --registry https://registry.npm.taobao.org; yarn build;"
  TARGET_DIR="/data/vhosts/static.test.com/$CI_COMMIT_REF_SLUG/"
  # 启动docker打包文件
  docker run -v $(pwd)/:/app -w  /app node:10 /bin/sh -c "$BUILD_COMMAND" || exit 1
  # 创建指定目录,-p表示:递归创建目录,如果目录已存在也不会报错
  mkdir -p $TARGET_DIR
  # 同步打包后文件到对应目录
  rsync -av --delete-after ./dist/ $TARGET_DIR
  服务端直出网站
  服务端直出网站部署脚本相对复杂,主要体现在更新时对容器的处理上:
   #!/bin/sh
  BUILD_COMMAND="yarn install --registry https://registry.npm.taobao.org; yarn build;"
  # 执行脚本时后面传入的第一个参数
  CI_COMMIT_REF_SLUG="$1"
  # 编译打包项目
  docker run -v $(pwd)/:/app -w  /app node:10 /bin/sh -c "$BUILD_COMMAND" || exit 1
  # 将项目打包到docker镜像,镜像名称带上CI_COMMIT_REF_SLUG
  # 运行此命令需要项目根路径有Dockerfile文件,文件比较简单,这里就不列出了
  docker build -t game-frontend:$CI_COMMIT_REF_SLUG .
  # 判断是否有当前分支对应的容器在运行
  if [ ! "$(docker ps -q -f name=$CI_COMMIT_REF_SLUG)" ];
  then
  # 如果有容器但已退出
  if [ "$(docker ps -aq -f status=exited -f name=$CI_COMMIT_REF_SLUG)" ];
  then
  # 删除容器
  docker rm $CI_COMMIT_REF_SLUG
  fi
  # 利用刚刚构建的镜像启动一个名为CI_COMMIT_REF_SLUG的容器
  docker run --name $CI_COMMIT_REF_SLUG -P -d game-frontend:$CI_COMMIT_REF_SLUG
  # 获取容器端口号,输出出来,方便查看
  HOSTPORT=$(docker inspect --format='{{(index (index .NetworkSettings.Ports "3000/tcp") 0).HostPort}}' $CI_COMMIT_REF_SLUG)
  echo "端口号:$HOSTPORT"
  # 如果已有容器,则获取端口号
  HOSTPORT=$(docker inspect --format='{{(index (index .NetworkSettings.Ports "3000/tcp") 0).HostPort}}' $CI_COMMIT_REF_SLUG)
  echo "端口号:$HOSTPORT"
  # 停止容器,并删除
  docker stop $CI_COMMIT_REF_SLUG
  docker rm $CI_COMMIT_REF_SLUG
  # 根据之前端口号启动新的容器
  docker run --name $CI_COMMIT_REF_SLUG -p $HOSTPORT:3000 -d game-frontend:$CI_COMMIT_REF_SLUG
  fi
  配置自动化部署
  完成了上面的准备工作之后,就可以配置Gitlab CI了。
  注册Gitlab Runner
  我们在Gitlab项目页中找到setting下面的CI/CD,按照指引安装Gitlab Runner即可。这里不多说了。
  编写.gitlab-ci.yml
   cache:
  untracked: true
  stages:
  - dev
  before_script:
  - git lfs pull
  dev:
  stage: dev
  script:
  # 这里就是上面编写的脚本
  - chmod +x ./scripts/test_dev.sh
  - ls -lsa ./scripts/test_dev.sh
  - ./scripts/test_dev.sh $CI_COMMIT_REF_SLUG
  tags:
  # 指定要使用的Gitlab runner
  - test-dev
  至此,自动化部署的多分支测试环境就配置完成了。
  遇到的问题
  1.在执行部署脚本时Gitlab runner需要去它的工作目录以外的地方创建目录,这时候出现了权限问题。
  因为是测试机,我直接将**/etc/passwd**中的gitlab-runner对于应的第三个参数user id修改为了0(root账号)便可以了:
 gitlab-runner:x:0:0:GitLab Runner:/home/gitlab-runner:/bin/bash
  2.执行脚本拉取公司docker仓库镜像时报权限问题,但是我机器上明明已经登录过了。这里是因为gitlab runner读取的是/home/gitlab-runner/.docker/下的账号配置,我们需要在ci中重新登录docker。

     本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号