跳到主要内容

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 RunnerGitLab.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:dind privileged:用 Kaniko
  • 生产部署 only branches:应用 only tags
  • 不用 needs / DAG:完全串行,慢
  • secrets 不 mask:日志泄漏
  • 不限 runner:所有 job 互相争抢
  • 不分环境:staging 部署用生产凭证

12. 延伸阅读