边缘设备也搞蓝绿部署?真正难的不是“切流”,而是“切错了怎么活”
边缘设备也搞蓝绿部署?真正难的不是“切流”,而是“切错了怎么活”
我是 Echo_Wish。
提到蓝绿部署,很多人的第一反应是:
“不就是准备两套环境,然后一键切换吗?”
在 Kubernetes、云服务器上,这事确实已经相当成熟。
但如果把场景换成边缘设备——工厂里的工业网关、摄像头、AGV、边缘服务器、门店终端、IoT 网关……
事情一下就没那么简单了。
因为云端部署失败,大不了回滚。
边缘设备部署失败,可能连回滚命令都发不进去。
这就是我今天特别想聊的一个问题:
在边缘设备上实现蓝绿部署,真正难的不是“怎么切换”,而是“切换失败以后,设备还能不能自己活下来”。
一、先别急着搞蓝绿,先搞清楚边缘环境有多“野”
传统服务器的部署流程可能是:
Git
↓
CI/CD
↓
构建镜像
↓
部署服务器
↓
健康检查
↓
流量切换
而边缘设备往往是:
云端
↓
互联网 / 5G / 专线
↓
边缘网关
↓
工控机
↓
设备
中间随便一个环节都有可能出问题。
比如:
- 网络突然断了
- 设备突然重启
- 磁盘空间不足
- 新版本启动失败
- CPU 被打满
- 内存泄漏
- MQTT 连接不上
- Docker 拉镜像失败
- 设备正在执行关键任务
- 云端下发升级命令,但是设备没收到
- 收到了升级命令,但升级过程中断电
所以边缘部署和云端部署有一个非常大的区别:
云端部署默认“控制面在线”,边缘部署必须默认“控制面随时可能失联”。
这也是蓝绿部署设计的第一原则。
不要把边缘设备当成一台永远在线的服务器。
二、所谓蓝绿部署,其实就是给自己留一条退路
我们假设设备当前运行的是:
Application V1
这就是蓝环境。
现在准备升级:
Application V2
我们不要直接:
停止 V1
↓
启动 V2
而是:
┌── Blue:V1
设备 ───┤
└── Green:V2
V1继续提供服务。
V2在旁边启动。
然后进行健康检查。
只有 V2:
启动成功
+
业务正常
+
依赖正常
+
运行稳定
之后,才把流量切过去。
最终:
┌── Blue:V1
设备 ───┤
└── Green:V2 ← 当前流量
如果 V2出问题:
Green挂了
↓
流量切回Blue
↓
V1继续工作
这就是蓝绿部署最核心的价值:
不是让升级更快,而是让升级失败时损失更小。
三、边缘设备蓝绿部署,我更推荐“目录 + 软链接”
如果你的边缘设备并没有 Kubernetes,也没有复杂的容器编排平台,其实完全没必要为了蓝绿部署硬上 K8s。
一个非常朴素的方法:
/opt/myapp/
├── releases/
│ ├── v1.0.0/
│ ├── v1.1.0/
│ └── v1.2.0/
│
├── blue -> releases/v1.1.0
├── green -> releases/v1.2.0
└── current -> blue
比如当前:
current -> blue
blue -> v1.1.0
green -> v1.2.0
服务启动时永远从:
/opt/myapp/current
读取程序。
这样升级的时候:
ln -sfn releases/v1.2.0 green
启动 Green。
测试完成以后:
ln -sfn green current
切换完成。
如果出现问题:
ln -sfn blue current
马上回滚。
这个方案看起来甚至有点“土”。
但我反而觉得:
边缘环境里,越简单的方案,越容易活得久。
四、真正关键的地方:不要“启动成功”就认为部署成功
这是很多系统最容易踩的坑。
比如:
./myapp
进程起来了。
然后:
部署成功!
这其实非常危险。
因为:
进程活着 ≠ 服务正常。
比如:
进程:正常
HTTP:正常
数据库:连接失败
MQTT:连接失败
摄像头:无法访问
模型:加载失败
这个时候如果你直接切流:
V1
↓
V2
那就是主动把生产环境送进坑里。
所以我建议至少设计三层健康检查。
第一层:进程检查
pgrep -f myapp
确认进程还活着。
第二层:接口检查
curl -f http://127.0.0.1:8080/health
例如返回:
{
"status": "UP"
}
第三层:业务检查
这个才是最重要的。
比如工业边缘设备:
GET /health/business
返回:
{
"status": "UP",
"database": "UP",
"mqtt": "UP",
"device": "UP",
"model": "UP"
}
只有全部正常,才允许切换。
代码可以简单写成:
check_health() {
for i in {1..30}
do
if curl -fs http://127.0.0.1:8081/health/business
then
echo "Green health check success"
return 0
fi
sleep 2
done
echo "Green health check failed"
return 1
}
这个思路非常重要:
部署系统负责“启动”,业务系统负责告诉部署系统“我到底能不能干活”。
五、别忘了:边缘设备最怕“半升级”
假设设备正在升级:
下载 V2
↓
解压
↓
停止 V1
↓
启动 V2
突然:
断电!
设备重新启动。
结果可能变成:
V1没了
V2也没装完整
这时候就比较刺激了。
所以升级包千万不要直接覆盖当前版本。
错误方式:
rm -rf /opt/myapp/*
tar -xzf app-v2.tar.gz -C /opt/myapp
正确方式应该是:
下载
↓
临时目录
↓
校验
↓
完整解压
↓
健康检查
↓
切换
比如:
mkdir -p /opt/myapp/releases/v1.2.0.tmp
tar -xzf app-v1.2.0.tar.gz \
-C /opt/myapp/releases/v1.2.0.tmp
然后校验:
sha256sum -c checksum.sha256
确认没问题以后再:
mv /opt/myapp/releases/v1.2.0.tmp \
/opt/myapp/releases/v1.2.0
永远不要直接碰正在运行的版本。
六、边缘蓝绿部署还有一个坑:配置文件
程序可以蓝绿。
但配置怎么办?
比如:
V1
数据库地址:DB_A
V2
数据库地址:DB_B
你切版本的时候,程序切过去了,但是配置没跟着切,就可能直接翻车。
所以我比较推荐:
/opt/myapp/
├── releases/
├── config/
│ ├── common.yaml
│ ├── blue.yaml
│ └── green.yaml
程序启动:
./myapp \
--config=/opt/myapp/config/green.yaml
配置和程序版本最好做到可追踪、可回滚。
更进一步,可以让每个 Release 自己带配置:
v1.1.0/
├── app
├── config.yaml
└── manifest.json
v1.2.0/
├── app
├── config.yaml
└── manifest.json
这样:
程序版本
+
配置版本
+
依赖版本
可以一起回滚。
七、我特别建议加一个“自动回滚”
这是整个边缘蓝绿部署里,我认为最值钱的功能。
比如:
Green启动
↓
健康检查
↓
通过
↓
切流
↓
观察5分钟
↓
发现异常
↓
自动回滚Blue
可以简单定义:
deploy_green
if ! check_health; then
rollback
exit 1
fi
switch_to_green
sleep 300
if ! check_business_metrics; then
rollback
fi
这里有个细节非常重要:
健康检查通过以后,也不能立刻认为部署成功。
为什么?
因为很多问题只有运行一段时间才暴露。
例如:
内存持续上涨
连接池泄漏
消息堆积
线程数不断增长
磁盘日志暴涨
所以最好设计:
启动检查
+
切流检查
+
观察窗口
三个阶段。
八、别把“蓝绿”理解成必须同时跑两套完整业务
这是很多人容易误解的地方。
边缘设备资源往往很有限。
比如:
CPU:4核
RAM:4GB
磁盘:64GB
你让 V1 和 V2 同时完整跑起来:
V1:2GB
V2:2GB
系统:1GB
直接把自己逼到 OOM。
所以实际工程中可以做成:
Blue:完整生产实例
Green:候选实例
Green启动时可以:
- 不接收生产流量
- 不启动部分高耗能模块
- 只进行核心业务验证
- 使用 Shadow Traffic
- 做关键接口测试
确认没问题之后,再正式切流。
也就是说:
蓝绿部署的核心是“隔离版本”,而不是“必须浪费两倍资源”。
九、如果用 Docker,其实会更舒服
如果边缘设备资源允许,Docker 会让这套方案更加清晰。
例如:
myapp:1.1.0
myapp:1.2.0
启动 Blue:
docker run -d \
--name myapp-blue \
-p 8081:8080 \
myapp:1.1.0
启动 Green:
docker run -d \
--name myapp-green \
-p 8082:8080 \
myapp:1.2.0
然后通过 Nginx 控制流量。
Blue:
upstream backend {
server 127.0.0.1:8081;
}
切到 Green:
upstream backend {
server 127.0.0.1:8082;
}
然后:
nginx -s reload
这样就形成:
┌── Blue :8081
Client → Nginx ──┤
└── Green :8082
回滚也非常简单。
十、但是边缘设备最关键的问题,其实不是技术,而是“失联”
假设:
云端
↓
升级指令
↓
边缘设备
升级到一半:
网络断开
怎么办?
我的答案是:
升级流程必须设计成“无需云端继续参与,也能完成或者回滚”。
也就是说,云端只负责:
告诉设备:
“你可以升级到 V2”
设备自己负责:
下载
↓
校验
↓
安装
↓
启动
↓
健康检查
↓
切换
↓
回滚
而不是:
云端:
下一步
设备:
收到
云端:
继续
设备:
收到
这种方式一旦断网,整套流程就卡死了。
十一、我比较推荐的边缘蓝绿部署架构
最终可以设计成这样:
云端控制平台
│
发布升级任务
│
▼
┌────────────────┐
│ Edge Agent │
│ 升级代理 │
└───────┬────────┘
│
┌────────┴────────┐
▼ ▼
Blue V1.1 Green V1.2
│ │
│ │
└──────┬──────────┘
▼
Health Check
│
┌─────┴─────┐
▼ ▼
Success Failed
│ │
▼ ▼
Switch Green Rollback
│
▼
Observe 5min
│
┌────┴────┐
▼ ▼
Stable Abnormal
│ │
▼ ▼
Complete Rollback
这里面其实有四个核心组件:
1. Edge Agent
负责升级、启动、停止、回滚。
2. Version Manager
负责管理:
当前版本
目标版本
上一个稳定版本
3. Health Checker
负责判断:
程序是不是活着
业务是不是正常
4. Watchdog
负责发现:
升级后异常
然后自动回滚。
十二、最后聊聊我对边缘蓝绿部署的一个看法
我一直觉得,很多工程师做部署系统的时候,特别喜欢追求“高级”。
什么:
Kubernetes
Service Mesh
Istio
GitOps
Multi Cluster
Progressive Delivery
这些东西当然好。
但是到了边缘场景,我反而建议大家先问自己三个问题:
设备断网怎么办?
设备断电怎么办?
新版本启动失败怎么办?
如果这三个问题还没有答案,那么你上再多平台,其实都只是把复杂度包装得更漂亮。
真正靠谱的边缘部署,我认为应该满足一个非常朴素的原则:
升级成功 → 新版本运行
升级失败 → 老版本继续运行
升级中断 → 重启后还能恢复
云端失联 → 设备还能自己完成流程
设备断电 → 不至于变砖
这才是边缘部署真正的“工程味”。
写在最后
蓝绿部署看起来是一个发布技术,实际上它解决的是一个更底层的问题:
我们有没有能力,让一次错误的发布,不至于变成一次事故?
云服务器可以靠人工救。
边缘设备往往不行。
尤其是那些部署在工厂、仓库、道路、矿区、门店甚至偏远地区的设备,你很难要求运维人员发现问题以后,立刻跑过去插根网线。
所以我越来越觉得:
边缘计算时代,部署系统的第一目标不是“发布得多快”,而是“出问题以后还能不能自己恢复”。
蓝绿部署只是手段。
真正值得追求的,其实是:
让设备拥有“犯错以后自己活下来”的能力。
这才是边缘运维真正该有的底气。
—— Echo_Wish
- 点赞
- 收藏
- 关注作者
评论(0)