GitLab CI/CD vs 手动操作:效率对比实测

devops进阶8 分钟阅读2026/9/3

GitLab CI/CD vs 手动操作:效率对比实测

为什么我开始做这个对比

上个月我们团队接了一个中等规模的项目,三个开发人员,每次发版流程是这样的:本地跑测试、手动打包、SSH 到服务器、备份旧版本、上传新包、重启服务、手动验证。整个过程我一个人操作大概要 25 分钟,而且有一次凌晨发版,我因为困了忘了备份,回滚花了两个小时。

第二天我下定决心:要么把流程自动化,要么我早晚要出事。但我也很好奇——引入 GitLab CI/CD 到底能省多少时间?网上都说“效率提升巨大”,但很少有人给出真实的数字。所以我做了一个月的对比实测,把每次部署的时间都记了下来。

环境说明

  • 项目:Node.js 后端 + Vue 前端,单体应用
  • 代码托管:自建 GitLab 16.x(公司内网服务器,4 核 8G)
  • 部署目标:2 台阿里云 ECS
  • 测试:Jest 单元测试 + 一套 API 冒烟测试

第一步:记录手动操作的基线

我先花了一周时间,把手动部署的每个步骤计时:

步骤 耗时
本地跑完整测试 6 分钟
手动构建 Docker 镜像并推送 4 分钟
SSH 到两台服务器,拉镜像、重启 5 分钟
手动冒烟验证 3 分钟
写发版记录、通知群 2 分钟
合计(含切换上下文的隐性时间) 22–28 分钟

更重要的是隐性成本:发版期间我不能干别的,而且发版经常被打断——测试跑到一半有人找我,回来忘了跑到哪一步了。

第二步:搭建最简流水线

我没有一上来就搞复杂的多阶段流水线,先写了一个能跑通的最小版本。项目根目录建 .gitlab-ci.yml

stages:
  - test
  - build
  - deploy

test:
  stage: test
  image: node:20
  script:
    - npm ci
    - npm run test:ci
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/

build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker login -u $REGISTRY_USER -p $REGISTRY_PASS $REGISTRY_URL
    - docker build -t $REGISTRY_URL/myapp:$CI_COMMIT_SHORT_SHA .
    - docker push $REGISTRY_URL/myapp:$CI_COMMIT_SHORT_SHA
  only:
    - main

deploy:
  stage: deploy
  image: alpine:3.19
  before_script:
    - apk add openssh-client
    - eval $(ssh-agent -s)
    - echo "$DEPLOY_SSH_KEY" | tr -d '\r' | ssh-add -
  script:
    - ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$SERVER_1
        "cd /opt/myapp && docker compose pull && docker compose up -d"
    - ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$SERVER_2
        "cd /opt/myapp && docker compose pull && docker compose up -d"
  environment:
    name: production

DEPLOY_SSH_KEYREGISTRY_PASS 这些敏感信息都在 GitLab 项目的 Settings → CI/CD → Variables 里配置,类型选 Masked,日志里就不会明文显示。

我踩的三个坑

坑一:Runner 不够用。 第一次 push 之后流水线卡在 pending 状态半小时。查了半天才发现自建 GitLab 没有注册共享 Runner。我自己在一台 4 核的机器上用 Docker 方式注册了一个:

docker run --rm -it -v gitlab-runner-config:/etc/gitlab-runner \
  gitlab/gitlab-runner register

注册时 executor 选 docker,默认镜像填 node:20

坑二:node_modules 缓存反而更慢。 我最开始加了 cache 配置以为会加速,结果发现缓存的上传下载每次要 90 秒,比直接 npm ci 还慢。后来改成了用 npm ci 配合本地 .npm 缓存目录,才真正提速。缓存不是加了就快的,要实测。

坑三:Docker-in-Docker 权限问题。 build 阶段一直报 Cannot connect to the Docker daemon。原因是我忘了在 variables 里配 DOCKER_TLS_CERTDIR: "",或者说服务里的 dind 没起来。加上:

variables:
  DOCKER_TLS_CERTDIR: ""

问题解决。这个问题网上的答案五花八门,最简单的办法就是看 Runner 的日志而不是流水线日志。

第三步:实测数据对比

配置稳定后,我记录了接下来三周的每次部署:

指标 手动操作 CI/CD
单次部署耗时(人参与时间) 22–28 分钟 2–3 分钟(其中人工时间约 30 秒:merge + 点重试)
机器执行时间 8–11 分钟
月部署次数 约 8 次 40+ 次
失败后回滚时间 30–60 分钟 约 2 分钟(重新部署上一个镜像 tag)
凌晨发版需求 无(合并即部署)

几个值得说的发现:

  1. 流水线的机器执行时间其实比手动打包还慢(要拉镜像、起容器),但这不重要——因为人不用盯着。实际节省的是“人的时间”,从每次 25 分钟降到 30 秒。
  2. 部署频率上去了,单次风险反而变小了。 以前一次发版塞五六个功能,现在每次合并一两个小改动,出问题好定位。
  3. 测试左移的效果超出预期。 以前偶尔有人本地不跑测试就发版,现在流水线里测试不过就部署不了,这个纪律是自动执行的。

进阶优化(第二个月做的)

流水线稳定后我又加了两样东西:

手动确认的部署门禁:生产环境部署前需要点一下:

deploy:
  stage: deploy
  when: manual
  allow_failure: false

失败通知:加了一个 after_script 调用企业微信 webhook,失败时群里直接报警,不用自己去 GitLab 里翻。

诚实的局限性说明

  • 前期投入是真的。 我搭第一版流水线花了大约一个整天,加上踩坑调试接近两天。如果你一个月只发一两次版,ROI 是负的。发版频率越高,这个投入越值。
  • Runner 维护是持续成本。 我那个共享 Runner 有一次磁盘满了导致所有构建失败,排障花了半小时。共享 Runner 是新的单点。
  • CI 日志偶尔会莫名超时,重跑就好了,但原因一直没查清楚,怀疑是内网 GitLab 服务器的并发问题。
  • 小团队不需要一开始就上多环境、多阶段流水线。 我见过有人第一天就配了 review apps、canary 部署,两周后没人维护,退回了手动。先跑通 test → build → deploy 三步,够用很久。

我的建议

如果你现在的手动部署超过 10 分钟,或者一周发版超过 2 次,值得花一两天把 GitLab CI/CD 搭起来。从最小可用的三阶段流水线开始,用真实数据对比一周,你会自己得出结论的——我的结论是:那 25 分钟,我再也回不去了。

相关 Agent

D

Docker

Docker 是一个容器化平台,允许开发者将应用及其依赖项打包成轻量级、可移植的容器。它简化了跨环境的开发、测试和部署过程。该描述强调它最适合容器化和开发环境,提供免费方案和团队方案,团队方案从每用户每月5美元起。

了解更多 →