17、GitLab与CI/CD:GitLab介绍、GitLab CI配置、Runner配置、自动化测试与部署

聊到Git,就不能不提GitLab。很多团队用GitHub做开源,但企业内部开发,GitLab才是真正的利器。为什么?因为它把代码托管、代码审查、CI/CD全打包在一起了。说白了,你不需要东拼西凑各种工具,一个GitLab就能搞定从提交到上线的整条链路。

我个人习惯把GitLab比作「开发者的瑞士军刀」。它不只是一个Git仓库,更是一个完整的DevOps平台。今天我们就来拆解它的核心能力——CI/CD。

GitLab CI/CD 是什么?

先别急着敲命令。我们得先搞清楚,CI/CD到底在解决什么问题。

你想想看,以前开发流程是什么样的?开发写完代码,手动打包,丢给测试,测试测完,再手动部署上线。中间任何一个环节出错,都得从头再来。我见过一个团队,上线一次要折腾大半天,光等编译就半小时。

CI/CD就是把这些重复劳动自动化。CI(持续集成)让你每次提交代码都自动跑测试、自动构建。CD(持续部署)让通过测试的代码自动部署到服务器。嗯,这里要注意:CD也可以是持续交付(手动触发部署),看团队策略。

核心价值:把「人肉操作」变成「机器自动执行」,减少人为失误,加快交付速度。

GitLab CI 的核心概念

要配置GitLab CI,你得先理解三个东西:Pipeline、Job、Stage。

  • Pipeline(流水线):一次CI/CD的完整执行过程。比如你push代码,触发一次Pipeline。
  • Job(任务):Pipeline里的最小执行单元。比如「运行测试」是一个Job,「构建镜像」是另一个Job。
  • Stage(阶段):一组Job的集合。比如「测试阶段」包含多个测试Job,「部署阶段」包含部署Job。

我曾经犯过一个错误:把所有Job都放在同一个Stage里。结果一个Job失败,整个Pipeline都停了。后来才明白,合理的Stage划分能让问题定位更清晰。

下面这张图展示了典型的Pipeline结构:

GitLab CI Pipeline 典型流程 代码提交 Stage 1: 构建 (Build) Stage 2: 测试 (Test) Stage 3: 部署 (Deploy) 每个Stage内的Job并行执行,Stage之间串行执行

配置 .gitlab-ci.yml

GitLab CI的配置文件叫 .gitlab-ci.yml,放在项目根目录。GitLab检测到这个文件后,就会自动触发CI/CD流程。

来看一个最基础的配置:

# .gitlab-ci.yml
stages:
  - build
  - test
  - deploy

build-job:
  stage: build
  script:
    - echo "正在编译项目..."
    - mkdir -p build
    - cp -r src/* build/

test-job:
  stage: test
  script:
    - echo "运行单元测试..."
    - npm test

deploy-job:
  stage: deploy
  script:
    - echo "部署到生产环境..."
    - scp -r build/ user@server:/var/www/
  only:
    - main

这个配置干了三件事:先构建,再测试,最后部署。注意 only: - main,意思是只有main分支的提交才会触发部署。我建议你养成这个习惯——部署操作一定要加分支限制,不然随便一个分支push都可能触发上线,那可就乱套了。

小技巧:可以用 rules 替代 only/except,更灵活。比如根据提交信息决定是否执行某个Job。

Runner 配置

配置文件写好了,谁来执行?答案是Runner。Runner是真正跑Job的「工人」。GitLab官方提供共享Runner,但很多时候你需要自己搭。

为什么?我遇到过这种情况:共享Runner排队太久,一个Job等半小时。而且共享Runner的环境不一定满足你的需求,比如需要特定版本的Node.js或Docker。

安装Runner很简单:

# 在服务器上安装GitLab Runner
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-runner

# 注册Runner
sudo gitlab-runner register

注册时需要输入GitLab实例地址和注册令牌。这些信息在项目的 Settings → CI/CD → Runners 页面可以找到。

Runner有三种类型:

类型 说明 适用场景
Shared Runner 所有项目共享 小团队、测试环境
Group Runner 组内项目共享 部门级项目
Specific Runner 指定项目专用 生产环境、特殊需求

我个人习惯给生产环境部署用Specific Runner,确保资源不被其他项目抢占。测试环境用Shared Runner就够了。

自动化测试

CI/CD的核心价值之一就是自动化测试。没有测试的流水线,说白了就是「自动部署bug」。我曾经接手过一个项目,CI流水线跑得挺欢,但里面全是 echo "test passed" 这种假测试。结果上线后问题不断。

真正的自动化测试应该包含:

  • 单元测试:测试每个函数、模块的正确性
  • 集成测试:测试模块之间的交互
  • 代码质量检查:用ESLint、SonarQube等工具

看一个带测试的完整示例:

stages:
  - lint
  - test
  - build
  - deploy

lint-job:
  stage: lint
  script:
    - npm install
    - npm run lint

unit-test:
  stage: test
  script:
    - npm install
    - npm run test:unit
  artifacts:
    reports:
      junit: junit.xml

integration-test:
  stage: test
  script:
    - docker-compose up -d
    - npm run test:integration
    - docker-compose down

build-job:
  stage: build
  script:
    - docker build -t myapp:$CI_COMMIT_SHORT_SHA .
    - docker push myapp:$CI_COMMIT_SHORT_SHA

deploy-prod:
  stage: deploy
  script:
    - kubectl set image deployment/myapp myapp=myapp:$CI_COMMIT_SHORT_SHA
  only:
    - main
  when: manual

注意 when: manual,这是手动触发部署。生产环境我强烈建议用手动部署,而不是自动。自动部署到测试环境没问题,但生产环境还是让人看一眼比较放心。

避坑指南:我曾经因为测试环境数据库和生产环境不一致,导致测试全过但上线就崩。后来我强制要求测试环境镜像和生产环境保持一致。记住:环境差异是CI/CD最大的敌人。

自动化部署策略

部署不是简单的把文件丢到服务器。现代部署讲究「零停机」和「快速回滚」。常用的策略有:

  • 蓝绿部署:维护两套环境,切换流量
  • 滚动更新:逐步替换旧实例
  • 金丝雀发布:先让少量用户用新版本

在GitLab CI中,你可以通过不同的Job来实现这些策略。比如:

deploy-canary:
  stage: deploy
  script:
    - kubectl set image deployment/myapp-canary myapp=myapp:$CI_COMMIT_SHORT_SHA
  only:
    - main
  environment:
    name: production/canary

deploy-production:
  stage: deploy
  script:
    - kubectl set image deployment/myapp myapp=myapp:$CI_COMMIT_SHORT_SHA
  only:
    - main
  when: manual
  environment:
    name: production

先部署金丝雀版本,观察一段时间没问题,再手动部署全量版本。这个流程我用了很久,效果很好。

环境变量与缓存

CI/CD中两个容易被忽略的点:环境变量和缓存。

环境变量用来存储敏感信息,比如数据库密码、API密钥。千万别写在代码里!在GitLab的 Settings → CI/CD → Variables 里配置,然后在yml中引用:

deploy-job:
  script:
    - echo "数据库密码是 $DB_PASSWORD"
  variables:
    DB_PASSWORD: $DB_PASSWORD

缓存用来加速构建。比如Node.js的 node_modules,每次重新安装太慢了:

cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/

install-deps:
  script:
    - npm install

这样只有分支切换或 package.json 变化时才会重新安装依赖。我算过,加了缓存后Pipeline时间缩短了60%。

总结

GitLab CI/CD其实不复杂。核心就三件事:写对 .gitlab-ci.yml、配好Runner、加好测试。但细节决定成败——环境一致性、分支策略、缓存配置,这些才是真正影响体验的地方。

如果你刚开始接触,建议从最简单的流水线开始,逐步加测试、加部署策略。别想着一步到位,CI/CD是持续改进的过程。

一句话记住:GitLab CI/CD不是银弹,但它能把重复劳动变成自动化流程,让你专注于真正有价值的事情——写代码。

公众号:蓝海资料掘金营,微信deep3321