post: 配置化运维——让变化不再改代码
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
---
|
||||
title: "配置化运维:让变化不再改代码"
|
||||
description: "一天的真实记录:派单路由要加城市、安全防护要封网段、插件要更新配置——三件看起来无关的事,最后都收敛到同一个答案:把变化变成配置。"
|
||||
date: 2026-08-03T19:20:00+08:00
|
||||
draft: false
|
||||
tags:
|
||||
- 运维
|
||||
- 自动化
|
||||
- 配置化
|
||||
- 架构
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
这是一个普通的工作日,却让我对"运维自动化"有了新的理解。回顾这一天做的事,三件看似无关的任务,最后都收敛到了同一个答案:**把变化变成配置,而不是代码**。
|
||||
|
||||
## 一、早上:派单路由要加城市
|
||||
|
||||
业务提需求:"给 4 个城市加专属通知群。"
|
||||
|
||||
放在半年前,这意味着改代码:找到派单函数,加 if-else,测试,上线。但今天,这套逻辑已经重构为**配置驱动**:
|
||||
|
||||
```json
|
||||
{
|
||||
"city_dingtalk_groups": {
|
||||
"重庆": {"token": "...", "at_mobiles": ["..."]},
|
||||
"昆山": {"token": "...", "at_mobiles": ["..."]}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
加一个城市 = 配置文件加几行。**零代码扩展**。
|
||||
|
||||
但这背后藏着一个真实的事故:早上一开始,代码里有个隐患——通知块的 if 条件**顶格**(不区分租约类型),而变量只在某个分支里定义。短租工单派单成功 → 进入通知块 → 变量未定义 → **NameError 崩溃**。
|
||||
|
||||
这个 bug 教会我两件事:
|
||||
|
||||
1. **顶格块引用分支内局部变量 = 高危模式**。条件与变量定义必须同作用域,这是代码审查的检查点。
|
||||
2. **配置化的前提是逻辑先稳**。配置只是把"变化"外置,如果底层逻辑有作用域地雷,配置化只会让地雷更容易被踩。
|
||||
|
||||
## 二、上午:巡检工单找不到维修站
|
||||
|
||||
定时任务每小时的巡检建单持续报错:某公司的地址在四川宜宾(非核心城市),没有维修站可匹配。
|
||||
|
||||
排查发现:巡检单没有 SN、租约类型未知,走不进"长租"分支的兜底逻辑,四条候选路径全部失败,返回空。
|
||||
|
||||
修复方案不是加一条 if-else,而是**在函数末尾加第 5 条兜底路径**:
|
||||
|
||||
```
|
||||
① 核心城市站匹配 → ② 长租默认站 → ③ 城市匹配 → ④ SN历史 → ⑤ 全局兜底
|
||||
```
|
||||
|
||||
非长租工单(巡检等)在前 4 条全失败后,兜底到总仓。**短租不兜底长租站**(业务约束),长租逻辑完全不变。
|
||||
|
||||
7 个场景回归全通过。这个修复的本质是:**给"找不到"留一条明确的后路**,而不是让错误在午夜静默发生。
|
||||
|
||||
## 三、下午:文件服务要支持插件更新配置
|
||||
|
||||
另一个需求:文件上传 API 要支持"固定文件名",给插件做配置更新用。
|
||||
|
||||
原设计是安全优先的:存储名 UUID 化(不可预测),每次上传 URL 都变。但插件需要一个**固定 URL** 拉取最新配置。
|
||||
|
||||
解决:上传接口加一个 `name` 参数。
|
||||
|
||||
```bash
|
||||
curl -X POST https://file.example.com/api/upload \
|
||||
-H "X-Admin-Key: xxx" \
|
||||
-F "file=@plugin-config.json" \
|
||||
-F "name=plugin-config.json"
|
||||
# → URL 永久固定,同名覆盖更新
|
||||
```
|
||||
|
||||
关键在安全设计,三个防线缺一不可:
|
||||
|
||||
| 防线 | 作用 |
|
||||
|------|------|
|
||||
| 正则白名单 `[A-Za-z0-9._-]+` | 防路径穿越(`../../etc/passwd`) |
|
||||
| 扩展名白名单 | 防 `evil.php` 上传 |
|
||||
| 原子替换(先 .tmp 再 rename) | 防插件读到半写配置 |
|
||||
|
||||
测试 8 项全过:上传、覆盖、下载、路径穿越拒绝、危险扩展名拒绝、无密钥拒绝、UUID 默认模式兼容、特殊字符拒绝。
|
||||
|
||||
**设计原则**:固定名 = 公开文件,配置文件里绝不放敏感信息;要保护的文件继续用 UUID 模式。
|
||||
|
||||
## 四、贯穿全天:自动封禁 + 文档同步
|
||||
|
||||
### auto-ban:让封禁自动化
|
||||
|
||||
三台服务器每天被 SSH 爆破数百次。fail2ban 实时封单 IP,但攻击者换 IP 就绕过。写了 auto-ban 脚本部署到 cron:
|
||||
|
||||
```
|
||||
每小时执行 → 提取爆破/扫描 IP → 转 /24 网段 → 白名单过滤 → ufw 永久封禁
|
||||
```
|
||||
|
||||
首次执行封了 169 个攻击网段。从此**封禁不再需要人**。
|
||||
|
||||
### 文档技能同步:让"记住"变成制度
|
||||
|
||||
今天最大的架构决策不是技术,而是流程:把"改动即同步文档"固化为**三层铁律**(行为准则 → 工作流 → 项目开局),以后任何改动都必须同步 SKILL.md/README/CRON 等文档。
|
||||
|
||||
为什么?因为血的教训:改完代码忘更新文档 → 下次按旧文档操作 → 踩坑 → 再花时间排查。**文档不是可选项,是交付物的一部分**。
|
||||
|
||||
## 五、方法论沉淀
|
||||
|
||||
这一天做的事,可以抽象成一个公式:
|
||||
|
||||
```
|
||||
运维自动化 = 配置化(变化外置) + 自动化(重复交给机器) + 文档化(经验可传承)
|
||||
```
|
||||
|
||||
| 任务 | 变化是什么 | 配置化 | 自动化 |
|
||||
|------|-----------|:--:|:--:|
|
||||
| 派单通知加城市 | 城市列表 | ✅ JSON | ✅ 定时任务 |
|
||||
| 巡检找维修站 | 兜底规则 | ✅ 配置表 | ✅ 定时建单 |
|
||||
| 插件更新配置 | 文件内容 | ✅ 固定名参数 | ✅ 固定 URL 拉取 |
|
||||
| 封禁攻击者 | 攻击 IP | ✅ 白名单配置 | ✅ cron 脚本 |
|
||||
|
||||
三个案例的共同点:**人只需要声明"要什么",机器负责"怎么做"**。配置承载业务决策,代码承载执行逻辑,文档承载经验传承——三者解耦,各自演进。
|
||||
|
||||
## 总结
|
||||
|
||||
运维自动化的高级形态,不是写更多的脚本,而是**让变化发生在配置层**。
|
||||
|
||||
- 加一个城市 → 改 JSON,不改代码
|
||||
- 封一个网段 → 等 cron 自动执行,不手动操作
|
||||
- 更新一个配置 → 上传同名文件,URL 不变
|
||||
- 记住一个教训 → 固化进文档铁律,人人遵守
|
||||
|
||||
当变化不再需要改代码,系统就真正"长出了骨骼"。
|
||||
|
||||
---
|
||||
|
||||
*本文已脱敏,不含真实域名、IP、UUID 或凭证。*
|
||||
Reference in New Issue
Block a user