GitLab CI/CD 完全指南

View source
一份涵盖从入门、配置到问题排查的完整 CI/CD 实践文档,实现快速上手并高效利用自动化流水线。

参考文档

GitLab CI/CD: 使用 CI/CD 构建您的应用程序
企业微信机器人: 消息推送配置说明

核心流程

项目的流水线被划分为多个阶段 (Stages),确保任务按预定顺序执行,完整流程如下:

notify_start -> lint -> sonar -> build -> deploy -> notify_end

  • lint & sonar: 在合并请求 (Merge Request) 场景下运行,进行代码规范检查和静态质量分析,保障代码质量。
  • build & deploy: 在推送到 devmaster 分支,或手动触发时执行,完成应用的构建和部署。

配置详解

CI/CD 文件结构

.
├── .gitlab-ci.yml       # 主配置文件,定义 stages, workflow, variables, include 规则
├── .gitlab-dev.yml      # dev 环境的作业 (build, deploy, notify)
├── .gitlab-prod.yml     # prod 环境的作业 (build, notify)
└── scripts/
    └── ci/
        ├── package-zip.sh     # 打包构建产物为 .zip 并生成环境变量
        ├── deploy-zip.sh      # 部署 .zip 包到目标服务器
        └── wechat-notify.js   # 发送企业微信通知
.gitlab-ci.yml
# 全局规则:只在指定分支或合并到指定分支的请求中运行
workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: always
    - if: $CI_PIPELINE_SOURCE == "push" && ($CI_COMMIT_BRANCH == "dev" || $CI_COMMIT_BRANCH == "master")
      when: always
    - if: $CI_PIPELINE_SOURCE == "web"
      when: always
    - when: never

# 定义流水线的阶段
stages:
  - notify_start
  - lint
  - sonar
  - build
  - deploy
  - notify_end

# 定义变量
variables:
  NODE_VERSION: lts
  PNPM_VERSION: latest
  GIT_DEPTH: 0
  GIT_STRATEGY: clone
  BUILD_ENV:
    value: dev
    options:
      - dev
      - prod
    description: 选择构建环境(dev/prod)
  SONAR_HOST_URL: # SonarQube 主机地址(自定义)
    value: 'http://10.0.0.100:9000'
    description: SonarQube主机地址
  WECHAT_WEBHOOK_URL: # 企业微信webhook地址,用于通知(自定义)
    value: 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-webhook-key-here'
    description: 企业微信webhook地址
  BUILD_DIR: # 构建目录(自定义)
    value: app-gen/dist/web/your-app-name
    description: 构建目录
  DEPLOY_HOST: # 测试部署主机(一般固定,无需修改)
    value: 10.0.0.100
    description: 测试部署主机
  DEPLOY_DIR: # 测试部署目录(自定义)
    value: /home/user/nginx/html/
    description: 测试部署目录

default:
  image: node:${NODE_VERSION}
  tags:
    - sonarqube

include:
  - local: .gitlab-dev.yml
    rules:
      - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "dev"
      - if: $CI_PIPELINE_SOURCE == "web" && $BUILD_ENV == "dev"
  - local: .gitlab-prod.yml
    rules:
      - if: $CI_PIPELINE_SOURCE == "web" && $BUILD_ENV == "prod"

# 代码检查作业
lint:
  stage: lint
  script:
    - npm install -g pnpm@${PNPM_VERSION}
    - pnpm install --frozen-lockfile
    - pnpm eslint 'app/**/*.{ts,tsx,vue}'
  artifacts:
    when: always
    reports:
      junit: .eslintcache
    paths:
      - .eslintcache
    expire_in: 1 week
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  allow_failure: true

# SonarQube 代码分析
sonarqube-check:
  stage: sonar
  image: openjdk:11-jre-slim
  variables:
    SONAR_PROJECT_KEY: ${CI_PROJECT_ID}
    SONAR_PROJECT_NAME: ${CI_PROJECT_TITLE}
    SONAR_PROJECT_VERSION: ${CI_COMMIT_SHORT_SHA}
    SONAR_USER_HOME: '${CI_PROJECT_DIR}/.sonar'
    SONAR_SCANNER_VERSION: 4.6.2.2472
  cache:
    key: 'sonarqube-${SONAR_SCANNER_VERSION}'
    paths:
      - .sonar/cache
      - sonar-scanner/
  before_script:
    - echo "准备 SonarScanner CLI ${SONAR_SCANNER_VERSION}..."
    - |
      if [ ! -d "sonar-scanner" ]; then
        echo "下载并安装 SonarScanner CLI..."
        apt-get update && apt-get install -y wget unzip
        wget -O sonar-scanner.zip "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_SCANNER_VERSION}-linux.zip"
        unzip sonar-scanner.zip
        mv sonar-scanner-${SONAR_SCANNER_VERSION}-linux sonar-scanner
      else
        echo "使用缓存的 SonarScanner CLI..."
      fi
    - export PATH="$PWD/sonar-scanner/bin:$PATH"
  script:
    - echo "运行测试并生成覆盖率报告..."
    - export PATH="$PWD/sonar-scanner/bin:$PATH"
    - |
      sonar-scanner \
        -Dsonar.projectKey=${SONAR_PROJECT_KEY} \
        -Dsonar.projectName="${SONAR_PROJECT_NAME}" \
        -Dsonar.projectVersion=${SONAR_PROJECT_VERSION} \
        -Dsonar.host.url=${SONAR_HOST_URL} \
        -Dsonar.login=${SONAR_TOKEN}
  allow_failure: true
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

# 流水线开始通知
notify-start:
  stage: notify_start
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    - node scripts/ci/wechat-notify.js --label "${CI_MERGE_REQUEST_TITLE}" --type CI-start
  when: on_success

# 流水线结束通知成功
notify-end-success:
  stage: notify_end
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    - node scripts/ci/wechat-notify.js --label "${CI_MERGE_REQUEST_TITLE}" --type CI-end --success
  when: on_success

# 流水线结束通知失败
notify-end-failed:
  stage: notify_end
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    - node scripts/ci/wechat-notify.js --label "${CI_MERGE_REQUEST_TITLE}" --type CI-end --failed
  when: on_failure
为了隔离不同环境的构建逻辑,采用了多脚本和动态配置的策略。
  • 构建脚本分离: package.json 中定义了两个构建脚本:
    • build: 用于 prod 环境,执行生产环境的完整构建。
    • build:dev: 用于 dev 环境,执行测试环境的特定构建。
  • 动态加载配置: .gitlab-ci.yml 会根据 $BUILD_ENV 变量的值,通过 include 规则动态加载 .gitlab-dev.yml.gitlab-prod.yml,从而执行对应环境的作业。

全局环境变量

变量名用途
BUILD_ENV控制构建环境 (dev/prod),流水线自动或手动选择
BUILD_DIR指定构建产物的输出目录,根据项目调整
SONAR_HOST_URLSonarQube 服务器地址
WECHAT_WEBHOOK_URL企业微信 WebHook地址,用于通知
DEPLOY_HOST部署目标服务器 IP 地址
DEPLOY_DIR部署到服务器上的目标目录
BUILD_DIR 等变量需要根据不同项目进行修改,请确保其指向正确的构建产物目录。

企业微信通知

流水线的关键节点会通过企业微信机器人发送实时通知。

  • 通知脚本: scripts/ci/wechat-notify.js 负责组装消息内容并发送。
  • @ 成员: 在消息中可以使用 <@userid> 的语法来提及指定成员,请确保填入的是成员的账号 (userid),而不是手机号或姓名。

手动执行流水线

除了自动化触发,你也可以手动运行流水线,并指定构建环境或者其他定义的全局变量。

  1. 进入项目的 构建 -> 流水线 页面。
  2. 点击 运行流水线 按钮。
  3. 选择对应分支,在 变量 区域,BUILD_ENV 变量会提供一个下拉框,你可以选择 devprod 环境。

常见问题 (FAQ)

Copyright © 2024 - 2025 YiXuan - MIT License