自动测试
简介
自动测试是CI中的一个环节,由代码合并master时自动触发,主要的目的是为了这次的版本变更不会影响到系统中的其他功能,保证整个系统对外提供的功能的正确性。详细的CI/CD的介绍请参考附录二:CI/CD。
GitLab CI
使用 GitLab CI + Docker Compose实现整个整个CI的流程。GitLab是通过项目根路径下的.gitlab-ci.yml文件配置定义CI流程,一般情况下使用标准CI配置文件即可,但在一些有特殊要求的项目下,开发人员需要能够在标准配置文件上修改自己项目的特殊需求。下面是php版本的标准CI配置文件及解释,详细请参考配置文件手册。
# 定义 stages
stages:
- test
- push
- deploy
- cleanup
variables:
# 项目唯一标识
PROJECT_INDEX: ${CI_PROJECT_NAME}${CI_COMMIT_SHA}
# 线下镜像仓库地址
DEV_REGISTRY_ADDRESS: gitlab.nw.com
# 生产镜像仓库地址
PRO_REGISTRY_ADDRESS: dockerhub.nw.com
# 镜像仓库名称
REPOSITORY: ${CI_PROJECT_PATH}
before_script:
- docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${DEV_REGISTRY_ADDRESS}
# 集成测试
test_job:
stage: test
script:
- docker-compose -p ${PROJECT_INDEX} up -d php
- sleep 120
- docker-compose -p ${PROJECT_INDEX} run --rm -w /data1/htdocs/${CI_PROJECT_NAME}/test/ php phpunit
after_script:
# 销毁测试中生产的容器和镜像
- docker-compose -p ${PROJECT_INDEX} down
- docker rmi ${PROJECT_INDEX}_php
only:
- master
tags:
- CI
# 推送镜像到线下代码仓库
push_offline:
stage: push
script:
- docker build -t ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA} .
- docker push ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA}
# 打上latest标签,以备构建稳定测试环境使用
- docker tag ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA} ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}
after_script:
# 清理镜像
- docker rmi ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA}
only:
- master
tags:
- CI
# 将镜像发布到生产仓库
push_online:
stage: push
script:
- git archive --format=zip [email protected]:security/configure.git master -o /tmp/configure.zip
- unzip -o /tmp/configure.zip -d /tmp/configure/
- cp -r /tmp/configure/${CI_PROJECT_NAME}/* ./
- docker build -t ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA} .
- sh /data/gitlab/bin/push.sh ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA}
- docker tag ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA} ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}
- sh /data/gitlab/bin/push.sh ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}
after_script:
- docker rmi ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA}
environment:
name: production
when: manual
only:
- master
tags:
- CD
# 更新测试环境的代码
deploy_test:
stage: deploy
script:
- docker-compose -f /data/test/${CI_PROJECT_PATH}/docker-compose.yml stop php
- docker-compose -f /data/test/${CI_PROJECT_PATH}/docker-compose.yml rm -f php
- docker-compose -f /data/test/${CI_PROJECT_PATH}/docker-compose.yml up -d php
only:
- master
tags:
- CI
# 清理ci过程中产生的环境
cleanup_job:
stage: cleanup
script:
# 对于稳定测试环境更新时会产生一些tag为none的镜像,此步骤是为了清理这些虚悬镜像
- docker images|grep none|awk '{print $3}'|xargs docker rmi -f
when: always
only:
- master
tags:
- CI
java版本CI文件如下:
# 定义 stages
stages:
- test
- push
- deploy
- cleanup
variables:
# 项目唯一标识
PROJECT_INDEX: ${CI_PROJECT_NAME}${CI_COMMIT_SHA}
# 线下镜像仓库地址
DEV_REGISTRY_ADDRESS: gitlab.nw.com
# 生产镜像仓库地址
PRO_REGISTRY_ADDRESS: dockerhub.nw.com
# 镜像仓库名称
REPOSITORY: ${CI_PROJECT_PATH}
before_script:
- docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${DEV_REGISTRY_ADDRESS}
# 集成测试
test_job:
stage: test
script:
- echo "skip test"
only:
- master
tags:
- CI
# 推送镜像到线下代码仓库
push_offline:
stage: push
script:
# 编译(构建编译环境,进行编译,可以通过编译环境解决不同版本jdk的问题)
- git archive --format=zip --format zip -o /tmp/${PROJECT_INDEX}.zip HEAD
- unzip -o /tmp/${PROJECT_INDEX}.zip -d /tmp/${PROJECT_INDEX}/
- docker run -i --rm --name mvn-jdk7 -v /path/to/local/repo:/path/to/local/repo -v /usr/share/maven/conf/settings.xml:/usr/share/maven/conf/settings.xml -v /tmp/${PROJECT_INDEX}:/data/${PROJECT_NAME} -w /data/${CI_PROJECT_NAME} maven:3-jdk-7 mvn package -DskipTests
- cp -r /tmp/${PROJECT_INDEX}/* ./
- docker build -t ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA} .
- docker push ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA}
# 打上latest标签,以备构建稳定测试环境使用
- docker tag ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA} ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}
after_script:
- rm -rf /tmp/${PROJECT_INDEX}.zip
- rm -rf /tmp/${PROJECT_INDEX}
# 清理镜像
- docker rmi ${DEV_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA}
only:
- master
tags:
- CI
# 将镜像发布到生产仓库
push_online:
stage: push
script:
# 编译(构建编译环境,进行编译,可以通过编译环境解决不同版本jdk的问题)
- git archive --format=zip --format zip -o /tmp/${PROJECT_INDEX}.zip HEAD
- unzip -o /tmp/${PROJECT_INDEX}.zip -d /tmp/${PROJECT_INDEX}/
- docker run -i --rm --name mvn-jdk7 -v /path/to/local/repo:/path/to/local/repo -v /usr/share/maven/conf/settings.xml:/usr/share/maven/conf/settings.xml -v /tmp/${PROJECT_INDEX}:/data/${PROJECT_NAME} -w /data/${CI_PROJECT_NAME} maven:3-jdk-7 mvn package -DskipTests
- cp -r /tmp/${PROJECT_INDEX}/* ./
# 添加生产配置
- git archive --format=zip [email protected]:security/configure.git master -o /tmp/configure.zip
- unzip -o /tmp/configure.zip -d /tmp/configure/
- cp -r /tmp/configure/${CI_PROJECT_NAME}/* ./
- docker build -t ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA} .
- sh /data/gitlab/bin/push.sh ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA}
- docker tag ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA} ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}
- sh /data/gitlab/bin/push.sh ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}
after_script:
- rm -rf /tmp/${PROJECT_INDEX}.zip
- rm -rf /tmp/${PROJECT_INDEX}
- docker rmi ${PRO_REGISTRY_ADDRESS}/${REPOSITORY}:${CI_COMMIT_SHA}
environment:
name: production
when: manual
only:
- master
tags:
- CD
# 更新稳定环境的代码
deploy_test:
stage: deploy
script:
- echo "skip deploy test"
only:
- master
tags:
- CI
# 清理ci过程中产生的环境
cleanup_job:
stage: cleanup
script:
- echo "skip cleanup"
when: always
only:
- master
tags:
- CI
Pipeline
一次 Pipeline 其实相当于一次构建任务,里面可以包含多个流程,如安装依赖、运行测试、编译、部署测试服务器、部署生产服务器等流程。
任何提交或者 Merge Request 的合并都可以触发 Pipeline,如下图所示:
+------------------+ +----------------+
| | trigger | |
| Commit / MR +---------->+ Pipeline |
| | | |
+------------------+ +----------------+
Stages
Stages 表示构建阶段,说白了就是上面提到的流程。我们可以在一次 Pipeline 中定义多个 Stages,这些 Stages 会有以下特点:
- 所有 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始
- 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败
因此,Stages 和 Pipeline 的关系就是:
+--------------------------------------------------------+
| |
| Pipeline |
| |
| +-----------+ +------------+ +------------+ |
| | Stage 1 |---->| Stage 2 |----->| Stage 3 | |
| +-----------+ +------------+ +------------+ |
| |
+--------------------------------------------------------+
Jobs
Jobs 表示构建工作,表示某个 Stage 里面执行的工作。我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:
- 相同 Stage 中的 Jobs 会并行执行
- 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功
- 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败
所以,Jobs 和 Stage 的关系图就是:
+------------------------------------------+
| |
| Stage 1 |
| |
| +---------+ +---------+ +---------+ |
| | Job 1 | | Job 2 | | Job 3 | |
| +---------+ +---------+ +---------+ |
| |
+------------------------------------------+
环境构建
采用docker服务编排进行构建,执行完单元测试后即销毁,编排文件与本地环境编排文件一致,构建命令。
docker-compose -p PROJECT_INDEX up php -d
执行单元测试用例:
docker-compose -p $PROJECT_INDEX run --rm -w /data1/htdocs/$CI_PROJECT_NAME/test/ php phpunit
注意事项
- 开发人员需要能够严格的按照要求去编写测试用例。
- 当CI构建失败时,一定要及时的去查找CI的失败原因并修改。