kubernetes中有状态应用的优雅缩容
将有状态的应用程序部署到Kubernetes是棘手的。 StatefulSet使它变得容易得多,但是它们仍然不能解决所有问题。最大的挑战之一是如何缩小StatefulSet而不将数据留在断开连接的PersistentVolume成为孤立对象上。在这篇博客中,我将描述该问题和两种可能的解决方案。
通过StatefulSet创建的每个Pod都有自己的PersistentVolumeClaim(PVC)和PersistentVolume(PV)。当按一个副本按比例缩小StatefulSet的大小时,其Pod之一将终止,但关联的PersistentVolumeClaim和绑定到其的PersistentVolume保持不变。在随后扩大规模时,它们会重新连接到Pod。
Scaling a StatefulSet
现在,想象一下使用StatefulSet部署一个有状态的应用程序,其数据在其pod中进行分区。每个实例仅保存和处理一部分数据。当您缩小有状态应用的规模时,其中一个实例将终止,其数据应重新分配到其余的Pod。如果您不重新分配数据,则在再次进行扩展之前,它仍然不可访问。
Redistributing data on scale-down
在正常关机期间重新分发数据
您可能会想:“既然Kubernetes支持Pod正常关闭的机制,那么Pod是否可以在关闭过程中简单地将其数据重新分配给其他实例呢?”事实上,它不能。为什么不这样做有两个原因:
- Pod(或更确切地说,其容器)可能会收到除缩容以外的其他原因的终止信号。容器中运行的应用程序不知道为什么终止该程序,因此不知道是否要清空数据。
- 即使该应用程序可以区分是缩容还是由于其他原因而终止,它也需要保证即使经过数小时或数天也可以完成关闭程序。 Kubernetes不提供该保证。如果应用程序进程在关闭过程中死掉,它将不会重新启动,因此也就没有机会完全分发数据。
因此,相信在正常关闭期间Pod能够重新分发(或以其他方式处理其所有数据)并不是一个好主意,并且会导致系统非常脆弱。
使用 tear-down 容器?
如果您不是Kubernetes的新手,那么你很可能知道什么是初始化容器。它们在容器的主要容器之前运行,并且必须在主要容器启动之前全部完成。
如果我们有tear-down容器(类似于init容器),但是在Pod的主容器终止后又会运行,该怎么办?他们可以在我们的有状态Pod中执行数据重新分发吗?
假设tear-down容器能够确定Pod是否由于缩容而终止。并假设Kubernetes(更具体地说是Kubelet)将确保tear-down容器成功完成(通过在每次返回非零退出代码时重新启动它)。如果这两个假设都成立,我们将拥有一种机制,可确保有状态的容器始终能够按比例缩小规模重新分配其数据。
但是?
可悲的是,当tear-down容器本身发生瞬态错误,并且一次或多次重新启动容器最终使它成功完成时,像上述的tear-down容器机制将只处理那些情况。但是,在tear-down过程中托管Pod的集群节点死掉的那些不幸时刻又如何呢?显然,该过程无法完成,因此无法访问数据。
现在很明显,我们不应该在Pod关闭时执行数据重新分配。相反,我们应该创建一个新的Pod(可能安排在一个完全不同的集群节点上)以执行重新分发过程。
这为我们带来了以下解决方案:
缩小StatefulSet时,必须创建一个新的容器并将其绑定到孤立的PersistentVolumeClaim。我们称其为“drain pod”,因为它的工作是将数据重新分发到其他地方(或以其他方式处理)。Pod必须有权访问孤立的数据,并且可以使用它做任何想做的事情。由于每个应用程序的重新分发程序差异很大,因此新的容器应该是完全可配置的-用户应该能够在drain Pod内运行他们想要的任何容器。
StatefulSet Drain Controller
由于StatefulSet控制器当前尚不提供此功能,因此我们可以实现一个额外的控制器,其唯一目的是处理StatefulSet缩容。我最近实现了这种控制器的概念验证。您可以在GitHub上找到源代码:
luksa/statefulset-scaledown-controllergithub.com
下面我们解释一下它是如何工作的。
在将控制器部署到Kubernetes集群后,您只需在StatefulSet清单中添加注释,即可将drain容器模板添加到任何StatefulSet中。这是一个例子:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: datastore
annotations:
statefulsets.kubernetes.io/drainer-pod-template: |
{
"metadata": {
"labels": {
"app": "datastore-drainer"
}
},
"spec": {
"containers": [
{
"name": "drainer",
"image": "my-drain-container",
"volumeMounts": [
{
"name": "data",
"mountPath": "/var/data"
}
]
}
]
}
}
spec:
...
该模板与StatefulSet中的主要Pod模板没有太大区别,只不过它是通过注释定义的。您可以像平常一样部署和扩展StatefulSet。
当控制器检测到按比例缩小了StatefulSet时,它将根据指定的模板创建新的drain容器,并确保将其绑定到PersistentVolumeClaim,该PersistentVolumeClaim先前已绑定至因按比例缩小而删除的有状态容器。
Drain容器获得与已删除的有状态容器相同的身份(即名称和主机名)。这样做有两个原因:
- 一些有状态的应用程序需要稳定的身份-这也可能在数据重新分发过程中适用。
- 如果在执行drain过程时再次扩容StatefulSet,则这将阻止StatefulSet控制器创建重复的容器并将其附加到同一PVC。
如果drain pod或其主机节点崩溃,则drain pod将重新安排到另一个节点上,在该节点上可以重试/恢复其操作。Drain pod完成后, Pod和PVC将被删除。备份StatefulSet时,将创建一个新的PVC。
示例
首先部署drain控制器:
$ kubectl apply -f https://raw.githubusercontent.com/luksa/statefulset-drain-controller/master/artifacts/cluster-scoped.yaml
接着部署示例StatefulSet:
$ kubectl apply -f https://raw.githubusercontent.com/luksa/statefulset-drain-controller/master/example/statefulset.yaml
这将运行三个有状态的Pod。将StatefulSet缩小为两个时,您会看到其中一个Pod开始终止。然后,删除Pod后,drain控制器将立即创建一个具有相同名称的新drain Pod:
$ kubectl scale statefulset datastore --replicas 2
statefulset.apps/datastore scaled
$ kubectl get po
NAME READY STATUS RESTARTS AGE
datastore-0 1/1 Running 0 3m
datastore-1 1/1 Running 0 2m
datastore-2 1/1 Terminating 0 49s
$ kubectl get po
NAME READY STATUS RESTARTS AGE
datastore-0 1/1 Running 0 3m
datastore-1 1/1 Running 0 3m
datastore-2 1/1 Running 0 5s <-- the drain pod
当drain pod 完成其工作时,控制器将其删除并删除PVC:
$ kubectl get po
NAME READY STATUS RESTARTS AGE
datastore-0 1/1 Running 0 3m
datastore-1 1/1 Running 0 3m
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ...
data-datastore-0 Bound pvc-57224b8f-... 1Mi ...
data-datastore-1 Bound pvc-5acaf078-... 1Mi ...
控制器的另一个好处是它可以释放PersistentVolume,因为它不再受PersistentVolumeClaim约束。如果您的集群在云环境中运行,则可以降低存储成本。
总结
请记住,这仅是概念验证。要成为StatefulSet缩容问题的正确解决方案,需要进行大量工作和测试。理想情况下,Kubernetes StatefulSet控制器本身将支持这样的运行drain容器,而不是需要一个与原始控制器竞争的附加控制器(当您缩容并立即再次扩容时)。
通过将此功能直接集成到Kubernetes中,可以在StatefulSet规范中用常规字段替换注释,因此它将具有模板,volumeClaimTemplates
和rainePodTemplate
,与使用注释相比,一切都变得更好了。
kubernetes中有状态应用的优雅缩容的更多相关文章
- Kubernetes 笔记 11 Pod 扩容与缩容 双十一前后的忙碌
本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. Hi,大家好, ...
- kubernetes常用命令:缩容扩容回滚
查看版本 kubectl version 查看节点 kubectl get nodes 部署app 说明: 提供deployment名称和app镜像地址(docker镜像地址) kubectl run ...
- 从零入门 Serverless | Serverless Kubernetes 应用部署及扩缩容
作者 | 邓青琳(轻零) 阿里云技术专家 导读:本文分为三个部分,首先给大家演示 Serverless Kubernetes 集群的创建和业务应用的部署,其次介绍 Serverless Kuberne ...
- kubernetes命令式容器应用编排/部署应用/探查应用详情/部署service对象/扩缩容/修改删除对象
部署Pod应用 创建delpoyment控制器对象 [root@master ~]# kubectl run myapp --image=ikubernetes/myapp:v1 --port=80 ...
- Airbnb的动态kubernetes集群扩缩容
Airbnb的动态kubernetes集群扩缩容 本文介绍了Airbnb的集群扩缩容的演化历史,以及当前是如何通过Cluster Autoscaler 实现自定义扩展器的.最重要的经验就是Airbnb ...
- Kubernetes 笔记 012 Pod 的自动扩容与缩容
本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. Hi,大家好, ...
- Docker Kubernetes 容器扩容与缩容
Docker Kubernetes 容器扩容与缩容 环境: 系统:Centos 7.4 x64 Docker版本:18.09.0 Kubernetes版本:v1.8 管理节点:192.168.1.79 ...
- Kubernetes 监控:Prometheus Adpater =》自定义指标扩缩容
使用 Kubernetes 进行容器编排的主要优点之一是,它可以非常轻松地对我们的应用程序进行水平扩展.Pod 水平自动缩放(HPA)可以根据 CPU 和内存使用量来扩展应用,前面讲解的 HPA 章节 ...
- Kubernetes有状态应用管理——PetSet
目录贴:Kubernetes学习系列 1.介绍 在Kubernetes中,大多数的Pod管理都是基于无状态.一次性的理念.例如Replication Controller,它只是简单的保证可提供服务的 ...
随机推荐
- HTML5 QRCode Scaner
HTML5 QRCode Scaner how to scan QR Code using the camera of the phone or website live demo https://c ...
- HTTP/3 protocol
HTTP/3 protocol https://caniuse.com/#feat=http3 HTTP/3 H3 https://en.wikipedia.org/wiki/HTTP/3 QUIC ...
- Flutter: MediaQuery
Flutter Widget of the Week 使用MediaQuery根据不同的屏幕大小调整应用程序的UI布局. 您还可以使用它根据用户布局首选项进行UI调整. class _MyHomeSt ...
- java数据类型(进阶篇)
public class note03 { public static void main(String[] args) { //数据类型拓展 //1.整数拓展 //进制: 二进制0b 十进制 八进制 ...
- 大小厂必问Java后端面试题(含答案)
你好,我是yes. 这个系列的文章不会是背诵版,不是那种贴上标准答案,到时候照着答就行的面试题汇总. 我会用大白话尽量用解释性.理解性的语言来回答,但是肯定没有比平时通过一篇文章来讲解清晰,不过我尽量 ...
- DCL之单例模式
所谓的DCL 就是 Double Check Lock,即双重锁定检查,在了解DCL在单例模式中如何应用之前,我们先了解一下单例模式.单例模式通常分为"饿汉"和"懒汉&q ...
- sqlyog如何增删改查?
转: sqlyog如何增删改查? 下面是一道完整的 sqlyog 增删改查的练习, 顺着做下去,可以迅速掌握. 1. 创建部门表dept,并插入数据: 2. 创建emp员工表,并插入数据: sql 代 ...
- 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 Offer 21 这题的解法其实是考察快慢指针和头尾指针. package com.walegarrett.offer; /** * @Aut ...
- PAT-1064(Complete Binary Search Tree)JAVA实现
Complete Binary Search Tree PAT-1064 本次因为涉及到完全二叉排序树,所以可以使用数组的形式来存储二叉排序树 对输入序列排序后,得到的是中序遍历二叉排序树的序列.对这 ...
- 用java输出"Hello,World!"
Hello,World! 一般步骤 随便新建一个文件夹,存放代码 新建一个java文件 新建.txt文档 文件后缀名改为.java Hello.java [注意]系统可能没有显示后缀名,我们需要手动打 ...