基于GitLab实现端到端DevOps流水线实践

运维 系统运维
本文档中的工作流是根据之前项目团队工作模式而配置的。重点参考技术的实现方式,工作流可以根据自身团队情况而定义。

[[396767]]

基于Gitlab实现项目端到端交付实践,从需求开发开始到交付流水线实现应用发布。每个项目团队的工作流都是不一样的,本文档中的工作流是根据之前项目团队工作模式而配置的。重点参考技术的实现方式,工作流可以根据自身团队情况而定义。

来源:http://www.idevops.site

1.整体规划设计


创建issue --> 创建特性分支 --> 特性分支提交流水线 --> 合并分支流水线 --> 发布分支流水线

  1. 创建issues关联特性分支 (特征以数字开头的分支为特性分支)
  2. 特性分支提交代码,触发提交流水线(构建验证部署到特性环境)
  3. 特性环境验证完成,合并到RELEASE分支。(触发合并流水线进行代码扫描,流水线成功才能合并)
  4. RELEASE分支手动发布 (UAT,STAG,PROD)
  5. 生产发布完成后RELEASE分支合并到Master分支,并基于master分支创建Release tag。

2.需求部分准备工作

创建里程碑

 

创建issue,关联里程碑

根据issue名称创建对应的特性分支

3.流水线准备工作

还可以直接使用之前的java项目

github :https://github.com/zeyangli/gitlabci-cidevops-java-service

准备模板库

准备可用的runner,根据之前内容安装部署runner 。

chart :https://github.com/zeyangli/gitlabci-runner-chart-k8s

配置项目CI文件

4.提交流水线设计

开发人员在特性分支提交代码,触发提交流水线进行代码验证并发布到特性环境验证(可手动控制发布)。

阶段:编译,测试,扫描,构建镜像,上传镜像,发布特性环境

特性环境:命名规范为项目名称-ID-分支名称,每个特性分支发布到对应的特性环境。

镜像名称:

  1. registry.cn-beijing.aliyuncs.com/cidevops/cidevops-java-service:3-input-error-a486c590-834 

ingress域名:

  1. "http://${CI_COMMIT_REF_NAME}.${CI_PROJECT_NAMESPACE}.${CI_PROJECT_NAME}.devops.com" 

Build阶段

定义build作业模板,参数化构建命令。

  1. ## build相关作业 
  2. ## 
  3.  
  4. .build: 
  5.   stage: build 
  6.   script:  
  7.     - ${BUILD_SHELL} 

在template中引入build作业模板,由于使用容器构建所以声明MAVEN_IMAGE变量定义镜像名称。由于之前对构建环境构建目录持久化,所以定义GIT_CLONE_PATH参数进入指定的构建目录操作。GIT_CHECKOUT设置全局每个作业无需重复下载代码。BUILD_SHELL定义构建所需要的命令。定义变量能够足够灵活,适合不同项目不同打包命令的场景下。

  1. include: 
  2.   - project: 'cidevops/cidevops-newci-service' 
  3.     ref: master 
  4.     file: 'jobs/build.yml' 
  5.  
  6.  
  7. variables: 
  8.   ## 全局配置 
  9.   GIT_CLONE_PATH: $CI_BUILDS_DIR/builds/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/$CI_PIPELINE_ID     
  10.   GIT_CHECKOUT: "false" 
  11.  
  12.   ## 依赖容器镜像 
  13.   BUILD_IMAGE: "maven:3.6.3-jdk-8" 
  14.    
  15.   ## 构建测试参数 
  16.   MAVEN_OPTS: "-Dmaven.repo.local=/home/gitlab-runner/ci-build-cache/maven " 
  17.   BUILD_SHELL: 'mvn clean package  -DskipTests  --settings=./settings.xml '  ##构建命令 
  18.  
  19.  
  20.  
  21. ## 运行阶段   
  22. stages: 
  23.   - build 
  24.  
  25. cache: 
  26.   paths: 
  27.     - target/ 
  28.      
  29. ################# Jobs Configure ##################### 
  30. ## 构建作业 
  31. build: 
  32.   variables: 
  33.     GIT_CHECKOUT: "true" 
  34.   image: ${BUILD_IMAGE} 
  35.   extends: .build 

定义build作业,设置作业变量GIT_CHECKOUT: "true"表示需要下载代码,默认build是我们流水线中的第一个作业所以必须设置为下载代码,否则构建失败。作业中的变量优先级高于全局。image定义我们要使用的镜像,如果采用非容器模式运行可以删除image标签。剩下的配置全部集成模板作业.build。

Test阶段

这里定义的是在运行编译后进行的单元测试。maven项目一般是mvn test,npm项目一般是npm run test等。不同的项目运行单元测试的指令不通,其他部分都差不多。这里以maven项目为例。开始设计maven项目单元测试。

编辑jobs/test.yml文件定义test作业模板。(后续自动化测试等测试相关作业放到此文件)

  1. #单元测试 
  2. .test: 
  3.   stage: test 
  4.   script: 
  5.     - $TEST_SHELL 
  6.   artifacts: 
  7.     reports: 
  8.       junit: ${JUNIT_REPORT_PATH} 

编辑模板文件,添加导入test作业模板。

  1. include: 
  2.   - project: 'cidevops/cidevops-newci-service' 
  3.     ref: master 
  4.     file: 'jobs/build.yml' 
  5.   - project: 'cidevops/cidevops-newci-service' 
  6.     ref: master 
  7.     file: 'jobs/test.yml' 

在模板文件中添加变量定义。

  1. variables: 
  2.   TEST_SHELL : 'mvn test  --settings=./settings.xml '                        ##测试命令 
  3.   JUNIT_REPORT_PATH: 'target/surefire-reports/TEST-*.xml'   ##单元测试报告 
  4.    
  5.    
  6. ## 测试作业 
  7. test: 
  8.   image: ${BUILD_IMAGE} 
  9.   extends: .test 
  10.   before_script: 
  11.     - ls  
  12.     - ls target/ 

 

代码扫描阶段

jobs/code_analysis.yml

  1. ##代码扫描 
  2. ## 
  3. ## 
  4. ## 
  5.  
  6. .code_analysis: 
  7.   variables: 
  8.     GLOBAL_PROJECT_ARGS: "-Dsonar.projectKey=${CI_PROJECT_NAME}  
  9.                           -Dsonar.projectName=${CI_PROJECT_NAME}  
  10.                           -Dsonar.projectVersion=${CI_COMMIT_REF_NAME}  
  11.                           -Dsonar.projectDescription=${CI_PROJECT_TITLE}" 
  12.     GLOBAL_SERVER_ARGS:  "-Dsonar.ws.timeout=30  
  13.                           -Dsonar.links.homepage=${CI_PROJECT_URL}  
  14.                           -Dsonar.host.url=${SONAR_SERVER_URL}  
  15.                           -Dsonar.login=${SONAR_SERVER_LOGIN} 
  16.                           -Dsonar.sourceEncoding=UTF-8 " 
  17.     GLOBAL_MR_ARGS: " -Dsonar.pullrequest.key=${CI_MERGE_REQUEST_IID}  
  18.                       -Dsonar.pullrequest.branch=${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}  
  19.                       -Dsonar.pullrequest.base=${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}  
  20.                       -Dsonar.gitlab.ref_name=${CI_COMMIT_REF_NAME}  
  21.                       -Dsonar.gitlab.commit_sha=${CI_COMMIT_SHA}  
  22.                       -Dsonar.gitlab.project_id=${CI_PROJECT_PATH}  
  23.                       -Dsonar.pullrequest.gitlab.repositorySlug=${CI_PROJECT_ID} " 
  24.     MULTI_BRANCH_ARGS: "-Dsonar.branch.name=${CI_COMMIT_REF_NAME}" 
  25.   stage: code_analysis 
  26.   script: 
  27.     - echo ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} ${GLOBAL_MR_ARGS} 
  28.     #sonar-scanner $GLOBAL_PROJECT_ARGS $GLOBAL_SERVER_ARGS $SCAN_JAVA_ARGS 
  29.     - | 
  30.         if [ $CI_PIPELINE_SOURCE == 'merge_request_event' ]  
  31.          
  32.         then 
  33.            echo "sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} ${GLOBAL_MR_ARGS}" 
  34.            sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS} ${GLOBAL_MR_ARGS} 
  35.         else  
  36.            echo "sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS}" 
  37.            sonar-scanner ${GLOBAL_PROJECT_ARGS} ${GLOBAL_SERVER_ARGS} ${SONAR_SCAN_ARGS}  ${MULTI_BRANCH_ARGS} 
  38.         fi  
  39.          
  40. .get_analysis_result: 
  41.   stage: get_analysis_result 
  42.   script: 
  43.     - | 
  44.         SONAR_REPORT_URL=$(grep "ceTaskUrl" .scannerwork/report-task.txt  | awk -F = '{OFS="=";print $2,$3}'
  45.         echo ${SONAR_REPORT_URL} 
  46.          
  47.          
  48.         for i in {1..10} 
  49.         do 
  50.           curl -k -u "ee2bcb37deeb6dfe3a07fe08fb529559b00c1b7b":"" ${SONAR_REPORT_URL}  -o sonar_result.txt -s 
  51.           grep '"status":"SUCCESS"' sonar_result.txt  && SONAR_SCAN_RESULT='SUCCESS' 
  52.          
  53.           if [ ${SONAR_SCAN_RESULT} == 'SUCCESS' ] 
  54.             then 
  55.               echo "${SONAR_SCAN_RESULT}" 
  56.               SONAR_SCAN_RESULT=SUCCESS 
  57.               break; 
  58.           else 
  59.             SONAR_SCAN_RESULT='ERROR' 
  60.             echo "第$i次获取结果信息,不是成功状态,睡眠10秒!" 
  61.             cat sonar_result.txt 
  62.             sleep 10 
  63.           fi 
  64.         done 

流水线模板

templates/pipeline.yml

  1. include: 
  2.   - project: 'cidevops/cidevops-newci-service' 
  3.     ref: master 
  4.     file: 'jobs/build.yml' 
  5.   - project: 'cidevops/cidevops-newci-service' 
  6.     ref: master 
  7.     file: 'jobs/test.yml' 
  8.   - project: 'cidevops/cidevops-newci-service' 
  9.     ref: master 
  10.     file: 'jobs/codeanalysis.yml' 
  11.  
  12.  
  13.  
  14. variables: 
  15.   ## 全局配置 
  16.   GIT_CLONE_PATH: $CI_BUILDS_DIR/builds/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/$CI_PIPELINE_ID     
  17.   GIT_CHECKOUT: "false" 
  18.  
  19.   ## 依赖容器镜像 
  20.   BUILD_IMAGE: "maven:3.6.3-jdk-8" 
  21.   SONAR_IMAGE: "sonarsource/sonar-scanner-cli:latest" 
  22.    
  23.   ## 构建测试参数 
  24.   MAVEN_OPTS: "-Dmaven.repo.local=/home/gitlab-runner/ci-build-cache/maven " 
  25.   BUILD_SHELL: 'mvn clean package  -DskipTests  --settings=./settings.xml '  ##构建命令 
  26.   TEST_SHELL : 'mvn test  --settings=./settings.xml '                        ##测试命令 
  27.   JUNIT_REPORT_PATH: 'target/surefire-reports/TEST-*.xml'   ##单元测试报告 
  28.  
  29.   ## 代码扫描 
  30.   SONAR_PROJECT_LANG: "JAVA" 
  31.   SONAR_SOURCE_DIR : "src"  
  32.   SONAR_SERVER_URL: "http://192.168.1.200:30090"  
  33.   SONAR_SERVER_LOGIN: "ee2bcb37deeb6dfe3a07fe08fb529559b00c1b7b"  
  34.   SONAR_SCAN_ARGS: "-Dsonar.sources=${SONAR_SOURCE_DIR}  
  35.                    -Dsonar.java.binaries=target/classes  
  36.                    -Dsonar.java.test.binaries=target/test-classes  
  37.                    -Dsonar.java.surefire.report=target/surefire-reports " 
  38.  
  39.    
  40.  
  41.  
  42.  
  43. ## 运行阶段   
  44. stages: 
  45.   - build 
  46.   - test 
  47.   - parallel01 
  48.  
  49. cache: 
  50.   paths: 
  51.     - target/ 
  52.      
  53. ################# Jobs Configure ##################### 
  54. ## 构建作业 
  55. build: 
  56.   variables: 
  57.     GIT_CHECKOUT: "true" 
  58.   image: ${BUILD_IMAGE} 
  59.   extends: .build 
  60.  
  61. ## 测试作业 
  62. test: 
  63.   image: ${BUILD_IMAGE} 
  64.   extends: .test 
  65.   before_script: 
  66.     - ls  
  67.     - ls target/ 
  68.  
  69. ## 代码扫描 
  70. code_analysis: 
  71.   stage: parallel01 
  72.   image: ${SONAR_IMAGE} 
  73.   extends: .code_analysis 

 

构建镜像阶段

jobs/build.yml

  1. .build-docker: 
  2.   stage: buildimage 
  3.   script: 
  4.     - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWD  $CI_REGISTRY 
  5.     - docker build -t ${IMAGE_NAME} -f ${DOCKER_FILE_PATH} . 
  6.     - docker push ${IMAGE_NAME}  
  7.     - docker rmi ${IMAGE_NAME} 

telmplate/pipeline.yml

  1. include: 
  2.   - project: 'cidevops/cidevops-newci-service' 
  3.     ref: master 
  4.     file: 'jobs/build.yml' 
  5.   - project: 'cidevops/cidevops-newci-service' 
  6.     ref: master 
  7.     file: 'jobs/test.yml' 
  8.   - project: 'cidevops/cidevops-newci-service' 
  9.     ref: master 
  10.     file: 'jobs/codeanalysis.yml' 
  11.  
  12.  
  13.  
  14. variables: 
  15.   ## 全局配置 
  16.   GIT_CLONE_PATH: $CI_BUILDS_DIR/builds/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/$CI_PIPELINE_ID     
  17.   GIT_CHECKOUT: "false" 
  18.  
  19.   ## 依赖容器镜像 
  20.   BUILD_IMAGE: "maven:3.6.3-jdk-8" 
  21.   SONAR_IMAGE: "sonarsource/sonar-scanner-cli:latest" 
  22.    
  23.   ## 构建测试参数 
  24.   MAVEN_OPTS: "-Dmaven.repo.local=/home/gitlab-runner/ci-build-cache/maven " 
  25.   BUILD_SHELL: 'mvn clean package  -DskipTests  --settings=./settings.xml '  ##构建命令 
  26.   TEST_SHELL : 'mvn test  --settings=./settings.xml '                        ##测试命令 
  27.   JUNIT_REPORT_PATH: 'target/surefire-reports/TEST-*.xml'   ##单元测试报告 
  28.  
  29.   ## 代码扫描 
  30.   SONAR_PROJECT_LANG: "JAVA" 
  31.   SONAR_SOURCE_DIR : "src"  
  32.   SONAR_SERVER_URL: "http://192.168.1.200:30090"  
  33.   SONAR_SERVER_LOGIN: "ee2bcb37deeb6dfe3a07fe08fb529559b00c1b7b"  
  34.   SONAR_SCAN_ARGS: "-Dsonar.sources=${SONAR_SOURCE_DIR}  
  35.                    -Dsonar.java.binaries=target/classes  
  36.                    -Dsonar.java.test.binaries=target/test-classes  
  37.                    -Dsonar.java.surefire.report=target/surefire-reports " 
  38.  
  39.   #构建镜像 
  40.   CI_REGISTRY: 'registry.cn-beijing.aliyuncs.com' 
  41.   CI_REGISTRY_USER: 'xxxxx' 
  42.   #CI_REGISTRY_PASSWD: 'xxxxxxxx.' 
  43.   IMAGE_NAME: "$CI_REGISTRY/$CI_PROJECT_PATH:$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA" 
  44.   DOCKER_FILE_PATH: "./Dockerfile" 
  45.  
  46.  
  47.  
  48.  
  49. ## 运行阶段   
  50. stages: 
  51.   - build 
  52.   - test 
  53.   - parallel01 
  54.  
  55. cache: 
  56.   paths: 
  57.     - target/ 
  58.      
  59. ################# Jobs Configure ##################### 
  60. ## 构建作业 
  61. build: 
  62.   variables: 
  63.     GIT_CHECKOUT: "true" 
  64.   image: ${BUILD_IMAGE} 
  65.   extends: .build 
  66.  
  67. ## 测试作业 
  68. test: 
  69.   image: ${BUILD_IMAGE} 
  70.   extends: .test 
  71.   before_script: 
  72.     - ls  
  73.     - ls target/ 
  74.  
  75. ## 代码扫描 
  76. code_analysis: 
  77.   stage: parallel01 
  78.   image: ${SONAR_IMAGE} 
  79.   extends: .code_analysis 
  80.  
  81. ## 构建镜像 
  82. build_image: 
  83.   image: docker:latest 
  84.   services: 
  85.     - name: docker:dind 
  86.   stage: parallel01 
  87.   extends: .build-docker 

 

K8S部署阶段

jobs/deploy.yml

  1. ## 应用发布 
  2.  
  3.  
  4. ## 使用kubectl镜像发布 
  5. .deploy_k8s: 
  6.   stage: deploy 
  7.   script: 
  8.     - echo $KUBE_TOKEN 
  9.     - kubectl config set-cluster my-cluster --server=${KUBE_URL} --certificate-authority="${KUBE_CA_PEM_FILE}" 
  10.     - kubectl config set-credentials admin --token=${KUBE_TOKEN} 
  11.     - ls -a  
  12.     - sed -i "s#__namespace__#${NAMESPACE}#g" deployment.yaml  
  13.     - sed -i "s#__appname__#${APP_NAME}#g" deployment.yaml  
  14.     - sed -i "s#__containerport__#${CONTAINER_PORT}#g" deployment.yaml  
  15.     - sed -i "s#__nodeport__#${NODE_PORT}#g" deployment.yaml  
  16.     - sed -i "s#__imagename__#${IMAGE_NAME}#g" deployment.yaml  
  17.     - sed -i "s#__CI_ENVIRONMENT_SLUG__#${CI_ENVIRONMENT_SLUG}#g" deployment.yaml  
  18.     - sed -i "s#__CI_PROJECT_PATH_SLUG__#${CI_PROJECT_PATH_SLUG}#g" deployment.yaml 
  19.     - sed -i "s#__ingressdomain__#${ENV_URL}#g" deployment.yaml 
  20.     - cat deployment.yaml 
  21.     - "kubectl create secret docker-registry ${APP_NAME} \ 
  22.             --docker-server=${CI_REGISTRY} \ 
  23.             --docker-username=$CI_REGISTRY_USER \ 
  24.             --docker-password=${CI_REGISTRY_PASSWD} \ 
  25.             --docker-email=test@test.com -n ${NAMESPACE} || echo 'secrets already exists'" 
  26.     - kubectl apply -f deployment.yaml   
  27.   environment: 
  28.     name"${CI_COMMIT_REF_NAME}" 
  29.     url: "http://${CI_COMMIT_REF_NAME}.${CI_PROJECT_NAMESPACE}.${CI_PROJECT_NAME}.devops.com" 
  30.     on_stop: rollout_k8s 
  31.   when: manual 
  32.    
  33. ## 回滚 
  34. .rollout_k8s: 
  35.   stage: rollout 
  36.   script: 
  37.     - rm -rf $HOME/.kube 
  38.     - kubectl config set-cluster my-cluster --server=${KUBE_URL} --certificate-authority="${KUBE_CA_PEM_FILE}" 
  39.     - kubectl config set-credentials admin --token=${KUBE_TOKEN} 
  40.     - kubectl rollout history deployment ${APP_NAME} -n ${NAMESPACE} 
  41.     - kubectl rollout undo deployment ${APP_NAME} -n ${NAMESPACE} 
  42.   when: manual 
  43.   environment: 
  44.     name"${CI_COMMIT_REF_NAME}" 
  45.     action: stop 

templates/pipeline.yml

  1. include: 
  2.   - project: 'cidevops/cidevops-newci-service' 
  3.     ref: master 
  4.     file: 'jobs/build.yml' 
  5.   - project: 'cidevops/cidevops-newci-service' 
  6.     ref: master 
  7.     file: 'jobs/test.yml' 
  8.   - project: 'cidevops/cidevops-newci-service' 
  9.     ref: master 
  10.     file: 'jobs/codeanalysis.yml' 
  11.   - project: 'cidevops/cidevops-newci-service' 
  12.     ref: master 
  13.     file: 'jobs/deploy.yml' 
  14.  
  15.  
  16.  
  17. variables: 
  18.   ## 全局配置 
  19.   GIT_CLONE_PATH: $CI_BUILDS_DIR/builds/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/$CI_PIPELINE_ID     
  20.   GIT_CHECKOUT: "false" 
  21.  
  22.   ## 依赖容器镜像 
  23.   BUILD_IMAGE: "maven:3.6.3-jdk-8" 
  24.   SONAR_IMAGE: "sonarsource/sonar-scanner-cli:latest" 
  25.    
  26.   ## 构建测试参数 
  27.   MAVEN_OPTS: "-Dmaven.repo.local=/home/gitlab-runner/ci-build-cache/maven " 
  28.   BUILD_SHELL: 'mvn clean package  -DskipTests  --settings=./settings.xml '  ##构建命令 
  29.   TEST_SHELL : 'mvn test  --settings=./settings.xml '                        ##测试命令 
  30.   JUNIT_REPORT_PATH: 'target/surefire-reports/TEST-*.xml'   ##单元测试报告 
  31.  
  32.   ## 代码扫描 
  33.   SONAR_PROJECT_LANG: "JAVA" 
  34.   SONAR_SOURCE_DIR : "src"  
  35.   SONAR_SERVER_URL: "http://192.168.1.200:30090"  
  36.   SONAR_SERVER_LOGIN: "ee2bcb37deeb6dfe3a07fe08fb529559b00c1b7b"  
  37.   SONAR_SCAN_ARGS: "-Dsonar.sources=${SONAR_SOURCE_DIR}  
  38.                    -Dsonar.java.binaries=target/classes  
  39.                    -Dsonar.java.test.binaries=target/test-classes  
  40.                    -Dsonar.java.surefire.report=target/surefire-reports " 
  41.  
  42.   #构建镜像 
  43.   CI_REGISTRY: 'registry.cn-beijing.aliyuncs.com' 
  44.   CI_REGISTRY_USER: 'xxxxx' 
  45.   #CI_REGISTRY_PASSWD: 'xxxxxxxx.' 
  46.   IMAGE_NAME: "$CI_REGISTRY/$CI_PROJECT_PATH:$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA" 
  47.   DOCKER_FILE_PATH: "./Dockerfile" 
  48.  
  49.   #部署应用k8s 
  50.   RUN_DEPLOY: "yes" 
  51.   APP_NAME: "$CI_PROJECT_NAME" 
  52.   CONTAINER_PORT: 8081 
  53.   #NODE_PORT: 30185 
  54.   NAMESPACE: "$CI_PROJECT_NAME-$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG" 
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61. ## 运行阶段   
  62. stages: 
  63.   - build 
  64.   - test 
  65.   - parallel01 
  66.   - deploy 
  67.   - rollout 
  68.  
  69.  
  70. cache: 
  71.   paths: 
  72.     - target/ 
  73.      
  74. ################# Jobs Configure ##################### 
  75. ## 构建作业 
  76. build: 
  77.   variables: 
  78.     GIT_CHECKOUT: "true" 
  79.   image: ${BUILD_IMAGE} 
  80.   extends: .build 
  81.  
  82. ## 测试作业 
  83. test: 
  84.   image: ${BUILD_IMAGE} 
  85.   extends: .test 
  86.   before_script: 
  87.     - ls  
  88.     - ls target/ 
  89.  
  90. ## 代码扫描 
  91. code_analysis: 
  92.   stage: parallel01 
  93.   image: ${SONAR_IMAGE} 
  94.   extends: .code_analysis 
  95.  
  96. ## 构建镜像 
  97. build_image: 
  98.   image: docker:latest 
  99.   services: 
  100.     - name: docker:dind 
  101.   stage: parallel01 
  102.   extends: .build-docker 
  103.  
  104. ## 发布应用 
  105. deploy_k8s: 
  106.   stage: deploy 
  107.   image: lucj/kubectl:1.17.2 
  108.   extends: .deploy_k8s 
  109.      
  110. ## 应用回滚 
  111. rollout_k8s: 
  112.   stage: rollout 
  113.   image: lucj/kubectl:1.17.2 
  114.   extends: .rollout_k8s 

5.流水线触发控制

使用workflow:rules 进行流水线控制,我们会用到Pipeline的变量,通过变量限制条件。

预定义变量参考文档:https://docs.gitlab.com//12.9/ee/ci/variables/predefined_variables.html

变量匹配语法: https://docs.gitlab.com//12.9/ee/ci/variables/README.html#supported-syntax

re2语法:https://github.com/google/re2/wiki/Syntax

排除新建分支的流水线

运行流水线您会发现,所有新创建的分支的CI_COMMIT_BEFORE_SHA为40个0。

  1. $ export 
  2.  
  3. declare -x CI_BUILD_BEFORE_SHA="0000000000000000000000000000000000000000" 
  4. declare -x CI_COMMIT_BEFORE_SHA="0000000000000000000000000000000000000000" 

  1. ## 流水线控制 
  2. workflow: 
  3.   rules: 
  4.     - if: $CI_COMMIT_BEFORE_SHA == "0000000000000000000000000000000000000000" 
  5.       when: never 
  6.     - when: always 

如何匹配特性分支和版本分支呢?

  1. #$CI_COMMIT_REF_NAME =~ /\d-*/ 
  2. #$CI_COMMIT_REF_NAME =~ /^RELEASE-*/  || 

合并流水线再进行构建验证

大家可以想像一下,如果是一个刚刚开始关注代码质量的团队,避免不了出现代码质量阈失败。 改进初期出现错误很正常,如果在初期就把质量阈配置的很严格,这会导致每次提交代码都会产生错误。所以我们可以适当的放开流水线的代码扫描(也就是流水线暂时不进行质量阈检查)。

如果不扫描就无法知道代码的准确质量,所以我们准备流水线仅扫描但不检查质量阈,而合并流水线会将代码质量展示在评论区。类似于这种情况我们可以设置流水线成功后才能合并。

默认是提交触发流水线运行,而设置了"流水线成功后合并"会检查原分支的最后一次提交的状态是否为success,如果是success则运行合并。 我们配置流水线在出现合并请求的时候,进行代码验证。

  1. ## 流水线控制 
  2. workflow: 
  3.   rules: 
  4.     - if: $CI_MERGE_REQUEST_ID 

6.部署流水线实践

我们将应用的部署文件也存储在代码库中管理,可能每个应用在各个环境中的配置文件不一致。所有分为三个配置文件 deployment-uat.yml、 deployment-stag.yml、 deployment-prod.yml

jobs/deploy.yml

  1. ## 应用发布 
  2.  
  3.  
  4. ## 使用kubectl镜像发布 
  5. .deploy_k8s: 
  6.   stage: deploy 
  7.   script: 
  8.     - echo $KUBE_TOKEN 
  9.     - kubectl config set-cluster my-cluster --server=${KUBE_URL} --certificate-authority="${KUBE_CA_PEM_FILE}" 
  10.     - kubectl config set-credentials admin --token=${KUBE_TOKEN} 
  11.     - ls -a  
  12.     - sed -i "s#__namespace__#${NAMESPACE}#g" ${DEPLOY_FILE} 
  13.     - sed -i "s#__appname__#${APP_NAME}#g" ${DEPLOY_FILE} 
  14.     - sed -i "s#__containerport__#${CONTAINER_PORT}#g" ${DEPLOY_FILE}  
  15.     - sed -i "s#__nodeport__#${NODE_PORT}#g" ${DEPLOY_FILE}  
  16.     - sed -i "s#__imagename__#${IMAGE_NAME}#g" ${DEPLOY_FILE}  
  17.     - sed -i "s#__CI_ENVIRONMENT_SLUG__#${CI_ENVIRONMENT_SLUG}#g" ${DEPLOY_FILE} 
  18.     - sed -i "s#__CI_PROJECT_PATH_SLUG__#${CI_PROJECT_PATH_SLUG}#g" ${DEPLOY_FILE} 
  19.     - sed -i "s#__ingressdomain__#${ENV_URL}#g" ${DEPLOY_FILE} 
  20.     - cat ${DEPLOY_FILE} 
  21.     - "kubectl create secret docker-registry ${APP_NAME} \ 
  22.             --docker-server=${CI_REGISTRY} \ 
  23.             --docker-username=$CI_REGISTRY_USER \ 
  24.             --docker-password=${CI_REGISTRY_PASSWD} \ 
  25.             --docker-email=test@test.com -n ${NAMESPACE} || echo 'secrets already exists'" 
  26.     - kubectl apply -f ${DEPLOY_FILE} 
  27.   environment: 
  28.     name"${ENV_NAME}" 
  29.     url: "http://${ENV_NAME}.${CI_PROJECT_NAMESPACE}.${CI_PROJECT_NAME}.devops.com" 
  30.     on_stop: "${ROLL_NAME}" 
  31.    
  32. ## 回滚 
  33. .rollout_k8s: 
  34.   stage: deploy 
  35.   script: 
  36.     - rm -rf $HOME/.kube 
  37.     - kubectl config set-cluster my-cluster --server=${KUBE_URL} --certificate-authority="${KUBE_CA_PEM_FILE}" 
  38.     - kubectl config set-credentials admin --token=${KUBE_TOKEN} 
  39.     - kubectl rollout history deployment ${APP_NAME} -n ${NAMESPACE} 
  40.     - kubectl rollout undo deployment ${APP_NAME} -n ${NAMESPACE} 
  41.   environment: 
  42.     name"${ENV_NAME}" 
  43.     action: stop 

templates/pipeline.yml

  1. include: 
  2.   - project: 'cidevops/cidevops-newci-service' 
  3.     ref: master 
  4.     file: 'jobs/build.yml' 
  5.   - project: 'cidevops/cidevops-newci-service' 
  6.     ref: master 
  7.     file: 'jobs/test.yml' 
  8.   - project: 'cidevops/cidevops-newci-service' 
  9.     ref: master 
  10.     file: 'jobs/codeanalysis.yml' 
  11.   - project: 'cidevops/cidevops-newci-service' 
  12.     ref: master 
  13.     file: 'jobs/deploy.yml' 
  14.  
  15.  
  16.  
  17. variables: 
  18.   ## 全局配置 
  19.   GIT_CLONE_PATH: $CI_BUILDS_DIR/builds/$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME/$CI_PIPELINE_ID     
  20.   GIT_CHECKOUT: "false" 
  21.  
  22.   ## 依赖容器镜像 
  23.   BUILD_IMAGE: "maven:3.6.3-jdk-8" 
  24.   SONAR_IMAGE: "sonarsource/sonar-scanner-cli:latest" 
  25.    
  26.   ## 构建测试参数 
  27.   MAVEN_OPTS: "-Dmaven.repo.local=/home/gitlab-runner/ci-build-cache/maven " 
  28.   BUILD_SHELL: 'mvn clean package  -DskipTests  --settings=./settings.xml '  ##构建命令 
  29.   TEST_SHELL : 'mvn test  --settings=./settings.xml '                        ##测试命令 
  30.   JUNIT_REPORT_PATH: 'target/surefire-reports/TEST-*.xml'   ##单元测试报告 
  31.  
  32.   ## 代码扫描 
  33.   SONAR_PROJECT_LANG: "JAVA" 
  34.   SONAR_SOURCE_DIR : "src"  
  35.   SONAR_SERVER_URL: "http://192.168.1.200:30090"  
  36.   SONAR_SERVER_LOGIN: "ee2bcb37deeb6dfe3a07fe08fb529559b00c1b7b"  
  37.   SONAR_SCAN_ARGS: "-Dsonar.sources=${SONAR_SOURCE_DIR}  
  38.                    -Dsonar.java.binaries=target/classes  
  39.                    -Dsonar.java.test.binaries=target/test-classes  
  40.                    -Dsonar.java.surefire.report=target/surefire-reports " 
  41.  
  42.   #构建镜像 
  43.   CI_REGISTRY: 'registry.cn-beijing.aliyuncs.com' 
  44.   CI_REGISTRY_USER: 'xxxxxx' 
  45.   #CI_REGISTRY_PASSWD: 'xxxxxxxx.' 
  46.   IMAGE_NAME: "$CI_REGISTRY/$CI_PROJECT_PATH:$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA" 
  47.   DOCKER_FILE_PATH: "./Dockerfile" 
  48.  
  49.   #部署应用k8s 
  50.   RUN_DEPLOY: "yes" 
  51.   APP_NAME: "$CI_PROJECT_NAME" 
  52.   CONTAINER_PORT: 8081 
  53.   #NODE_PORT: 30185 
  54.   NAMESPACE: "$CI_PROJECT_NAME-$CI_PROJECT_ID-$CI_ENVIRONMENT_SLUG" 
  55.  
  56.  
  57. ## 流水线控制 
  58. workflow: 
  59.   rules: 
  60.     - if: $CI_MERGE_REQUEST_ID 
  61.     - if: $CI_PIPELINE_SOURCE == 'web' 
  62.     - if: $CI_COMMIT_BEFORE_SHA == "0000000000000000000000000000000000000000" 
  63.       when: never 
  64.  
  65.  
  66. ## 运行阶段   
  67. stages: 
  68.   - build 
  69.   - test 
  70.   - parallel01 
  71.   - get_analysis_result 
  72.   - deploy 
  73.   - rollout 
  74.  
  75.  
  76. cache: 
  77.   paths: 
  78.     - target/ 
  79.      
  80. before_script: 
  81.   - export 
  82.      
  83.      
  84. ################# Jobs Configure ##################### 
  85. ## 构建作业 
  86. build: 
  87.   variables: 
  88.     GIT_CHECKOUT: "true" 
  89.   image: ${BUILD_IMAGE} 
  90.   extends: .build 
  91.  
  92. ## 测试作业 
  93. test: 
  94.   image: ${BUILD_IMAGE} 
  95.   extends: .test 
  96.   before_script: 
  97.     - ls  
  98.     - ls target/ 
  99.  
  100. ## 代码扫描 
  101. code_analysis: 
  102.   stage: parallel01 
  103.   image: ${SONAR_IMAGE} 
  104.   extends: .code_analysis 
  105.  
  106. ## 获取构建结果 
  107. get_analysis_result: 
  108.   image: curlimages/curl:7.70.0 
  109.   extends: .get_analysis_result 
  110.   needs: 
  111.     - code_analysis 
  112.  
  113. ## 构建镜像 
  114. build_image: 
  115.   image: docker:latest 
  116.   services: 
  117.     - name: docker:dind 
  118.   stage: parallel01 
  119.   extends: .build-docker 
  120.  
  121. ## feature发布应用 
  122. deploy_feature: 
  123.   variables: 
  124.     DEPLOY_FILE: 'deployment.yaml' 
  125.     ENV_NAME: 'feature' 
  126.   stage: deploy 
  127.   image: lucj/kubectl:1.17.2 
  128.   extends: .deploy_k8s 
  129.   rules: 
  130.     - if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/  
  131.       when: never 
  132.     - if: $CI_COMMIT_REF_NAME =~ /\d-*/ 
  133.       when: manual 
  134.     - when: never 
  135.      
  136. ## 应用回滚 
  137. rollout_feature: 
  138.   stage: rollout 
  139.   image: lucj/kubectl:1.17.2 
  140.   extends: .rollout_k8s 
  141.   rules: 
  142.     - if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/  
  143.       when: never 
  144.     - if: $CI_COMMIT_REF_NAME =~ /\d-*/ 
  145.       when: manual 
  146.     - when: never 
  147.  
  148. ## UAT 
  149. deploy_uat: 
  150.   variables: 
  151.     DEPLOY_FILE: 'config/deployment-uat.yaml' 
  152.     ENV_NAME: 'uat' 
  153.   stage: deploy 
  154.   image: lucj/kubectl:1.17.2 
  155.   extends: .deploy_k8s 
  156.   rules: 
  157.     - if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/  
  158.       when: manual 
  159.     - when: never 
  160.  
  161. ## UAT应用回滚 
  162. rollout_uat: 
  163.   stage: rollout 
  164.   image: lucj/kubectl:1.17.2 
  165.   extends: .rollout_k8s 
  166.   rules: 
  167.     - if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/  
  168.       when: manual 
  169.     - when: never 
  170.  
  171. ## STAG 
  172. deploy_stag: 
  173.   variables: 
  174.     DEPLOY_FILE: 'config/deployment-stag.yaml' 
  175.     ENV_NAME: 'stag' 
  176.   stage: deploy 
  177.   image: lucj/kubectl:1.17.2 
  178.   extends: .deploy_k8s 
  179.   rules: 
  180.     - if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/  
  181.       when: manual 
  182.     - when: never 
  183.  
  184. ## STAG应用回滚 
  185. rollout_stag: 
  186.   stage: rollout 
  187.   image: lucj/kubectl:1.17.2 
  188.   extends: .rollout_k8s 
  189.   rules: 
  190.     - if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/  
  191.       when: manual 
  192.     - when: never 
  193.  
  194. ## PROD 
  195. deploy_prod: 
  196.   variables: 
  197.     DEPLOY_FILE: 'config/deployment-prod.yaml' 
  198.     ENV_NAME: 'prod' 
  199.   stage: deploy 
  200.   image: lucj/kubectl:1.17.2 
  201.   extends: .deploy_k8s 
  202.   rules: 
  203.     - if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/  
  204.       when: manual 
  205.     - when: never 
  206.  
  207. ## PROD应用回滚 
  208. rollout_prod: 
  209.   stage: rollout 
  210.   image: lucj/kubectl:1.17.2 
  211.   extends: .rollout_k8s 
  212.   rules: 
  213.     - if: $CI_COMMIT_REF_NAME =~ /^RELEASE-*/  
  214.       when: manual 
  215.     - when: never 

7.发布完成后

1.将版本分支合并到master分支

2.基于master分支创建版本标签

3.关闭issues 和里程碑

 

 

责任编辑:姜华 来源: DevOps云学堂
相关推荐

2020-10-25 11:28:12

开源端到端流水线

2022-07-18 06:05:28

Gitlab流水线

2017-02-28 15:40:30

Docker流水线Azure

2017-02-28 16:00:45

DevOpsMarkdownreST

2023-08-18 10:24:52

GitLabCI 流水线

2024-01-07 12:47:35

Golang流水线设计模式

2017-03-02 14:12:13

流水线代码Clojure

2021-12-24 08:02:48

GitLabCI模板库流水线优化

2024-11-04 12:38:52

2023-12-11 18:35:37

测试流水线自动化

2023-05-10 15:08:00

Pipeline设计模式

2023-05-26 08:31:09

2019-11-07 10:02:33

开源开源工具DevOps

2013-06-06 09:31:52

2021-11-08 07:41:16

Go流水线编程

2022-01-26 08:12:42

Jenkins开源流水线

2021-06-26 14:22:34

Tekton流水线Kubernetes

2020-09-28 09:12:22

DevOps

2021-06-28 06:32:46

Tekton Kubernetes Clone

2023-05-09 10:48:21

AppStackZadig
点赞
收藏

51CTO技术栈公众号