GitLab CI/CD
GitLab CI/CD 是 GitLab 内置的持续集成和持续交付功能,通过 .gitlab-ci.yml 文件定义流水线,支持 Docker、Kubernetes、云原生构建和部署。
核心概念
| 概念 |
说明 |
| Pipeline |
完整的 CI/CD 流水线,包含多个 Stage |
| Stage |
阶段,多个 Job 可以在同一阶段并行执行 |
| Job |
具体任务,如编译、测试、部署 |
| Runner |
执行 Job 的代理,支持共享和专用 |
| Artifact |
构建产物,在 Job 之间传递 |
| Cache |
缓存,用于加速重复构建 |
| Environment |
环境,追踪部署历史 |
基础配置
.gitlab-ci.yml 基础结构
stages:
- build
- test
- deploy
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
before_script:
- echo "Before script"
after_script:
- echo "After script"
build:
stage: build
image: maven:3.9-eclipse-temurin-17
script:
- mvn clean package -DskipTests
artifacts:
paths:
- target/*.jar
expire_in: 1 hour
tags:
- docker
test:unit:
stage: test
image: maven:3.9-eclipse-temurin-17
script:
- mvn test
coverage: '/Total:.*?([0-9]{1,3})%/'
artifacts:
reports:
junit: target/surefire-reports/*.xml
paths:
- target/surefire-reports/
expire_in: 1 day
tags:
- docker
test:integration:
stage: test
image: maven:3.9-eclipse-temurin-17
services:
- postgres:15
- redis:7
script:
- mvn verify -Pintegration-tests
tags:
- docker
deploy:staging:
stage: deploy
only:
- main
environment:
name: staging
url: https://staging.example.com
on_stop: stop:staging
script:
- kubectl config use-context staging
- kubectl apply -f k8s/staging/
tags:
- kubernetes
stop:staging:
stage: deploy
environment:
name: staging
action: stop
script:
- kubectl config use-context staging
- kubectl delete -f k8s/staging/
tags:
- kubernetes
when: manual
Docker 镜像构建
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
build:docker:
stage: build
image: docker:24-dind
services:
- docker:24-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
after_script:
- docker logout $CI_REGISTRY
tags:
- docker
artifacts:
reports:
trivy: trivy-report.json
only:
- main
- tags
多分支策略
stages:
- build
- test
- deploy
# MR 合并请求流水线
merge_request:
stage: build
image: node:20-alpine
script:
- npm ci
- npm run build
- npm run test
only:
- merge_requests
rules:
- if: $CI_MERGE_REQUEST_ID
# 主分支生产部署
deploy:production:
stage: deploy
script:
- echo "Deploying to production"
environment:
name: production
url: https://example.com
only:
- main
when: manual
rules:
- if: $CI_COMMIT_BRANCH == "main"
# 标签发布
release:
stage: release
image: ubuntu:22.04
before_script:
- apt-get update && apt-get install -y curl
script:
- |
curl --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--data "tag_name=$CI_COMMIT_TAG" \
--data "description=Release $CI_COMMIT_TAG" \
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/releases"
only:
- tags
rules:
- if: $CI_COMMIT_TAG
Kubernetes 部署
deploy:kubernetes:
stage: deploy
image: bitnami/kubectl:latest
services:
- docker:24-dind
before_script:
- kubectl config use-context $KUBECTL_CONTEXT
- echo $KUBE_CERT | base64 -d > /tmp/ca.crt
script:
- kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- kubectl rollout status deployment/myapp
environment:
name: production
url: https://myapp.example.com
kubernetes:
namespace: production
only:
- main
rules:
- if: $CI_COMMIT_BRANCH == "main"
依赖缓存
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .m2/repository
- node_modules/
- .npm/
maven:build:
stage: build
image: maven:3.9-eclipse-temurin-17
cache:
key: maven-${CI_COMMIT_REF_SLUG}
paths:
- .m2/repository
policy: pull-push
script:
- mvn clean package
npm:build:
stage: build
image: node:20-alpine
script:
- npm ci
- npm run build
cache:
key: npm-${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
policy: pull-push
Matrix Jobs(矩阵构建)
build:matrix:
stage: build
image: docker:24-dind
services:
- docker:24-dind
parallel:
matrix:
- SERVICE: api
VERSION: v1
- SERVICE: api
VERSION: v2
- SERVICE: web
VERSION: v1
- SERVICE: web
VERSION: v2
script:
- docker build -t myapp/${SERVICE}:${VERSION} .
- docker push myapp/${SERVICE}:${VERSION}
GitLab Runner 配置
Docker Executor
[[runners]]
name = "docker-runner"
url = "https://gitlab.example.com"
token = "<runner-token>"
executor = "docker"
[runners.cache]
MaxUploadedArchiveSize = 104857600
[runners.docker]
tls_verify = false
image = "docker:24-dind"
privileged = true
disable_cache = false
volumes = ["/cache", "/certs/client"]
shm_size = 0
Kubernetes Executor
# gitlab-runner-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: gitlab-runner-config
data:
config.toml: |
[[runners]]
name = "kubernetes-runner"
url = "https://gitlab.example.com"
token = "<runner-token>"
executor = "kubernetes"
[runners.kubernetes]
namespace = "gitlab-ci"
image = "ubuntu:22.04"
privileged = false
cpu_limit = "2"
memory_limit = "4Gi"
cpu_request = "1"
memory_request = "2Gi"
service_cpu_limit = "1"
service_memory_limit = "1Gi"
helper_cpu_limit = "500m"
helper_memory_limit = "256Mi"
[runners.kubernetes.pull_policy]
policy = "if-not-present"
高级特性
DAG 调度(跳过 Stage)
stages:
- build
- test
- deploy
# 使用 needs 跳过空 Stage,实现 DAG 调度
build:
stage: build
script: make build
test:unit:
stage: test
needs: [build]
script: make test:unit
test:integration:
stage: test
needs: [build]
script: make test:integration
deploy:
stage: deploy
needs: [test:unit, test:integration]
script: make deploy
父子流水线
# .gitlab-ci.yml(父流水线)
trigger:child:
stage: build
trigger:
include:
- local: pipelines/child-pipeline.yml
strategy: depend
CI/CD Variable 权限级别
| 变量类型 |
说明 |
用途示例 |
| Unprotected |
无分支限制 |
Docker Registry |
| Protected |
仅保护分支可用 |
生产环境密钥 |
| Masked |
输出中隐藏值 |
密码、Token |
故障排除
# 本地调试流水线
gitlab-runner exec docker --docker-privileged build
# 查看 Runner 日志
sudo journalctl -u gitlab-runner -f
# 重新注册 Runner
gitlab-runner register \
--url https://gitlab.example.com \
--token <token> \
--description "docker-runner" \
--executor docker \
--docker-image "docker:24-dind"
最佳实践
- 流水线模块化:使用
include 引用共享 CI 配置
- 构建缓存:充分利用 Maven/npm 本地仓库加速构建
- 并行执行:使用
parallel:matrix 或 needs 实现并行
- 产物清理:设置合理的
expire_in,避免存储浪费
- Secret 管理:使用 GitLab CI/CD Variable,不在代码中硬编码
下一步