GitLab CI/CD是内置于GitLab的持续集成/持续交付系统,通过仓库根目录的.gitlab-ci.yml文件定义流水线,由GitLab Runner执行具体任务。相比Jenkins的插件式架构,GitLab CI与代码仓库深度集成,配置即代码,无需额外维护CI服务。对于已有GitLab基础设施的团队,GitLab CI是成本最低的CI/CD落地方案。
Runner安装注册与Executor选型
GitLab Runner是流水线任务的执行器,支持多种Executor类型。Shell Executor直接在Runner主机上执行命令,适合简单场景;Docker Executor在容器中执行,隔离性好且支持指定镜像版本,是生产环境推荐方案。
# 安装GitLab Runner(Ubuntu/Debian)
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
apt-get install gitlab-runner
# 注册Runner
gitlab-runner register
# 输入GitLab URL: https://gitlab.example.com/
# 输入Registration Token: 从GitLab项目Settings -> CI/CD -> Runners获取
# 输入Executor: docker
# 输入Default Docker Image: node:20-alpine
注册后Runner配置文件位于/etc/gitlab-runner/config.toml,可调整并发数和缓存目录:
concurrent = 4 # 最大并发任务数
[[runners]]
name = "docker-runner"
executor = "docker"
[runners.docker]
image = "node:20-alpine"
volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
pull_policy = "if-not-present" # 避免每次都拉取镜像
[runners.cache]
Type = "s3"
ServerAddress = "minio.internal:9000"
BucketName = "runner-cache"
AccessKey = "minioadmin"
SecretKey = "minioadmin"
pull_policy = "if-not-present"优先使用本地镜像,仅当本地不存在时才拉取,可大幅减少流水线启动时间。缓存配置使用S3兼容存储(如MinIO),将构建缓存与Runner主机解耦,多Runner共享缓存。
.gitlab-ci.yml流水线结构
一个完整的前端项目流水线配置:
image: node:20-alpine
variables:
NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.npm-cache"
CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/.cypress-cache"
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .npm-cache/
- .cypress-cache/
policy: pull-push
stages:
- install
- test
- build
- deploy
install:
stage: install
script:
- npm ci --cache .npm-cache --prefer-offline
artifacts:
paths:
- node_modules/
expire_in: 1 hour
lint:
stage: test
needs: [install]
script:
- npm run lint
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
unit-test:
stage: test
needs: [install]
script:
- npm run test:unit -- --coverage --reporter=json
coverage: '/Lines.*: (\d+\.\d+)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
paths:
- coverage/
expire_in: 7 days
build:
stage: build
needs: [lint, unit-test]
script:
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 day
rules:
- if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"
deploy-staging:
stage: deploy
needs: [build]
script:
- rsync -avz --delete dist/ /var/www/staging/
environment:
name: staging
url: https://staging.example.com
rules:
- if: $CI_COMMIT_BRANCH == "develop"
deploy-production:
stage: deploy
needs: [build]
script:
- rsync -avz --delete dist/ /var/www/production/
environment:
name: production
url: https://www.example.com
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual # 需要手动触发生产部署
needs关键字定义任务间的显式依赖,允许同一stage的任务并行执行,无需等待同stage其他任务完成。rules替代旧版only/except,基于表达式条件控制任务是否执行。when: manual使生产部署需要人工确认,防止误发布。
Docker镜像构建与推送到Registry
使用Docker-in-Docker(dind)或Kaniko构建镜像。Kaniko无需Docker守护进程,安全性更好:
build-image:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.23.0-debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo "{"auths":{"${CI_REGISTRY}":{"auth":"$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64)"}}}" > /kaniko/.docker/config.json
- /kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHORT_SHA}"
--destination "${CI_REGISTRY_IMAGE}:latest"
--cache=true
--cache-repo "${CI_REGISTRY_IMAGE}/cache"
--cache-ttl=168h
--cache=true启用Kaniko层缓存,未变更的Dockerfile层直接复用缓存镜像层,构建时间从分钟级降至秒级。--cache-repo指定缓存存储仓库,需提前创建。
环境变量管理与Secret保护
GitLab CI支持项目级、环境级和组的变量管理。敏感信息(API密钥、数据库密码)应通过CI/CD Variables配置,而非硬编码在.gitlab-ci.yml中:
deploy-production:
stage: deploy
script:
- |
ssh -o StrictHostKeyChecking=no deploy@prod-server << 'EOF'
cd /app
docker compose pull
DATABASE_URL=$DATABASE_URL docker compose up -d
EOF
variables:
DATABASE_URL: $PROD_DATABASE_URL
rules:
- if: $CI_COMMIT_BRANCH == "main"
在GitLab项目Settings -> CI/CD -> Variables中定义PROD_DATABASE_URL,勾选Masked选项使其在日志中显示为[MASKED]。勾选Protected选项使变量仅在受保护分支(如main)的流水线中可用,防止在feature分支中泄漏。
对于需要动态生成的密钥(如临时数据库密码),可在流水线中生成并通过GitLab API传递:
generate-secrets:
stage: deploy
script:
- DB_PASSWORD=$(openssl rand -hex 16)
- |
curl --request PUT --header "PRIVATE-TOKEN: $CI_JOB_TOKEN" --data "value=$DB_PASSWORD" "$CI_API_V4_URL/projects/$CI_PROJECT_ID/variables/DEPLOY_DB_PASSWORD"
并行测试与流水线性能优化
测试套件耗时较长时,利用parallel关键字拆分为多个并行任务:
test:
stage: test
parallel: 4
script:
- |
NODE_INDEX=$((CI_NODE_INDEX - 1))
NODE_TOTAL=$CI_NODE_TOTAL
npx jest --shard=$NODE_INDEX/$NODE_TOTAL
artifacts:
reports:
junit: test-results/junit.xml
parallel: 4将测试拆分为4个并行任务,CI_NODE_INDEX和CI_NODE_TOTAL由GitLab自动注入。Jest的--shard参数支持测试文件级别的分片分配。4个并行任务可将测试时间降低约60%(考虑任务调度开销)。
Junit测试报告通过artifacts.reports.junit上传,GitLab自动在Merge Request中显示测试结果摘要,包括失败用例数和新增失败用例数。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/gitlabcicd-liu-shui-xian-shi-zhan-gitlabciyml-pei-zhi-yu/