GitLab_ .gitlab-ci.yml完全配置指南

2 阅读6分钟

📋 GitLab CI/CD .gitlab-ci.yml 指南

作用:定义自动化流水线的"剧本"——什么时候构建、用什么环境构建、构建完怎么部署。

阅读提示:本文档为"傻瓜式"教程,看完就能独立写出适合自己项目的 CI 配置。


📑 目录


一、.gitlab-ci.yml 是什么

简单理解:它是告诉 GitLab "代码推送后自动做什么" 的说明书。

比如:

  • 推代码 → 自动编译 Java → 自动打包 Vue → 自动部署到服务器
  • 推代码 → 跑单元测试 → 测试通过才部署
  • 推代码 → 构建 Docker 镜像 → 推送到镜像仓库

所有这些步骤,都写在 .gitlab-ci.yml 里。


二、文件放哪里

必须放在 Git 仓库的根目录,文件名必须.gitlab-ci.yml(注意前面有个点)。

my-project/                    ← 项目根目录
├── .gitlab-ci.yml             ← 放这里!
├── backend/
├── frontend/
└── README.md

⚠️ 文件名写错(如 gitlab-ci.yml 少了点)、放错位置(如放在 backend/ 里),流水线都不会触发。


三、基础结构速览

stages:           # ← 定义阶段顺序
  - build
  - test
  - deploy

build_job:        # ← Job 名字,随便取
  stage: build    # ← 属于哪个阶段
  tags:           # ← 用哪个 Runner 执行
    - docker
  image: node:20  # ← 用什么 Docker 镜像
  script:         # ← 真正执行的命令
    - echo "开始构建"
    - npm install
    - npm run build

一次推送后,GitLab 会按这个顺序执行

build 阶段的所有 Job(并行)
    ↓
test 阶段的所有 Job(并行)
    ↓
deploy 阶段的所有 Job(并行)

四、核心字段详解

4.1 stages — 定义流水线阶段

stages:
  - build-backend
  - build-frontend
  - test
  - deploy
说明示例
阶段名随便取buildtestdeploypackage
同一阶段的 Job 并行执行build-backendbuild-frontend 同时跑
不同阶段 串行执行必须等 build 阶段全部完成,test 才开始

💡 技巧:把耗时的操作放在前面并行执行,比如前后端同时构建。


4.2 variables — 全局变量

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
  NODE_ENV: "production"
  DEPLOY_PATH: "/var/www/frontend"
  API_BASE: "/api"

在 script 里引用

script:
  - echo $NODE_ENV              # 输出 production
  - echo ${DEPLOY_PATH}         # 输出 /var/www/frontend
  - mvn package $MAVEN_OPTS     # 等价于 mvn package -Dmaven.repo.local=.m2/repository
变量类型说明
全局变量写在最上面,所有 Job 都能用
Job 变量写在某个 Job 里,只有该 Job 能用
build_job:
  variables:
    MY_VAR: "only_for_this_job"   # ← 只有 build_job 能用
  script:
    - echo $MY_VAR

4.3 tags — 指定 Runner(关键!)

build_job:
  tags:
    - docker        # ← 只有标签含 docker 的 Runner 会执行

为什么重要?

你的服务器可能有多个 Runner:

  • docker-runner:在 Docker 容器里跑构建(安全隔离)
  • shell-runner:直接在宿主机上跑部署(能操作本地文件)

通过 tags 告诉 GitLab:这个 Job 必须由谁执行

场景tags 设置
Maven 编译 Javatags: [docker]
npm 构建 Vuetags: [docker]
复制文件到 Nginx 目录tags: [shell]
执行 systemctl 重启服务tags: [shell]

⚠️ 如果 tags 不匹配,Job 会永远 pending(橙色),不会执行。


4.4 image — Docker 镜像(仅 Docker Executor)

build_job:
  image: maven:3.9-eclipse-temurin-21-alpine

作用:告诉 Docker Runner,启动一个什么环境的容器来执行命令。

技术栈推荐镜像
Java + Mavenmaven:3.9-eclipse-temurin-21-alpine
Java + Gradlegradle:8.5-jdk21-alpine
Vue/Reactnode:20-alpine
Pythonpython:3.11-alpine
Gogolang:1.22-alpine
.NETmcr.microsoft.com/dotnet/sdk:8.0

💡 带 alpine 的版本体积小(约 5MB 基础),拉取快,省时间。


4.5 script — 执行命令列表

script:
  - echo "开始构建"
  - cd backend
  - mvn clean package -DskipTests
  - ls -la target/

每行是一个独立的 shell 命令,按顺序执行。如果某一行报错,后面的命令不会执行。

多行脚本写法(更整洁):

script:
  - |
    echo "======== 开始构建 ========"
    cd backend
    mvn clean package -DskipTests
    echo "======== 构建完成 ========"

条件判断

script:
  - |
    if [ "$CI_COMMIT_BRANCH" = "main" ]; then
      echo "部署到生产环境"
    else
      echo "部署到测试环境"
    fi

4.6 artifacts — 产物传递(跨 Job 共享文件)

build_job:
  script:
    - mvn package
  artifacts:
    paths:
      - backend/target/*.jar     # ← 把 jar 包保存下来
    expire_in: 1 week             # ← 1 周后自动删除

为什么需要 artifacts?

build_job 在 Docker 容器里编译出 jar 包,容器一销毁文件就没了。deploy_job 需要这个 jar 包才能部署。

artifacts 的作用:把文件"暂存"起来,让后面的 Job 能下载使用。

传递多个文件

artifacts:
  paths:
    - backend/target/*.jar
    - frontend/dist/
    - report/coverage.html
  expire_in: 3 days

💡 artifacts vs cache 区别

  • artifacts:同一条流水线的不同 Job 之间传递文件(如 build → deploy)
  • cache:跨流水线复用文件(如下次构建直接用上次下载的依赖)

4.7 cache — 缓存加速

build_job:
  cache:
    paths:
      - backend/.m2/repository    # ← Maven 依赖缓存
      - frontend/node_modules/   # ← npm 依赖缓存
    key: "$CI_COMMIT_REF_SLUG"    # ← 按分支隔离缓存

作用:避免每次构建都重新下载依赖,节省大量时间。

不同 Job 用不同缓存(避免冲突):

# 后端 Job
cache:
  paths:
    - backend/.m2/repository/
  key: "mvn-$CI_COMMIT_REF_SLUG"

# 前端 Job
cache:
  paths:
    - frontend/node_modules/
  key: "npm-$CI_COMMIT_REF_SLUG"

4.8 dependencies — 指定依赖哪个 Job 的产物

deploy_job:
  dependencies:
    - build-backend    # ← 只拿 build-backend 的 artifacts

作用:控制 deploy_job 下载哪些 artifacts。如果不写,默认下载前面所有 Job 的 artifacts。

不下载任何产物(适合纯脚本 Job):

deploy_job:
  dependencies: []     # ← 空数组,不下载任何文件

4.9 only / except / rules — 触发条件

旧写法:only / except(不推荐新项目用)
deploy_job:
  only:
    - main          # ← 只有推送到 main 分支才触发
  except:
    - develop       # ← develop 分支不触发
新写法:rules(功能更强,推荐)
deploy_job:
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'       # main 分支才部署
      when: always
    - if: '$CI_COMMIT_BRANCH == "develop"'     # develop 分支只构建不部署
      when: never
    - when: manual                               # 其他分支手动触发
when含义
on_success前面阶段成功才执行(默认)
on_failure前面阶段失败才执行(用于报错通知)
always无论成败都执行(用于清理)
manual手动触发(用于部署到生产环境)
delayed延迟执行(如延迟 30 分钟部署)

生产环境手动审批示例

deploy-prod:
  stage: deploy
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual          # ← 必须人工点击"执行"按钮
  script:
    - echo "✅ 生产环境已确认上线!"

4.10 when — 执行时机

deploy_job:
  stage: deploy
  when: manual    # ← 需要手动点击才能执行

常用场景

场景when 值
自动部署到测试环境on_success
手动审批后部署到生产manual
构建失败时发送通知on_failure
无论成败都清理临时文件always

4.11 needs — 跳过阶段,直接依赖(DAG 流水线)

默认流水线是阶段顺序执行:

build → test → deploy

needs 可以让前后端并行部署,不用等对方:

deploy-backend:
  stage: deploy
  needs: [build-backend]      # ← 只要 build-backend 完成就开始
  dependencies: [build-backend]
  script:
    - echo "部署后端"

deploy-frontend:
  stage: deploy
  needs: [build-frontend]     # ← 只要 build-frontend 完成就开始
  dependencies: [build-frontend]
  script:
    - echo "部署前端"

效果:前后端构建完成后同时部署,不用等对方。


4.12 before_script / after_script — 公共脚本

build_job:
  before_script:
    - echo "======== 开始构建 ========"
    - pwd
  script:
    - mvn clean package
  after_script:
    - echo "======== 构建结束 ========"
    - du -sh target/
字段执行时机
before_scriptscript 之前自动执行
after_scriptscript 之后自动执行(即使 script 失败也会执行)

💡 适合放公共准备操作,比如打印时间、设置环境变量、清理临时文件。


4.13 environment — 环境配置(部署追踪)

deploy_job:
  stage: deploy
  environment:
    name: production
    url: http://172.19.90.78
  script:
    - echo "部署到生产环境"

效果

  • GitLab 网页会显示 "Deployed to production" 按钮
  • 点击按钮直接跳转到部署地址
  • 可以查看每次部署的历史记录

多环境配置

deploy-staging:
  environment:
    name: staging
    url: http://172.19.90.78:8080

deploy-prod:
  environment:
    name: production
    url: http://172.19.90.78

4.14 allow_failure — 允许失败

code_style_check:
  stage: test
  script:
    - eslint src/
  allow_failure: true    # ← 即使检查失败,流水线也继续执行

适用场景

  • 代码风格检查(eslint、prettier)
  • 非关键测试
  • 可选的安全扫描

⚠️ 如果 allow_failure: false(默认),Job 失败会导致整个流水线失败。


五、高级用法

5.1 矩阵构建(多版本并行测试)

unit-tests:
  parallel:
    matrix:
      - PROVIDER: [aws, gcp, azure]
        STACK: [monitoring, app, db]
  script:
    - echo "Testing $PROVIDER - $STACK"

效果:自动生成 3×3=9 个并行 Job,测试不同组合。


5.2 流水线触发器(一个项目触发另一个项目)

trigger-downstream:
  stage: deploy
  trigger:
    project: my-group/another-project
    branch: main

效果:当前项目部署成功后,自动触发另一个项目的流水线。


5.3 定时触发流水线

workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"

在 GitLab 网页 CI/CD → Schedules 中设置定时任务,比如每天凌晨 2 点自动跑测试。


六、实战配置模板

6.1 前后端分离项目(Java + Vue)

stages:
  - build-backend
  - build-frontend
  - deploy

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"

# ========== 构建 Java 后端 ==========
build-backend:
  stage: build-backend
  tags: [docker]
  image: maven:3.9-eclipse-temurin-21-alpine
  cache:
    paths: [backend/.m2/repository]
    key: "mvn-$CI_COMMIT_REF_SLUG"
  script:
    - cd backend
    - mvn clean package -DskipTests
    - ls -la target/
  artifacts:
    paths: [backend/target/*.jar]
    expire_in: 1 day

# ========== 构建 Vue 前端 ==========
build-frontend:
  stage: build-frontend
  tags: [docker]
  image: node:20-alpine
  cache:
    paths: [frontend/node_modules/]
    key: "npm-$CI_COMMIT_REF_SLUG"
  script:
    - cd frontend
    - npm install
    - npm run build
    - ls -la dist/
  artifacts:
    paths: [frontend/dist/]
    expire_in: 1 day

# ========== 部署后端 ==========
deploy-backend:
  stage: deploy
  tags: [shell]
  needs: [build-backend]
  dependencies: [build-backend]
  script:
    - sudo systemctl stop backend || true
    - cp backend/target/*.jar /opt/backend/app.jar
    - sudo systemctl start backend
    - sleep 5
    - sudo systemctl status backend

# ========== 部署前端 ==========
deploy-frontend:
  stage: deploy
  tags: [shell]
  needs: [build-frontend]
  dependencies: [build-frontend]
  script:
    - rm -rf /var/www/frontend/*
    - cp -r frontend/dist/* /var/www/frontend/
    - ls -la /var/www/frontend/

6.2 多环境部署(测试环境自动 + 生产环境手动)

stages:
  - build
  - deploy-staging
  - deploy-prod

build:
  stage: build
  tags: [docker]
  image: maven:3.9-eclipse-temurin-21-alpine
  script:
    - mvn clean package -DskipTests
  artifacts:
    paths: [target/*.jar]

# 测试环境:自动部署
deploy-staging:
  stage: deploy-staging
  tags: [shell]
  dependencies: [build]
  environment:
    name: staging
    url: http://172.19.90.78:8082
  rules:
    - if: '$CI_COMMIT_BRANCH == "develop"'
  script:
    - cp target/*.jar /opt/backend-staging/app.jar
    - sudo systemctl restart backend-staging

# 生产环境:手动审批
deploy-prod:
  stage: deploy-prod
  tags: [shell]
  dependencies: [build]
  environment:
    name: production
    url: http://172.19.90.78
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual          # ← 必须人工点击"执行"
  script:
    - cp target/*.jar /opt/backend/app.jar
    - sudo systemctl restart backend

6.3 构建 Docker 镜像并推送

stages:
  - build
  - dockerize

build:
  stage: build
  tags: [docker]
  image: maven:3.9-eclipse-temurin-21-alpine
  script:
    - mvn clean package -DskipTests
  artifacts:
    paths: [target/*.jar]

dockerize:
  stage: dockerize
  tags: [docker]
  image: docker:24
  services:
    - docker:24-dind        # ← Docker in Docker
  dependencies: [build]
  script:
    - cp target/*.jar app.jar
    - docker build -t myapp:$CI_COMMIT_SHA .
    - docker push myapp:$CI_COMMIT_SHA

七、内置变量大全

变量示例值说明
$CI_COMMIT_BRANCHmain当前分支名
$CI_COMMIT_TAGv1.0.0当前标签名
$CI_COMMIT_SHAa1b2c3d...当前 commit 完整哈希
$CI_COMMIT_SHORT_SHAa1b2c3d当前 commit 短哈希
$CI_PROJECT_NAMEmy-project项目名
$CI_PROJECT_ID42项目 ID
$CI_PIPELINE_ID123流水线 ID
$CI_JOB_NAMEbuild_job当前 Job 名
$CI_JOB_STAGEbuild当前阶段名
$CI_REGISTRY172.19.90.78:8080GitLab 镜像仓库地址
$CI_REGISTRY_USERgitlab-ci-token镜像仓库用户名
$CI_REGISTRY_PASSWORDxxx镜像仓库密码

使用示例

script:
  - echo "当前分支是 $CI_COMMIT_BRANCH"
  - echo "Commit ID 是 $CI_COMMIT_SHA"
  - docker build -t myapp:$CI_COMMIT_SHORT_SHA .

八、常见错误排查

❌ 1. 流水线没触发

检查

  1. 文件名是否正确?必须是 .gitlab-ci.yml(前面有点)
  2. 文件是否在仓库根目录?
  3. 是否推送到 GitLab?本地修改不触发,必须 git push

❌ 2. Job 一直 pending(橙色)

原因:没有匹配的 Runner。

排查

  1. tags 是否和 Runner 标签一致?
  2. Runner 是否在线?GitLab 网页 Settings → CI/CD → Runners 查看
  3. Runner 是否分配给当前项目?

❌ 3. script config should be a string or a nested array

原因:YAML 格式错误,通常是缩进问题。

解决

  • 确保用空格缩进,不要用 Tab
  • 冒号后面必须有空格:stage: build
  • 列表项前面是横杠 + 空格- echo "hello"

❌ 4. No such file or directory

原因:artifacts 没传递,或路径写错。

排查

  1. dependencies 是否写了?
  2. artifacts.paths 路径是否正确?
  3. 两个 Job 的 paths 是否匹配?
# build_job 输出到 backend/target/
artifacts:
  paths: [backend/target/*.jar]

# deploy_job 要从 backend/target/ 读取
dependencies: [build_job]
script:
  - ls backend/target/    # ← 路径要对

❌ 5. Permission denied

原因:Runner 用户没有文件操作权限。

解决

# 给目录赋权
sudo chown -R gitlab-runner:gitlab-runner /opt/backend
sudo chmod 755 /opt/backend

# 给 sudo 权限
sudo tee /etc/sudoers.d/gitlab-runner << 'EOF'
gitlab-runner ALL=(ALL) NOPASSWD: /bin/systemctl restart backend
EOF

❌ 6. 前端页面刷新 404

原因:Nginx 没有配置单页应用回退。

解决:Nginx 配置加上:

location / {
    try_files $uri $uri/ /index.html;
}

🎯 总结

字段作用必填
stages定义阶段顺序
script执行命令
tags指定 Runner否(但建议写)
imageDocker 镜像否(Docker Executor 需要)
artifacts传递产物
cache缓存依赖
dependencies依赖产物
rules触发条件
when执行时机
needs并行依赖
environment环境追踪

📅 文档生成时间:2026-08-18 📝 用途:GitLab CI/CD .gitlab-ci.yml 配置参考手册