裸辞半年后重返职场,我差点被 CI/CD 给整自闭了

CD还没发
2025-12-14 22:23
阅读 556

大家好,我是老张(化名),前大厂 P7,去年裸辞 Gap 了整整半年,美其名曰“探索人生第二曲线”,实则在家刷 GitHub、啃源码、打游戏。两个月前,终于被老婆的白眼和房贷账单逼着重新找了份工作——一家中型互联网公司,团队氛围还不错,就是 deadline 比我前司还卷。

入职第一天,Leader 就甩给我一个 SpringBoot 项目:“小张啊,你不是搞过大厂高可用架构吗?帮我们把 CI/CD 流程搭起来吧,现在每次上线都靠手动打包、人肉部署,测试那边天天在群里@我,说环境又崩了。”

我当时表面稳如老狗,内心已经慌得一批:裸辞半年,CI 工具链都快忘光了!


为什么我这个“前大厂员工”也差点翻车?

说实话,在前东家时,CI/CD 都是 DevOps 团队封装好的平台,点点按钮就完事了。自己写个 Jenkinsfile?那都是运维兄弟的事儿。结果现在到了新公司,DevOps 岗位还没招到人,整个后端团队就我资历最老(其实也就比应届生多干了三年),这活儿自然落我头上了。

更尴尬的是,上周五晚上我还在为一个 SpringBoot 项目的集成测试卡住发愁——本地跑得好好的,推到 GitLab CI 上就报错:

Error: Could not find or load main class com.example.MyApplication

当时真的想砸电脑。后来发现是因为 DockerfileCOPY 的路径没对齐……这种低级错误,在大厂根本轮不到我犯,因为有标准化模板。但现在?一切从零开始。

也是这次踩坑,让我意识到:懂原理 + 能落地,才是真本事。 于是花了两周时间,从零搭建了一套轻量但可靠的 CI 流程。今天这篇《持续集成工具入门指南》,既是给团队新人的文档,也算是我 Gap 半年后重返职场的第一份技术复健作业。

顺便说一句:最近面试问 CI/CD 的频率明显高了,很多公司不再满足于你会写 CRUD,而是看你有没有工程化思维。所以这篇也顺手塞点“Springboot 面试题”彩蛋,助你跳槽一臂之力。


别再傻傻地“人肉集成”了!

先说说我们原来的开发流程有多原始:

  1. 开发写完代码,本地 mvn clean package
  2. 把 jar 包拖到测试群里:“@测试同学,新包来了,部署下”
  3. 测试同学手动替换服务器上的旧包,重启服务
  4. 出问题了?回滚?不好意思,没人知道上个版本 jar 包在哪……

这种模式的问题显而易见:

  • 不可重复:不同人打包可能依赖版本不一致
  • 不可追溯:线上出 bug,不知道是哪个 commit 引入的
  • 效率低下:每次上线都要等人,产品经理在旁边疯狂催:“能不能快点?用户都投诉了!”

而持续集成(CI)的核心思想就一句话:每次提交代码,自动触发构建、测试、打包,确保主干始终可发布。

听起来很美好,但选哪个工具?Jenkins?GitLab CI?GitHub Actions?还是 Argo CD?


工具选型:别被花里胡哨的功能忽悠了

作为过来人,我的建议是:先看团队用什么 Git 平台!

  • 如果你们用 GitLab(像我们公司),直接上 GitLab CI,无缝集成,配置简单,YAML 写起来也清爽。
  • 如果是 GitHub,那就 GitHub Actions,生态强大,Marketplace 插件多。
  • 如果公司已经有一套 Jenkins 集群,且运维愿意维护,那也可以用,但配置复杂度高,学习曲线陡。

我们最终选了 GitLab CI,原因很简单:省事。不用额外部署 Jenkins 服务器,不用配 agent,直接在 .gitlab-ci.yml 里写 pipeline 就行。

下面是我们 SpringBoot 项目的简化版 CI 配置:

stages:
  - build
  - test
  - package
  - deploy-dev

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"

cache:
  paths:
    - .m2/repository/
    - target/

build:
  stage: build
  script:
    - mvn compile -B
  only:
    - merge_requests

test:
  stage: test
  script:
    - mvn test -B
  coverage: '/TOTAL.*?([0-9]{1,3})%/'
  only:
    - merge_requests

package:
  stage: package
  script:
    - mvn package -DskipTests -B
    - cp target/*.jar app.jar
  artifacts:
    paths:
      - app.jar
  only:
    - main

deploy-dev:
  stage: deploy-dev
  script:
    - echo "Deploying to dev environment..."
    - scp app.jar user@dev-server:/app/
    - ssh user@dev-server "systemctl restart myapp"
  only:
    - main

注:生产环境部署我们用了更安全的方式(比如通过 Ansible 或 K8s Helm),这里仅为演示。


踩过的坑:那些让你深夜抓狂的细节

坑1:Maven 依赖每次都重新下载?

解决:用 cache 缓存 .m2/repository,速度提升 80%。

坑2:测试覆盖率怎么上报?

我们在 test job 里加了 coverage 正则,GitLab 会自动解析并显示在 MR 页面。这样 Code Review 时就能看到:“哟,你这新增代码覆盖率才 30%?”

坑3:部署脚本权限问题?

别用 root!我们新建了一个 deployer 用户,只给 /app/ 目录写权限,并用 SSH 密钥认证。安全意识要拉满——别让 CI 成为黑客入口。

坑4:SpringBoot 应用启动失败?

一定要在 Dockerfile 或部署脚本里指定 -Dspring.profiles.active=dev,否则默认加载 application.properties,可能连不上数据库。


为什么 CI 是 SpringBoot 面试题的高频考点?

最近帮 Leader 面了几个人,发现一个趋势:面试官不再只问 “SpringBoot 自动装配原理”,而是会问:

“你们项目是怎么做持续集成的?”
“如果 CI 流水线失败了,你怎么排查?”
“如何保证每次构建的可重复性?”

这些问题其实在考察你的工程素养。举个例子:

Q:SpringBoot 项目如何在 CI 中运行集成测试?

A:不能只跑单元测试!我们要启动内嵌 Tomcat,调用真实 API。可以用 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT),配合 Testcontainers 启动临时 MySQL 容器。

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@Testcontainers
class UserControllerIntegrationTest {

    @Container
    static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0");

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", mysql::getJdbcUrl);
        registry.add("spring.datasource.username", mysql::getUsername);
        registry.add("spring.datasource.password", mysql::getPassword);
    }

    // your test cases...
}

这种能力,光看八股文是学不会的,必须实战。


效果如何?团队终于能睡安稳觉了

自从 CI 上线后:

  • 上线频率从每周1次 → 每天3次
  • 线上事故减少70%(因为问题在合并前就被 CI 拦截)
  • 测试同学不再骂我了(感动)

更重要的是,代码质量肉眼可见地提升了。因为每个人提 MR 时都知道:如果测试不通过,CI 会直接 block 合并。久而久之,大家写代码时就会主动考虑可测性、模块解耦——这不就是我们追求的“可维护性”吗?


给新手的几点真心建议

  1. 从小做起:先实现“代码提交 → 自动跑测试”,别一上来就想搞全自动发布到生产。
  2. 安全第一:CI 脚本里不要硬编码密码!用 GitLab 的 Variables 或 Vault 管理密钥。
  3. 可观测性:给每个 job 加日志输出,失败时能快速定位。
  4. 别过度设计:我们初期想搞多环境矩阵测试,结果维护成本太高,最后砍掉,只保留 dev 和 prod 两套 pipeline。

最后:Gap 半年不是终点,而是重启

裸辞那半年,我一度怀疑自己是不是脱离 industry 太久了。但这次从零搭建 CI 的经历让我明白:技术人的核心能力,不是记住多少 API,而是解决问题的思路和工程化思维。

如果你也在准备跳槽,或者刚入职新公司被安排搞 CI,别慌。从一个简单的 .gitlab-ci.yml 开始,一步步来。所有复杂的系统,都是由一个个简单的 commit 堆起来的。

对了,文末放个彩蛋:我们团队现在招人,要求不高——只要能写出不被 CI 拒绝的代码就行 😎

Happy Coding,愿你的 pipeline 永远 green!

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝