以前每到月底核对阿里云账单,我都觉得心在滴血。
作为一家不到30人技术团队的负责人,我曾陷入过这样一个怪圈:开发为了并行开发几个功能,嚷嚷着要加机器;测试因为环境不稳定,经常在群里喊“谁又改配置了?”;运维(其实就是我兼职)每天还要手动去清理那些早就没人用的“僵尸容器”。
最惨的一次,一个已经上线三个月的营销活动环境,因为忘了关,默默跑了一整季度的流量费,够买好几台高配MacBook了。
那时我才意识到,对于中小团队,搭建环境不难,难的是如何优雅地“销毁”它。
今天我想聊聊,在没有专职运维、预算有限的情况下,我们是如何通过一套“用完即焚”的机制,把测试环境管理顺畅的。
既然没钱,就别搞“长生不老”的环境
很多中小团队的测试环境是“固定资产”。比如 IP 为 .100 的是开发联调环境,.101 是集成测试环境。所有人的代码都往这两个大熔炉里扔。
这就导致一个经典场景:前端小刘刚部署完,后端大李这边的接口改了还没发,环境瞬间崩盘。排查一小时,代码五分钟。
观点:测试环境应该是“一次性餐具”,而不是“传家宝”。
我们要做的,是基于 Feature Branch(特性分支)动态生成环境。
去年双十一前夕,我们要并行开发三个大需求。按照老路子,我得去开三台云服务器,配环境、装依赖,等项目结束了还得记着去退订。
后来我们逼了自己一把,把整个流程改成了**“按需拉起”**。
大概逻辑是这样的:
- 开发提交代码到
feature/xxx分支; - GitLab CI 自动触发,根据 Docker Compose 模板,在并在集群里拉起一套独立命名空间的服务(比如
app-feature-xxx); - 自动配置一个动态域名(如
xxx.test.mycompany.com)丢到钉钉群里。
结果非常直观: 测试人员拿到的是一个纯净、独立的环境,随便折腾都不会影响别人。更关键的是,我们引入了一个规则:分支合并即销毁。一旦代码合入主干,这个环境及其占用的资源立刻被脚本自动回收。
这不仅仅是技术变更,更是资源管理思维的转变。
哪怕是脚本,也要做成“一键式”
只要涉及到“人”去操作,就一定会出错。
我之前有个习惯,每周五下午会手动去清理那些未使用的Docker容器。但有一次因为临时开会忘了,结果周末流量激增,一台残留的压力测试容器把数据库连接池打爆了,导致线上服务短暂不可用。
这事儿让我背了个大锅,也让我下定决心做全链路自动化。
观点:把部署和销毁的逻辑封装进代码仓库,别藏在运维的脑子里。
对于我们这种中小团队,上 Kubernetes (K8s) 可能有点重,维护成本高。我推荐一个简单的组合拳:Docker Compose + Makefile + Shell Script。
我们在每个项目的根目录下都放了一个 Makefile。不管是新来的实习生,还是我也好,需要环境时,只需要敲一个命令。
举个真实的例子,我们的后端项目里有这样一个 deploy.sh 脚本片段,它不仅负责跑起来,还负责给自己设定“寿命”:
#!/bin/bash
# 自动生成唯一标识
ENV_ID=$(git rev-parse --short HEAD)
echo "正在部署环境: $ENV_ID"
# 启动服务
docker-compose -p $ENV_ID up -d
# 【关键点】记录创建时间,用于后续超时销毁
echo "$(date +%s) $ENV_ID" >> /opt/env_tracker/active_envs.log
# 自动清理逻辑:如果是临时测试,设置TTL(比如4小时后自动下线)
if [ "$DEPLOY_TYPE" == "temp" ]; then
echo "警告:此环境将在4小时后自毁"
# 调用延时任务或注册到清理脚本中
fi
这个改动落地后,最直接的效果是扯皮变少了。以前部署失败,开发会说“环境有问题”;现在部署脚本跟代码在一起,环境起不来,那就是代码或者配置有问题,修就完事了。
对抗惰性:给环境装个“定时炸弹”
人性是懒惰的。即便有了自动销毁机制,大家还是习惯开着环境“以防万一”。
我曾做过一次突击检查,发现服务器上跑着20多个容器,真正活跃的只有3个。问了一圈,开发A说“那个Bug还没复现出来,先留着”,开发B说“我待会儿还要用”。结果这个“待会儿”就是一个星期。
观点:默认销毁,保留需申请。
我们制定了一条硬性规则:非主干环境,生命周期只有 24 小时。
为了落地这个规则,我写了一个简单的 Python 脚本(我们戏称为“灭霸脚本”),挂在 Crontab 里,每天凌晨 3 点运行。
它的工作逻辑很简单:
- 扫描所有非 Master 分支对应的容器;
- 检查该容器的最后活跃时间(通过日志或者 Git 提交时间);
- 如果超过 24 小时无人认领,直接 Kill,并发送一条钉钉通知:“环境
feature-login-fix已被系统回收,如有需要请重新触发流水线。”
刚开始推行的时候,骂声一片。有兄弟抱怨:“我昨天配好的数据今天没了!”
但坚持了两个月后,神奇的事情发生了:
大家开始习惯把初始化数据的动作写进 seed 脚本里,而不是手动去数据库插数据(因为环境随时会没)。这反倒逼着大家提升了测试数据的管理能力。
现在,我们的云服务器资源利用率维持在 70% 左右,再也没有那种“CPU利用率 5%,内存却爆了”的怪象。
看到这里,不妨停下来想一想
你现在的团队里,是不是也有几个“没人敢动”的测试环境?或者几台你根本不知道在跑什么的云主机?
你有没有发现,很多时候我们不敢销毁环境,是因为重建环境的成本太高?
如果你也想改变现状,不需要一上来就搞高大上的云原生,建议从这 3 个动作开始:
- 盘点家底:今天就登录你的云控制台,把所有正在运行的实例列个表,标记出哪些是最近一周没人在用的。
- 容器化一切:如果还在用虚机手动部署,赶紧切到 Docker。这是“用完即焚”的前提。
- 配置即代码:把环境变量、启动参数全部抽离到配置文件或代码仓库中,确保任何一个人拿到代码,都能一键拉起一模一样的环境。
DevOps 不是只有大厂才能玩的高精尖,对于我们中小团队来说,它更像是一种**“抠门”的艺术**——用最少的资源,跑最稳的代码。