为什么我们小厂后端要搞部署工具?从线上炸锅到简历镀金的血泪史

后端便利贴
2025-12-18 09:18
阅读 1326

上周五晚上十点,我正窝在出租屋里啃着冷掉的黄焖鸡,突然钉钉连环炸——"用户登录不上了!"、"支付接口502!"、"快救火!!!"。我手一抖,汤汁溅到了 MacBook 的触控板上。

又双叒叕是部署问题。

这已经是我们这个月第三次因为手动部署翻车了。作为北京一家不到50人的创业公司里,独立负责用户中心这条业务线的后端开发,我一度以为自己是个写代码的,结果发现80%的时间都在当“人肉运维”。


被逼上梁山:从“改一行代码上线”到“不敢动生产环境”

说来你可能不信,半年前我们公司的部署流程是这样的:

  1. 我在本地 git commit -m "fix login bug"
  2. 登录生产服务器(对,就一台)
  3. git pull origin main
  4. 手动重启 Java 进程(有时候忘了 kill,两个进程跑着,内存爆了)
  5. 祈祷没出问题

听起来像段子?但这就是现实。我们团队没有专职运维,产品经理天天催“这个需求很简单,改个字段就行,今晚能上线吗?”,测试同学一边测一边吐槽“你们后端是不是又把数据库连错了?”

最离谱的是去年双11前夕,我为了修复一个紧急订单状态问题,在凌晨三点直接在生产机器上 vim 修改了 .properties 配置文件,结果手滑多打了个冒号,服务直接起不来。那晚,老板站在工位后面沉默了十分钟,然后说:“要不……咱们搞个部署工具?”

我当时心里想:早干嘛去了?


面试题挑战:面试官问我“你们怎么部署的”,我差点社死

其实推动我认真搞部署工具的,还有一个“私心”——跳槽

上个月我去面了一家大厂,终面时技术总监随口问:“你们团队是怎么做 CI/CD 的?”
我支支吾吾说了半天“就是 git pull + 手动重启”,对方眼神明显变了,最后委婉地说:“嗯……经验很‘原始’啊。”

那一刻我意识到:不会部署自动化,简历上就少了一块硬通货。现在随便看个中级后端岗 JD,不写着“熟悉 Jenkins/GitLab CI/ArgoCD”都不好意思发。更别说 DevOps、SRE 这些词早就不是大厂专属了——连我们这种小破厂,投资人尽调时都会问“你们有自动化部署能力吗?”

于是,我下定决心:哪怕是为了下次面试不被问住,也得把这套东西搞起来。


选型纠结症:Jenkins?GitLab CI?还是直接上云原生?

一开始我想直接上 Jenkins ——毕竟老牌、文档多、插件全。但一想到要在那台已经跑了 MySQL、Redis、Nginx 和我们三个微服务的 4C8G 小破服务器上再塞个 Jenkins master + agent,我就头皮发麻。

而且 Jenkins 的 Groovy 脚本写起来真的反人类,光是配置 Webhook 触发就折腾了两天,还老是权限报错:

ERROR: Failed to push image: denied: requested access to the resource is denied

我一度想放弃,直到隔壁组前端小哥(对,就是那个喜欢研究 Lottie 动画的)说:“你们后端还在玩 Jenkins?我们前端都用 GitHub Actions 了,YAML 写起来贼清爽。”

一句话点醒梦中人。

考虑到我们代码托管在 GitLab(公司为了省钱自建的),最终决定用 GitLab CI + Docker + 自建 Runner 的组合。理由很现实:

  • 不用额外买 SaaS 服务(省💰)
  • 和现有 Git 仓库无缝集成
  • YAML 配置比 Groovy 友好多了
  • 我还能顺手学点 Docker,给简历加个“容器化”标签

实战:从零搭建自动部署流水线

说干就干。第一步是申请资源——其实就是跟老板要了另一台 4C8G 的云服务器专门跑 CI Runner。老板听说能减少线上事故,爽快批了(看来上次双11的锅他记忆犹新)。

1. 安装 GitLab Runner

在新机器上跑几条命令就行:

# 安装 runner
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
sudo apt-get install gitlab-runner

# 注册 runner(注意执行器选 docker)
sudo gitlab-runner register \
  --url "https://your-gitlab.company.com/" \
  --registration-token "YOUR_TOKEN" \
  --executor "docker" \
  --docker-image alpine:latest

这里踩了个坑:一开始用了 shell 执行器,结果每次构建都污染宿主机环境。换成 docker 后,每个 job 都在干净容器里跑,再也不怕“在我机器上能跑”。

2. 编写 .gitlab-ci.yml

这才是重头戏。我们的目标很简单:提交代码 → 自动构建镜像 → 推送到私有仓库 → 滚动更新生产服务

stages:
  - build
  - deploy

variables:
  IMAGE_NAME: registry.company.com/user-service
  DOCKER_HOST: tcp://docker:2375
  DOCKER_TLS_VERIFY: "0"

# 构建阶段
build_image:
  stage: build
  image: docker:20.10.16
  services:
    - docker:20.10.16-dind
  script:
    - echo "Building image with tag: $CI_COMMIT_SHORT_SHA"
    - docker build -t $IMAGE_NAME:$CI_COMMIT_SHORT_SHA .
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker push $IMAGE_NAME:$CI_COMMIT_SHORT_SHA
  only:
    - main

# 部署阶段
deploy_to_prod:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client curl
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh && chmod 700 ~/.ssh
    - ssh-keyscan -H $PROD_HOST >> ~/.ssh/known_hosts
  script:
    - |
      ssh $PROD_USER@$PROD_HOST "
        docker pull $IMAGE_NAME:$CI_COMMIT_SHORT_SHA &&
        docker stop user-service || true &&
        docker rm user-service || true &&
        docker run -d --name user-service -p 8080:8080 $IMAGE_NAME:$CI_COMMIT_SHORT_SHA
      "
  only:
    - main
  when: manual  # 手动确认才部署,防误触

几个关键点:

  • when: manual:必须手动点击“部署”按钮才会执行,避免一合并就上线(吃过亏)
  • SSH 密钥通过 GitLab Variables 注入:不用把私钥写进代码
  • Docker-in-Docker (dind):让构建过程完全隔离

3. 配合前端动画?其实是配合前端部署!

说到前端,我们前端小哥之前用 Vercel 一键部署,羡慕死我了。现在我们也给他搞了个类似的流程:

# 前端项目的 .gitlab-ci.yml 片段
deploy_frontend:
  stage: deploy
  image: node:18
  script:
    - npm ci
    - npm run build
    - rsync -avz dist/ $FRONTEND_USER@$FRONTEND_HOST:/var/www/html/
  only:
    - main

现在他每次提 PR,CI 会自动构建预览版;合并到 main 后,点一下“deploy”,5 秒上线。上周他甚至用 Lottie 做了个部署成功动画嵌在管理后台里,美其名曰“提升运营幸福感”——产品经理居然真吃这套!


效果对比:从“提心吊胆”到“躺平发布”

搞完这套工具后,变化立竿见影。我整理了个小表格:

指标 手动部署时代 自动化部署后
单次部署耗时 15~30 分钟 < 3 分钟
回滚速度 手动切分支 + 重启(10分钟+) 重新运行上一个 job(1分钟)
人为失误率 每月 2~3 次事故 0(近3个月)
发布心理压力 “上线如上坟” “点完按钮去喝咖啡”
简历关键词 “熟悉 Spring Boot” “主导 CI/CD 流水线建设”

最爽的是上周三,产品临时要改个文案,我改完代码推上去,CI 自动跑完,点一下 deploy,两分钟后他说“好了!”。他惊讶地问:“这就完了?不用等你操作?” 我淡淡一笑:“时代变了,兄弟。”


血泪教训:别踩这些坑!

当然,过程不是一帆风顺。分享几个让我半夜惊醒的坑:

  1. Runner 权限过大
    一开始 Runner 用 root 跑,结果某个 job 里的 rm -rf /(虽然是误写)差点清空服务器。后来严格限制容器权限,并用非 root 用户运行服务。

  2. 镜像标签混乱
    最初用 latest 标签,导致回滚时不知道该拉哪个版本。现在强制用 git commit short hash 作为标签,可追溯性拉满。

  3. 没做健康检查
    有次服务启动了但数据库连不上,CI 显示“部署成功”,实际用户用不了。现在 deploy 脚本加了 curl -f http://localhost:8080/health,不健康就自动回滚。

  4. 忽略日志收集
    刚开始容器日志没挂载,出问题只能 docker logs。现在统一用 Filebeat + ELK,查日志快多了。


不只是为了“不出事”,更是为了“能睡觉”

写这篇文章的时候,我刚下班,通勤地铁上刷着手机。以前这时候我总在担心:“今天下午上线的那个功能,半夜会不会挂?” 现在?CI 流水线跑完绿色 ✅,我就敢关电脑走人。

部署工具的本质,不是炫技,而是把人从重复、高危、低效的操作中解放出来。

对我们这种小厂来说,没有运维团队兜底,后端就得自己扛起稳定性大旗。搞自动化部署,短期看是花时间,长期看是救命。而且——别忘了——它还能让你的简历在 HR 筛选时多亮那么一丢丢。

下次面试官再问“你们怎么部署的”,我可以淡定掏出手机,给他看 GitLab CI 的 pipeline 页面,然后说:“喏,点一下,就上线了。”


最后说点人话

我知道很多小厂同学会说:“我们人少、项目急、老板不给资源,搞什么 CI/CD?”

但我想说:恰恰是因为人少、项目急,才更需要自动化。你省下的每一分钟救火时间,都是在延长自己的职业生涯寿命。更何况,现在开源工具这么成熟,一套基础流水线,周末两天就能搭起来。

别等到线上炸了、背了锅、面试被问住,才后悔没早点动手。

对了,如果你也在小厂挣扎,欢迎评论区交流。顺便,有没有内推机会?简历已更新,关键词加满了 😏

评论 0

最热最新
暂无评论
后端便利贴Lv.1
0
影响力
0
文章
0
粉丝