kubernetes中新功能StatefulSet实现功能与现阶段切换系统对比
目前docker的使用:
pod ip全网可以访问
双网卡绑定
namespace按库级别划分
chubaoDB:
master、router:ReplicationController
partitionserver:Pod
弹性数据库:
mysql实例Pod
老版 切换系统
与kubernetes弱偶和,通过双网卡实现跨namespace的pod间访问
将数据库作为无状态服务使用
1、数据本地存储,pod删除后数据即丢失
2、主从切换使用MHA
3、固定IP
4、域名切换需要依靠程序实现
5、依靠zabbix检测故障
6、添加从库需依赖dbs系统
与kubernetes强偶和
1、数据采用共享存储,pod删除后,数据不丢失即使node节点宕机,在合适的条件下,将拉起一个新的pod,数据不丢失
2、不再需要mha切换,完全依靠kebernetes
3、pod的ip不固定,主要依靠service提供对外服务(要想保持Pod IP不变,可以借助稳定的Pod hostname定制IPAM获取固定的Pod IP)
4、dbs资产管理信息简化,只需同步etcd中的信息即可
5、依靠zabbix的判断逻辑
6、添加从库只需要一条命令,将会自动选择从第n-1个节点同步数据
依赖kubernetes dns、node controller等,通过定义配置文件利用kubernetes自身提供的高可用机制
Note: StatefulSets are stable (GA) in 1.9.
Kubernetes1.9版本开始StatefulSets发布GA版本
有状态的服务:
稳定的、唯一的网络标识。
稳定的、持久的存储。
有序的、优雅的部署和伸缩。
有序的、优雅的删除和停止。
有序的、自动的滚动更新。
限制
1、共享存储
2、删除pod后,相关连的pv不会被删除,并且这些pv默认也不会被其他pvc bound
3、删除StatefulSets资源不影响pod,友好的删除pod,用缩容
4、稳定的网络标识
Pod Identity
StatefulSet Pods 拥有一个唯一的标识
Ordinal Index
如果StatefulSet有多个replicas,每个Pod将会按找个0~N-1编号
Stable Network ID
Cluster Domain Service (ns/name) StatefulSet (ns/name) StatefulSet Domain Pod DNS Pod Hostname
cluster.local default/nginx default/web nginx.default.svc.cluster.local web-{0…N-1}.nginx.default.svc.cluster.local web-{0…N-1}
cluster.local foo/nginx foo/web nginx.foo.svc.cluster.local web-{0…N-1}.nginx.foo.svc.cluster.local web-{0…N-1}
kube.local foo/nginx foo/web nginx.foo.svc.kube.local web-{0…N-1}.nginx.foo.svc.kube.local web-{0…N-1}
CNI网络模型
稳定的主要是针对Pod发生re-schedule后仍然要保持之前的网络标识和持久化存储。这里所说的网络标识包括hostname、集群内DNS中该Pod对应的A Record,并不能保证Pod re-schedule之后IP不变。要想保持Pod IP不变,我们可以借助稳定的Pod hostname定制IPAM获取固定的Pod IP。借助StatefulSet的稳定的唯一的网络标识特性,我们能比较轻松的实现Pod的固定IP需求,然后如果使用Deployment,那么将会复杂的多,你需要考虑滚动更新的过程中的参数控制(maxSurge、maxUnavailable)、每个应用的IP池预留造成的IP浪费等等问题。
StatefulSet的Pod管理策略
OrderedReady,StatefulSet的Pod默认管理策略,就是逐个的、顺序的进行部署、删除、伸缩,也是默认的策略。
Parallel,支持并行创建或者删除同一个StatefulSet下面的所有Pods,并不会逐个的、顺序的等待前一个操作确保成功后才进行下一个Pod的处理。其实用这种管理策略的场景非常少。
StatefulSet的更新策略
StatefulSet的更新策略(由.spec.updateStrategy.type指定)支持以下两种:
OnDelete, 含义同Deployment的OnDelete策略,大家应该很熟悉了,不多介绍。
RollingUpdate,滚动更新过程也跟Deployment大致相同,区别在于:
相当于Deployment的maxSurge=0,maxUnavailable=1(其实StatefulSet是不存在这两个配置的)
滚动更新的过程是有序的(逆序),index从N-1到0逐个依次进行,并且下一个Pod创建必须是前一个Pod Ready为前提,下一个Pod删除必须是前一个Pod shutdown并完全删除为前提。
支持部分实例滚动更新,部分不更新,通过.spec.updateStrategy.rollingUpdate.partition来指定一个index分界点。
所有ordinal大于等于partition指定的值的Pods将会进行滚动更新。
所有ordinal小于partition指定的值得Pods将保持不变。即使这些Pods被recreate,也会按照原来的pod template创建,并不会更新到最新的版本。
特殊地,如果partition的值大于StatefulSet的期望副本数N,那么将不会触发任何Pods的滚动更新。
安装部署:
非固定ip,依靠创建的service
步骤:
https://kubernetes.io/docs/tasks/run-application/run-replicated-stateful-application/
1、定义pv、pvc、StrogeClass
2、定义configmap
3、定义service
主库:headless service(不会分配clusterIP)
mysql-write
从库:常规service
mysql-read
4、定义statefulset
启动命令
kubectl create -f mysql-statefulset.yaml
NAME READY STATUS RESTARTS AGE mysql-0 2/2 Running 0 2m --主库 mysql-1 2/2 Running 0 1m --从库 mysql-2 2/2 Running 0 1m --从库
健康检查:
LivenessProbe探针
ReadinessProbe探针
根据statefulset中的定义
写操作连接mysql-write的service
读操作连接mysql-read的service
读操作在从库、主库实现负载均衡
5、管理操作
加从库:
kubectl scale statefulset mysql --replicas=5
删从库:
kubectl delete pod mysql-2
标记为unschedulable:
kubectl uncordon pod mysql-2
kubectl cordon pod mysql-2
故障处理:
1、Node网络异常等情况下该如何处理
https://kubernetes.io/docs/concepts/architecture/nodes/
Condition
The conditions field describes the status of all Running nodes.
Node Condition Description
OutOfDisk True if there is insufficient free space on the node for adding new pods, otherwise False
Ready True if the node is healthy and ready to accept pods, False if the node is not healthy and is not accepting pods, and Unknown if the node controller has not heard from the node in the last node-monitor-grace-period (default is 40 seconds)
MemoryPressure True if pressure exists on the node memory – that is, if the node memory is low; otherwise False
PIDPressure True if pressure exists on the processes – that is, if there are too many processes on the node; otherwise False
DiskPressure True if pressure exists on the disk size – that is, if the disk capacity is low; otherwise False
NetworkUnavailable True if the network for the node is not correctly configured, otherwise False
The node condition is represented as a JSON object. For example, the following response describes a healthy node.
“conditions”: [ {“type”: “Ready”,“status”: “True”} ]
如果Ready的status保持Unknown或False的时间超过pod-eviction-timeout,则会将参数传递给kube-controller-manager,节点控制器会调度该节点上的所有Pod以进行删除。 默认逐出超时持续时间为5分钟。 在某些情况下,当节点无法访问时,apiserver无法与节点上的kubelet通信。 在重新建立与apiserver的通信之前,不能将删除pod的决定传送到kubelet。 同时,计划删除的pod可以继续在分区节点上运行。
正常情况下,StatefulSet Controller会保证集群内同一namespace下不会出现多个相同network identity的StatefulSet Pods。
如果集群内出现以上情况,那么有可能导致该有状态应用不能正常工作、甚至出现数据丢失等致命问题。
如果你使用Kubernetes 1.5之前的版本,当Node Condition是NetworkUnavailable时,node controller会强制从apiserver中删除这个Node上的这些pods对象,这时StatefulSet Controller就会自动在其他Ready Nodes上recreate同identity的Pods。这样做其实风险是很大的,可能会导致有一段时间有多个相同network identity的StatefulSet Pods,可能会导致该有状态应用不能正常工作。所以尽量不要在Kubernetes 1.5之前的版本中使用StatefulSet,或者你明确知道这个风险并且无视它。
如果你使用Kubernetes 1.5+的版本,当Node Condition是NetworkUnavailable时,node controller不会强制从apiserver中删除这个Node上的这些pods对象,这些pods的state在apiserver中被标记Terminating或者Unknown,因此StatefulSet Controller并不会在其他Node上再recreate同identity的Pods。当你确定了这个Node上的StatefulSet Pods shutdown或者无法和该StatefulSet的其他Pods网络不同时,接下来就需要强制删除apiserver中这些unreachable pods object,然后StatefulSet Controller就能在其他Ready Nodes上recreate同identity的Pods,使得StatefulSet继续健康工作。
在Kubernetes 1.5+中,如何强制从apiserver中删除该StatefulSet pods呢?有如下三种方法:
如果Node永久的无法连接网络或者关机了,意味着能确定这个Node上的Pods无法与其他Pods通信了,不会对StatefulSet应用的可用性造成影响,那么建议手动从apiserver中删除该NetworkUnavailable的Node,Kubernetes会自动从apiserver中删除它上面的Pods object。
如果Node是因为集群网络脑裂导致的,则建议去检查网络问题并成功恢复,因为Pods state已经是Terminating或者Unkown,所以kubelet从apiserver中获取到这个信息后就会自动删除这些Pods。
其他情况才考虑直接手动从apiserver中删除这些Pods,因为这时你无法确定对应的Pods是否已经shutdown或者对StatefulSet应用无影响,强制删除后就可能导致出现同一namespace下有多个相同network identity的StatefulSet Pods,所以尽量不要使用这种方法。
kubectl delete pods --grace-period=0 --force
https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
Taint Nodes by Condition
在版本1.12中,TaintNodesByCondition功能发布beta版本,node lifecycle controller会自动创建与 node conditions相对应的taint(用于将特定的Pod调度到特定的Node的操作)。 类似地,调度程序不检查node conditions; 相反,调度程序检查taint。 这可确保node conditions不会影响节点上的调度。 用户可以选择通过添加 Pod tolerations来忽略一些Node的问题(Node conditions中所列出的)。 Note that TaintNodesByCondition only taints nodes with NoSchedule effect。 由TaintBasedEviction控制的NoExecute effect的功能,目前是一个测试版功能,默认情况下从版本1.13开始启用。
2:删除集群时必须是先暂停后删除,暂停至少三天后自动删除;
可以根据StatefulSets的特性,将pod删除(此时对应的pv不会删除),三天后再删除pv
3:故障扩容要考虑重启的情况,当容器或宿主机重启时不做扩容,实例不可用30分钟以上自动触发扩容;
LivenessProbe探针,用与判断容器是否健康,告诉kubelet一个容器什么时候处于不健康的状态,。如果LivenessProbe探针探测到容器不健康,则kubelet将删除该容器,并根据容器的重启策略做相应的处理
三种实现方式:
1)ExecAction:在容器内部执行一个命令,如果该命令的退出状态码为0,则表明容器健康
2)TCPSocketAction:通过容器的IP地址和端口号执行TCP检查,如果端口能被访问,则表明容器健康
3)HTTPGetAction:通过容器的IP地址和端口号及路径调用HTTP Get方法,如果响应的状态码大于等于200且小与400,则认为容器状态健康
ReadinessProbe探针,用于判断容器是否启动完成,且准备接受请求。如果ReadinessProbe探针检测到失败,则Pod的状态将被修改,Endpoint Controller将从Service的Endpoint中删除包含该容器所在Pod的IP地址的Endpoint条目
4:扩容必须要考虑监控、备份、资产信息变更,老的状态置为下线,三天后执行实例层面的实际删除;
针对etcd中存储的信息做watch
5:分布式故障检测,防止网络或是整个机柜断电等操作。
需确保Kubernetes集群的可靠
官方版本中service对外提供服务
https://kubernetes.io/docs/concepts/services-networking/service/
ClusterIP:在集群内部IP上公开服务。 选择此值使服务只能从群集中访问。 这是默认的ServiceType
NodePort:在静态端口(NodePort)上在每个节点的IP上公开服务。 将自动创建NodePort服务将路由到的ClusterIP服务。 您将能够通过请求:从群集外部联系NodePort服务:
LoadBalancer:使用云提供商的负载均衡器在外部公开服务。 将自动创建外部负载均衡器将路由到的NodePort和ClusterIP服务。
ExternalName:通过返回带有值的CNAME记录,将服务映射到externalName字段的内容(例如foo.bar.example.com)。 没有设置任何类型的代理。 这需要版本1.7或更高版本的kube-dns。
https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/
traefik-ingress-controller
nginx-ingress-controller
分别解决http和tcp协议服务的外部暴露问题。