GitLab教程(6): CI/CD基础与.gitlab-ci.yml入门

GitLab CI/CD是GitLab内置的持续集成和持续部署功能。本文将介绍CI/CD的基本概念和.gitlab-ci.yml配置文件的编写方法。

什么是GitLab CI/CD

# CI/CD流程

代码提交 → 自动构建 → 自动测试 → 自动部署
   ↓          ↓          ↓          ↓
  push     compile     test      deploy
            ↓          ↓          ↓
         artifacts   reports   environment

# 核心概念
- Pipeline: 流水线,一次完整的CI/CD过程
- Stage: 阶段,流水线中的步骤
- Job: 作业,具体执行的任务
- Runner: 执行器,运行Job的代理
- Artifact: 产物,Job生成的文件

# 触发方式
- Push到分支
- 合并请求
- 定时计划
- API触发
- 手动触发

第一个Pipeline

# 在项目根目录创建 .gitlab-ci.yml

# 最简单的例子
stages:
  - build
  - test
  - deploy

build-job:
  stage: build
  script:
    - echo "Building the application..."
    - echo "Build complete!"

test-job:
  stage: test
  script:
    - echo "Running tests..."
    - echo "All tests passed!"

deploy-job:
  stage: deploy
  script:
    - echo "Deploying application..."
    - echo "Deployment complete!"

# 提交并推送
git add .gitlab-ci.yml
git commit -m "Add CI/CD configuration"
git push origin main

# 查看Pipeline
# Project > CI/CD > Pipelines

# Pipeline输出示例
Pipeline #1 passed
├── build-job ✓ (10s)
│   Running with gitlab-runner 16.8.0
│   $ echo "Building the application..."
│   Building the application...
│   $ echo "Build complete!"
│   Build complete!
│   Job succeeded
├── test-job ✓ (8s)
└── deploy-job ✓ (5s)

.gitlab-ci.yml基本结构

# 完整的配置示例

# 定义阶段(按顺序执行)
stages:
  - build
  - test
  - deploy

# 全局变量
variables:
  APP_NAME: "my-app"
  NODE_VERSION: "18"

# 全局默认值
default:
  image: node:18-alpine
  before_script:
    - echo "Starting job..."
  after_script:
    - echo "Job finished."

# 构建作业
build:
  stage: build
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 hour

# 测试作业
test:
  stage: test
  script:
    - npm run test
  coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'

# 部署作业
deploy:
  stage: deploy
  script:
    - echo "Deploying $APP_NAME"
  environment:
    name: production
    url: https://example.com
  only:
    - main

Job关键字详解

script - 执行命令

# script是唯一必需的关键字

job-name:
  script:
    - echo "Single command"
    - |
      echo "Multi-line"
      echo "commands"
      if [ -f "file.txt" ]; then
        cat file.txt
      fi
    - npm install
    - npm run build

# before_script - script之前执行
build:
  before_script:
    - npm ci
  script:
    - npm run build

# after_script - 无论成功失败都执行
test:
  script:
    - npm run test
  after_script:
    - echo "Cleanup..."
    - rm -rf temp/

image - Docker镜像

# 指定运行环境

# 全局镜像
image: node:18

jobs:
  build:
    script:
      - node --version

# Job级别覆盖
build-java:
  image: maven:3.8-openjdk-17
  script:
    - mvn clean package

build-python:
  image: python:3.11
  script:
    - pip install -r requirements.txt
    - python setup.py build

build-go:
  image: golang:1.21
  script:
    - go build ./...

# 使用私有镜像
build:
  image:
    name: registry.example.com/my-image:latest
    entrypoint: [""]  # 覆盖默认入口点
  script:
    - my-command

variables - 变量

# 全局变量
variables:
  GLOBAL_VAR: "global value"
  DATABASE_URL: "postgres://localhost/mydb"

# Job级别变量
build:
  variables:
    BUILD_ENV: "production"
  script:
    - echo $GLOBAL_VAR
    - echo $BUILD_ENV

# 预定义变量(自动可用)
job:
  script:
    - echo $CI_COMMIT_SHA          # 提交SHA
    - echo $CI_COMMIT_BRANCH       # 分支名
    - echo $CI_COMMIT_REF_NAME     # 引用名
    - echo $CI_PIPELINE_ID         # Pipeline ID
    - echo $CI_JOB_ID              # Job ID
    - echo $CI_PROJECT_NAME        # 项目名
    - echo $CI_PROJECT_PATH        # 项目路径
    - echo $CI_REGISTRY_IMAGE      # 镜像仓库地址
    - echo $GITLAB_USER_EMAIL      # 用户邮箱

# 敏感变量(在Settings > CI/CD > Variables设置)
# 不要在.gitlab-ci.yml中硬编码密码!
deploy:
  script:
    - echo $DEPLOY_PASSWORD  # 从CI/CD变量获取

artifacts - 构建产物

# 保存构建产物供后续Job使用

build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
      - node_modules/
    expire_in: 1 week
    name: "build-$CI_COMMIT_SHA"

test:
  stage: test
  script:
    - npm run test
  artifacts:
    reports:
      junit: test-results.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura.xml
    when: always  # 即使失败也保存

# 下载artifacts
# Job页面 > Download按钮
# 或后续Job自动获取

deploy:
  stage: deploy
  script:
    - ls dist/  # 自动从build job获取
    - ./deploy.sh

cache - 缓存

# 缓存依赖加速构建

# Node.js项目缓存
build:
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run build

# 基于文件的缓存key
build:
  cache:
    key:
      files:
        - package-lock.json
    paths:
      - node_modules/
  script:
    - npm ci

# Maven项目缓存
build-java:
  cache:
    key: maven-cache
    paths:
      - .m2/repository/
  variables:
    MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
  script:
    - mvn clean package

# Python项目缓存
build-python:
  cache:
    key: pip-cache
    paths:
      - .cache/pip/
  variables:
    PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
  script:
    - pip install -r requirements.txt

控制Job执行

only/except - 条件执行

# 只在特定分支执行
deploy-prod:
  script:
    - ./deploy.sh production
  only:
    - main
    - master

# 排除分支
test:
  script:
    - npm run test
  except:
    - schedules  # 不在定时任务时运行

# 标签触发
release:
  script:
    - ./release.sh
  only:
    - tags

# 合并请求触发
review:
  script:
    - ./deploy-review.sh
  only:
    - merge_requests

rules - 高级条件(推荐)

# rules比only/except更灵活

deploy-prod:
  script:
    - ./deploy.sh production
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual  # 手动触发
    - if: $CI_COMMIT_TAG
      when: on_success  # 自动执行

test:
  script:
    - npm run test
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"
    - if: $CI_COMMIT_BRANCH == "develop"

# 文件变更触发
frontend-test:
  script:
    - npm run test:frontend
  rules:
    - changes:
        - src/frontend/**/*
        - package.json

backend-test:
  script:
    - mvn test
  rules:
    - changes:
        - src/main/**/*
        - pom.xml

# 组合条件
deploy:
  rules:
    - if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push"
      when: manual
      allow_failure: false

when - 执行时机

# when选项
# on_success: 前面的job都成功时执行(默认)
# on_failure: 前面的job失败时执行
# always: 总是执行
# manual: 手动触发
# delayed: 延迟执行
# never: 不执行

deploy-prod:
  stage: deploy
  script:
    - ./deploy.sh
  when: manual  # 需要手动点击触发

notify-failure:
  stage: notify
  script:
    - ./send-alert.sh
  when: on_failure  # 只在失败时执行

cleanup:
  stage: cleanup
  script:
    - ./cleanup.sh
  when: always  # 无论成功失败都执行

delayed-job:
  script:
    - echo "Delayed execution"
  when: delayed
  start_in: 30 minutes

验证配置

# 使用CI Lint验证配置
# Project > CI/CD > Editor > Validate

# 或访问
# https://gitlab.example.com/project/-/ci/lint

# 粘贴配置内容,点击"Validate"

# 验证结果示例
Status: syntax is correct

Jobs:
- build
- test
- deploy

# 错误示例
Status: syntax is incorrect
Error: jobs:build:script config should be a string or a nested array of strings

实际项目示例

# Node.js项目完整示例

stages:
  - install
  - build
  - test
  - deploy

variables:
  NODE_ENV: production

default:
  image: node:18-alpine
  cache:
    key:
      files:
        - package-lock.json
    paths:
      - node_modules/

install:
  stage: install
  script:
    - npm ci
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week

lint:
  stage: test
  script:
    - npm run lint

test:
  stage: test
  script:
    - npm run test:coverage
  coverage: '/Statements\s*:\s*(\d+\.?\d*)%/'
  artifacts:
    reports:
      junit: junit.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura.xml

deploy-staging:
  stage: deploy
  script:
    - npm run deploy:staging
  environment:
    name: staging
    url: https://staging.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"

deploy-production:
  stage: deploy
  script:
    - npm run deploy:production
  environment:
    name: production
    url: https://example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual

总结

本文介绍了GitLab CI/CD的基础知识和.gitlab-ci.yml的常用配置。掌握这些概念后,你可以为项目配置自动化的构建、测试和部署流程。

下一篇我们将学习GitLab Runner的安装和配置。

发表回复

后才能评论