
我是 Echo_Wish。
提到蓝绿部署,很多人的第一反应是:
“不就是准备两套环境,然后一键切换吗?”
在 Kubernetes、云服务器上,这事确实已经相当成熟。
但如果把场景换成边缘设备——工厂里的工业网关、摄像头、AGV、边缘服务器、门店终端、IoT 网关……
事情一下就没那么简单了。
因为云端部署失败,大不了回滚。
边缘设备部署失败,可能连回滚命令都发不进去。
这就是我今天特别想聊的一个问题:
在边缘设备上实现蓝绿部署,真正难的不是“怎么切换”,而是“切换失败以后,设备还能不能自己活下来”。
传统服务器的部署流程可能是:
Git
↓
CI/CD
↓
构建镜像
↓
部署服务器
↓
健康检查
↓
流量切换而边缘设备往往是:
云端
↓
互联网 / 5G / 专线
↓
边缘网关
↓
工控机
↓
设备中间随便一个环节都有可能出问题。
比如:
所以边缘部署和云端部署有一个非常大的区别:
云端部署默认“控制面在线”,边缘部署必须默认“控制面随时可能失联”。
这也是蓝绿部署设计的第一原则。
不要把边缘设备当成一台永远在线的服务器。
我们假设设备当前运行的是:
Application V1这就是蓝环境。
现在准备升级:
Application V2我们不要直接:
停止 V1
↓
启动 V2而是:
┌── Blue:V1
设备 ───┤
└── Green:V2V1继续提供服务。
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启动时可以:
确认没问题之后,再正式切流。
也就是说:
蓝绿部署的核心是“隔离版本”,而不是“必须浪费两倍资源”。
如果边缘设备资源允许,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
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。