代码人生不是写完就跑,而是让项目活下来

不想写日报
2026-01-15 08:47
阅读 4068

去年双11前夜,我坐在深圳南山某腾讯系公司茶水间里,手里捏着一杯快凉透的美式,脑子里全是 CI/CD 流水线又崩了的消息。运维群炸锅,产品催上线,测试报了一堆“偶发性失败”,而我——一个自诩“能用脚本解决一切”的 DevOps 工程师——正盯着 GitLab Runner 日志里那句熟悉的 Error: connection refused 想砸键盘。

那一刻我突然意识到:我们写的每一行代码,最终都要在真实世界的混沌中生存。代码人生不是炫技、不是卷八股文、更不是 PR 数拉满就完事,而是如何让项目在复杂的产品迭代节奏下持续交付、稳定运行、快速反馈。今天这篇文章,就是我在踩过无数坑、熬过无数夜后,对“技术探索与实践最佳实践”的一点碎碎念。


从“能跑就行”到“不敢上线”的血泪史

刚入行那会儿,我觉得自动化就是写个 shell 脚本把 build、test、deploy 串起来,跑通就 OK。结果第一次负责一个核心支付模块的发布,因为没做环境隔离,测试数据污染了预发库,导致第二天大促时用户余额显示负数——产品总监直接冲进办公室问:“你们是不是想让我背锅?”

那之后我痛定思痛,开始研究开源项目源码,比如 GitLab CI 的执行器模型、Argo CD 的声明式同步机制、还有 Spinnaker 的金丝雀发布策略。我发现,真正的工程化,不是工具堆砌,而是流程可追溯、状态可验证、变更可回滚。

在深圳这种互联网密集区,大厂小厂都在卷“快速迭代”,但快≠乱。我们团队现在有个不成文规矩:没有自动化流水线的项目,不准合入主干。听起来有点霸道,但这是用线上事故换来的共识。


实践一:项目结构即契约,别让协作变成猜谜游戏

很多团队的项目仓库乱得像程序员的桌面:scripts/、tools/、old_backup_v2_final/……新人来了第一周光搞懂目录结构就秃了头。

我们现在强制推行 “标准化项目骨架”,结合 monorepo 思想,但不盲目跟风。关键原则就一条:任何人 clone 下来,5 分钟内知道怎么本地调试、怎么跑测试、怎么部署。

my-service/
├── .devcontainer/          # VS Code Remote-Containers 配置(深圳夏天太热,远程开发救我命)
├── .github/workflows/      # GitHub Actions 流水线(替代 GitLab,老板说要降本增效)
├── charts/                 # Helm Chart,K8s 部署单元
├── src/                    # 源码
├── tests/                  # 端到端测试 + 契约测试
├── Makefile                # 统一入口:make test, make build, make deploy
└── README.md               # 必须包含:本地启动命令、依赖说明、负责人

吐槽一句:产品经理总说“这个需求很简单”,但当你问他“这个接口的 SLA 是多少?失败重试策略是什么?”时,他眼神就开始飘了。所以我们在 README 里加了 “产品契约” 小节,逼他们填清楚非功能需求。


实践二:代码人生,从“写完就跑”到“可观测闭环”

以前我觉得监控是 SRE 的事,直到有一次服务内存泄漏,Pod 每小时重启一次,但业务指标看着正常,直到三天后用户投诉“操作变慢”。查日志发现 GC 时间飙升,而我们的 Prometheus 根本没采集 JVM Metaspace 指标。

现在我们要求所有服务必须暴露以下四类指标(参考 Google SRE 书):

类型 示例指标 用途
请求量 http_requests_total 判断流量突增
错误率 http_request_errors_total 快速定位异常
延迟 http_request_duration_seconds SLA 达标与否
饱和度 process_open_fds, cpu_usage 资源瓶颈预警

而且,指标必须和业务语义绑定。比如订单创建失败,不能只报 5xx,而要打上 order_create_failed{reason="inventory_short"}。这样产品看 Grafana 面板时,也能大致判断是库存问题还是风控拦截。


实践三:产品思维驱动自动化设计

很多 DevOps 工程师陷入一个误区:沉迷于技术实现,忘了服务对象是谁。

我们的自动化流水线,其实是为产品团队赋能的工具链。举个例子:以前每次灰度发布,都要手动改 Nginx upstream,产品经理只能干等。现在我们搞了个 “一键灰度”按钮,集成到内部平台:

  1. 选择目标版本
  2. 输入灰度比例(1%、5%、10%...)
  3. 自动创建 Argo Rollout 资源
  4. 实时展示新旧版本错误率对比
  5. 产品确认后,自动全量

技术选型背后是用户体验。为什么选 Argo Rollout 而不是原生 Deployment?因为它支持蓝绿、金丝雀、渐进式发布,且状态机清晰,YAML 可读性强——这对非运维人员友好。而 Spinnaker 虽然强大,但学习成本太高,我们团队撑不住。


实战:用 GitOps 管住“手欠”的开发者

曾经有个同事,为了“快速修复”,直接 kubectl edit deployment 改了线上配置。结果下次 CI 自动部署时,他的改动被覆盖,服务挂了。这种“漂移配置”(Configuration Drift)简直是 DevOps 的噩梦。

我们引入 GitOps 模式,核心思想就一句:集群状态 = Git 仓库里的声明。

具体做法:

  • 所有 K8s 资源定义放在 infra/ 仓库
  • 使用 FluxCD 监听该仓库
  • 任何变更必须通过 MR(Merge Request)
  • MR 需要至少一人 review + 自动化检查(如 kubeval)
# 示例:FluxCD Kustomization
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: my-service-prod
  namespace: flux-system
spec:
  interval: 10m
  path: "./clusters/prod/my-service"
  prune: true        # 自动清理已删除资源
  sourceRef:
    kind: GitRepository
    name: infra-config
  validation: client # 提前校验 YAML 合法性

效果:现在谁想改线上配置,必须走 MR。历史变更全在 Git 里,审计、回滚、对比都方便。连产品经理都能看懂 MR 里的 diff —— “哦,原来是把 replicas 从 3 改成 5 了”。


那些年,我们踩过的“最佳实践”坑

别信“银弹”。有些所谓的最佳实践,在特定场景下就是毒药。

  • 过度容器化:曾有个内部工具,每天只跑一次批处理,硬要打包成 Docker + K8s Job,结果维护成本远高于收益。后来直接用 systemd + cron,香得很。
  • 盲目追求 IaC:Terraform 很好,但如果你的云资源半年才变一次,写一堆 HCL 反而增加认知负担。简单场景,Shell 脚本 + 参数化足矣。
  • 测试覆盖率迷信:90% 覆盖率 ≠ 无 Bug。我们曾有个测试覆盖了所有分支,但没 mock 外部依赖,结果集成时才发现第三方 API 限流。契约测试 > 单元测试覆盖率。

最后:代码人生,是修桥铺路,不是搭积木

在深圳这座“速度之城”,我们总被推着往前跑。但作为 DevOps 工程师,我的角色不是加速器,而是稳定器+放大器——让团队跑得更快的同时,不至于翻车。

技术探索的意义,不在于用了多新的框架,而在于是否解决了真实痛点。上周五晚上,当我看到产品同学自己点了几下鼠标就完成了灰度发布,并在群里说“这次发布好稳”,那一刻,比 merge 一个 PR 还爽。

所以,别再问“DevOps 到底要做什么”。答案很简单:让你的项目活下来,让你的代码人生可持续。

毕竟,我们写的不是代码,是信任。

评论 0

最热最新
暂无评论
不想写日报Lv.1
0
影响力
0
文章
0
粉丝