GitLab-CI配置与优化
1. 基础结构
# .gitlab-ci.yml
stages:
- lint
- test
- build
- deploy
variables:
NODE_VERSION: "20"
default:
image: node:${NODE_VERSION}-alpine
cache:
key:
files: [package-lock.json]
paths: [node_modules/]
lint:
stage: lint
script:
- npm ci
- npm run lint
unit:
stage: test
script:
- npm ci
- npm run test -- --coverage
coverage: '/Lines\s*:\s*([0-9.]+)%/'
artifacts:
paths: [coverage/]
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
build:
stage: build
script:
- npm ci
- npm run build
artifacts:
paths: [dist/]
expire_in: 1 week
deploy:prod:
stage: deploy
only: [tags]
when: manual
environment:
name: production
url: https://app.example.com
script:
- ssh user@server "cd /var/www && rm -rf dist && tar xzf $CI_PROJECT_DIR/dist.tar.gz"
2. Stage 与 Job
- stage 串行
- 同 stage 内 jobs 并行
needs:跨 stage 依赖(DAG 模式,更灵活)
build:
stage: build
needs: [lint, unit] # 一旦 lint + unit 完成就跑(不等其他 stage)
3. 缓存
cache:
key:
files: [package-lock.json]
paths:
- node_modules/
- .npm/
policy: pull-push # pull / push / pull-push
pull 只读,push 只写。开发分支 pull-push,main 分支也 pull-push 才能持续更新。
4. Artifacts
artifacts:
paths: [dist/, coverage/]
expire_in: 1 week
reports:
junit: junit.xml
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
artifact 跨 job 传递。CI 完成后 GitLab UI 可下载。
5. 变量
5.1 内置
$CI_PROJECT_DIR:项目路径$CI_COMMIT_SHA:commit hash$CI_COMMIT_REF_NAME:分支 / tag$CI_PIPELINE_ID、$CI_JOB_ID$CI_ENVIRONMENT_NAME
5.2 自定义
Settings → CI/CD → Variables:
- File / Variable 两种类型
- Protected(仅 main / tags)
- Masked(日志掩码)
deploy:
script:
- echo "$DEPLOY_KEY" > ~/.ssh/deploy_key
- chmod 600 ~/.ssh/deploy_key
- ssh -i ~/.ssh/deploy_key user@server "..."
6. Runner
| 类型 | 说明 |
|---|---|
| Shared Runner | GitLab.com 提供,免费有限 |
| Group Runner | 组下项目共享 |
| Project Runner | 单项目独占 |
| Self-Hosted | 自部署 |
K8s 上跑 GitLab Runner:
helm install gitlab-runner gitlab/gitlab-runner \
--set runnerRegistrationToken=<token> \
--set rbac.create=true \
-n gitlab-runner
每个 job 一个 pod,隔离干净。
6.1 标签匹配
my-job:
tags: [docker, fast]
只有 tag 匹配的 runner 执行。
7. Environment 与审批
deploy:staging:
environment:
name: staging
url: https://staging.example.com
deployment_tier: staging
only: [main]
deploy:prod:
environment:
name: production
url: https://app.example.com
deployment_tier: production
when: manual
only: [tags]
Protected environment + 限制 only certain users 可触发。
8. Docker 镜像构建(Kaniko)
GitLab CI 里不推荐 docker-in-docker(要 privileged)。用 Kaniko:
build:image:
image:
name: gcr.io/kaniko-project/executor:v1.20.0-debug
entrypoint: [""]
script:
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor
--context $CI_PROJECT_DIR
--dockerfile $CI_PROJECT_DIR/Dockerfile
--destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
--destination $CI_REGISTRY_IMAGE:latest
--cache=true
9. 部署到 K8s
deploy:k8s:
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/frontend web=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -n frontend
- kubectl rollout status deployment/frontend -n frontend --timeout=300s
environment:
name: production
only: [tags]
KUBECONFIG 通过 CI variable 注入。
10. include / extends
# 复用配置
.node-template:
image: node:20-alpine
cache: { paths: [node_modules/] }
before_script: [npm ci]
lint:
extends: .node-template
script: [npm run lint]
test:
extends: .node-template
script: [npm test]
# 跨项目 include
include:
- project: 'devops/ci-templates'
file: '/node.yml'
ref: main
11. 常见反模式
- 每个 job 重新 npm install:不用 cache
- artifact 体积巨大:dist 全传,应只传必要
docker:dindprivileged:用 Kaniko- 生产部署 only branches:应用 only tags
- 不用 needs / DAG:完全串行,慢
- secrets 不 mask:日志泄漏
- 不限 runner:所有 job 互相争抢
- 不分环境:staging 部署用生产凭证
12. 延伸阅读
- GitLab CI 文档
- Kaniko
- GitLab Runner
- 模块 06 GitHub Actions 深度实践(对比)