【Kubernetes】使用StatefulSet进行的资源调度,有状态应用更新发布时,必须遵循的版本灰度:金丝雀发布,StatefulSet重建步骤

StatefulSet金丝雀发布实战:用Partition实现安全的版本灰度

在有状态应用的更新中,直接全量替换版本风险太高——一旦新镜像有问题,可能导致整个集群不可用。金丝雀发布(Canary Deployment)通过先更新部分实例验证,再逐步扩大范围,能极大降低风险。而StatefulSet的Partition(分区)功能,正是实现这种灰度更新的利器。本文结合我的实操过程,带你掌握这一核心技能。

一、什么是StatefulSet的金丝雀发布?

简单说,StatefulSet的金丝雀发布就是:通过配置Partition参数,控制只有部分Pod更新到新版本,其余仍保持旧版本。验证新版本没问题后,再调整Partition扩大更新范围,直到全量完成。

为什么必须用Partition
StatefulSet的Pod有严格序号(如web-0web-4),而Partition的作用是:

  • 序号 ≥ Partition的Pod:会被更新到新版本
  • 序号 < Partition的Pod:保持旧版本不变

这种按序号控制的方式,特别适合有状态应用(比如让序号大的从节点先更新,验证没问题再更新主节点)。

二、实战步骤:从准备到灰度更新

环境准备:先扩缩容到5个副本

首先我需要足够的实例来演示“部分更新”,所以先将副本数从2扩容到5:

# 扩容到5个副本(生成web-0到web-4)
kubectl scale sts web --replicas=5

# 查看Pod状态(确认所有实例正常运行)
kubectl get po
# 输出:
# NAME      READY   STATUS    RESTARTS   AGE
# web-0     1/1     Running   0          7h5m
# web-1     1/1     Running   0          42m
# web-2     1/1     Running   0          37s
# web-3     1/1     Running   0          36s
# web-4     1/1     Running   0          35s

此时所有Pod都使用旧版本镜像(nginx:1.7.9),可以通过describe命令确认:

# 查看任意Pod的镜像版本
kubectl describe po web-0 | grep "Image:"
# 输出:Image:         nginx:1.7.9

核心操作:配置Partition实现金丝雀更新

我的目标是:让序号3、4的Pod先更新到新版本(nginx:1.24.1),序号0、1、2保持旧版本。这需要通过Partition=3实现。

步骤1:编辑StatefulSet配置,设置Partition和新镜像
# 用edit命令进入交互式编辑
kubectl edit sts web

在编辑器中找到updateStrategy部分,添加partition: 3,并修改镜像为nginx:1.24.1

spec:
  updateStrategy:
    rollingUpdate:
      partition: 3  # 核心:只更新序号≥3的Pod
    type: RollingUpdate
  template:
    spec:
      containers:
      - name: nginx
        image: nginx:1.24.1  # 新版本镜像

保存退出后,Kubernetes会自动触发更新。

步骤2:观察更新结果——只有部分Pod更新

等待几分钟后查看Pod状态:

# 查看所有Pod的状态
kubectl get po
# 输出中可以看到:
# web-4     0/1     ContainerCreating   0          55s  (正在拉取新镜像)
# web-3     1/1     Running             0          5m15s(可能已更新或等待)
# web-2     1/1     Running             0          5m16s(保持旧版本)
# web-1     1/1     Running             0          47m  (保持旧版本)
# web-0     1/1     Running             0          7h10m (保持旧版本)

再通过describe确认镜像版本:

# 查看序号≥3的Pod(web-4)
kubectl describe po web-4 | grep "Image:"
# 输出:Image:         nginx:1.24.1 (已更新到新版本)

# 查看序号<3的Pod(web-2)
kubectl describe po web-2 | grep "Image:"
# 输出:Image:         nginx:1.7.9 (保持旧版本)

关键观察

  • web-3web-4(序号≥3)会被更新到nginx:1.24.1
  • web-0web-1web-2(序号<3)仍使用旧镜像nginx:1.7.9

这就是金丝雀发布的核心效果——只让部分实例验证新版本。

三、Partition参数的工作原理

很多初学者会疑惑:Partition=3为什么会只更新序号≥3的Pod?这需要结合StatefulSet的更新逻辑理解:

  1. StatefulSet更新时,会先创建新的控制器版本(Revision)
    新镜像会生成一个新的Revision,而Partition决定了哪些Pod会切换到这个新Revision。

  2. 序号与Partition的对比决定是否更新

    • Partition=N时:
      • 序号 ≥ N 的Pod:会被更新到新Revision(新版本)
      • 序号 < N 的Pod:保持在旧Revision(旧版本)
  3. 更新顺序仍遵循StatefulSet的规则
    即使设置了Partition,更新仍按“从高序号到低序号”进行(先更新web-4,再更新web-3),避免有状态应用的依赖关系被破坏。

四、常见问题与解决方案

问题1:设置Partition后,目标Pod未更新

我的web-4一度处于ContainerCreating状态,查看事件发现是镜像拉取中:

kubectl describe po web-4 | grep Events -A 10
# 输出:
# Normal  Pulling    85s   kubelet            Pulling image "nginx:1.24.1"

解决:耐心等待镜像拉取完成,或确认镜像名称正确(比如是否写成1.24而非1.24.1)。

问题2:如何扩大更新范围?

如果验证web-3web-4的新版本没问题,想继续更新web-2,只需调整Partition

# 再次编辑StatefulSet,将Partition改为2
kubectl edit sts web
# 修改:partition: 2

# 此时序号≥2的Pod(web-2、3、4)都会更新到新版本

问题3:新版本有问题,如何回滚?

如果发现web-4运行异常,需立即停止更新并回滚:

# 方法1:将镜像改回旧版本,Partition保持3(只回滚已更新的Pod)
kubectl edit sts web
# 修改image为nginx:1.7.9

# 方法2:如果需要全量回滚,将Partition设为0(所有Pod回滚)
kubectl edit sts web
# 修改partition: 0

五、实操命令总结

操作目的命令说明
准备环境(扩容)kubectl scale sts web --replicas=5生成足够的Pod用于灰度
配置金丝雀更新kubectl edit sts webupdateStrategy中添加partition: 3并修改镜像
查看Pod状态kubectl get po观察哪些Pod在更新/运行
确认镜像版本 kubectl describe po <pod名称> grep "Image:"验证是否按预期更新
扩大更新范围kubectl edit sts web减小Partition值(如从3→2)
回滚更新kubectl edit sts web将镜像改回旧版本,或调整Partition

六、初学者注意事项

  1. Partition是“序号阈值”,不是“数量”
    Partition=3不是“更新3个Pod”,而是“更新序号≥3的Pod”,别混淆“序号”和“数量”。

  2. 更新顺序仍为“从高到低”
    即使设置Partition=3,更新也会先web-4web-3,这是StatefulSet对有状态应用的保护。

  3. 镜像名称要准确
    实操中nginx:1.24.1是存在的,但nginx:1.9.1可能拉不下来,建议先在节点上用docker pull验证镜像是否可拉取。

  4. 逐步扩大范围更安全
    不要一次从Partition=3跳到Partition=0,建议按“3→2→1→0”逐步调整,每次验证后再扩大。

总结:StatefulSet金丝雀发布的核心价值

对于有状态应用(如数据库、分布式集群),金丝雀发布不是可选而是必需——它能在更新过程中保留“回退余地”。StatefulSet的Partition通过序号控制更新范围,完美适配有状态应用的依赖关系(比如先更新从节点,再更新主节点)。

掌握这个技能后,你可以:

  • 用少量实例验证新版本稳定性
  • 发现问题时快速缩小影响范围
  • 按可控节奏完成全量更新

记住:有状态应用的更新核心是“稳”,而Partition就是实现“稳”的关键工具。下次更新有状态应用时,不妨试试这种灰度方式,比直接全量更新安心多了。


StatefulSet的安全重建

一、安全删除StatefulSet的正确方法

直接删除StatefulSet会导致Pod被终止,但如果有持久化存储(PVC),数据卷不会被自动删除。为了彻底清理并重新开始,建议按以下步骤操作:

1. 先缩容到0,确保所有Pod优雅终止
# 将副本数缩容到0,让Pod优雅关闭
kubectl scale sts web --replicas=0

# 确认所有Pod已终止
kubectl get po | grep web
# 应该没有web-*的Pod显示
2. 删除StatefulSet资源,如果有service服务也要删除
# 删除StatefulSet(注意:不会删除PVC)
kubectl delete sts web

# 验证删除成功
kubectl get sts web
# 应该显示 "Error from server (NotFound)"
3. (可选)删除相关的PVC和PV(如果需要彻底清理数据)

如果你使用了持久化存储,且希望完全重置,可以删除相关的PVC:

# 查看是否有web相关的PVC
kubectl get pvc | grep web

# 如果有,逐个删除(注意:这会删除数据!)
kubectl delete pvc <pvc名称>

二、用web.yaml重新创建StatefulSet

确认所有资源已清理后,就可以用你的YAML文件重新部署:

# 检查web.yaml内容(确保镜像版本正确)
cat web.yaml

# 示例web.yaml内容(关键部分)
# spec:
#   replicas: 5  # 确认副本数
#   updateStrategy:
#     rollingUpdate:
#       partition: 3  # 按需调整Partition
#   template:
#     spec:
#       containers:
#       - name: nginx
#         image: nginx:1.24.1  # 确认镜像版本

# 应用配置创建StatefulSet
kubectl apply -f web.yaml

# 查看创建状态
kubectl get sts web -w
# 等待READY显示5/5

五、总结:StatefulSet重建的最佳实践

  1. 先缩容后删除:避免直接删除导致Pod强制终止
  2. 保留PVC:如果需要保留数据,不要删除PVC
  3. 检查YAML配置:重建前确认镜像版本、Partition等参数正确
  4. 预拉取镜像:提前在节点上拉取镜像,减少部署时间
  5. 验证部署结果:创建后检查Pod状态、镜像版本和事件日志

  • 总结
# 1. 先将StatefulSet缩容到0
kubectl scale sts web --replicas=0
kubectl get po -l app=nginx  # 确认所有web Pod已终止

# 2. 删除StatefulSet和Service(按资源类型和名称删除)
kubectl delete sts,svc web nginx

# 3. 验证删除结果
kubectl get sts,svc | grep -E 'web|nginx'
# 应该没有web和nginx相关的资源显示

# 4. 重建(使用更新后的配置文件)
kubectl apply -f web.yaml

# 5. 监控创建过程
kubectl get sts,svc,po -l app=nginx -w
# 等待所有Pod变为Running状态,Service就绪

https://github.com/0voice

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值