想学习更多相关知识请看博主的个人博客地址:https://blog.huli.com/

https://blog.huli.com/

在Kubernetes系统中,Pod的管理对象RC、Deployment、DaemonSet 和Job都面向无状态的服务。但现实中有很多服务是有状态的,特别是 一些复杂的中间件集群,例如MySQL集群、MongoDB集群、Akka集 群、ZooKeeper集群等,这些应用集群有4个共同点。

(1)每个节点都有固定的身份ID,通过这个ID,集群中的成员可 以相互发现并通信。

(2)集群的规模是比较固定的,集群规模不能随意变动。

(3)集群中的每个节点都是有状态的,通常会持久化数据到永久 存储中。

(4)如果磁盘损坏,则集群里的某个节点无法正常运行,集群功 能受损。

如果通过RC或Deployment控制Pod副本数量来实现上述有状态的集 群,就会发现第1点是无法满足的,因为Pod的名称是随机产生的,Pod 的IP地址也是在运行期才确定且可能有变动的,我们事先无法为每个 Pod都确定唯一不变的ID。另外,为了能够在其他节点上恢复某个失败 的节点,这种集群中的Pod需要挂接某种共享存储,为了解决这个问 题,Kubernetes从1.4版本开始引入了PetSet这个新的资源对象,并且在 1.5版本时更名为StatefulSet,StatefulSet从本质上来说,可以看作 Deployment/RC的一个特殊变种,它有如下特性。

  • StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来 发现集群内的其他成员。假设StatefulSet的名称为kafka,那么第1个Pod 叫kafka-0,第2个叫kafka-1,以此类推。
  • StatefulSet控制的Pod副本的启停顺序是受控的,操作第n个Pod 时,前n-1个Pod已经是运行且准备好的状态。
  • StatefulSet里的Pod采用稳定的持久化存储卷,通过PV或PVC来 实现,删除Pod时默认不会删除与StatefulSet相关的存储卷(为了保证数 据的安全)。
  • StatefulSet除了要与PV卷捆绑使用以存储Pod的状态数据,还要与 Headless Service配合使用,即在每个StatefulSet定义中都要声明它属于 哪个Headless Service。Headless Service与普通Service的关键区别在于, 它没有Cluster IP,如果解析Headless Service的DNS域名,则返回的是该 Service对应的全部Pod的Endpoint列表。StatefulSet在Headless Service的 基础上又为StatefulSet控制的每个Pod实例都创建了一个DNS域名,这个 域名的格式为:
	$(podname).$(headless service name)

比如一个3节点的Kafka的StatefulSet集群对应的Headless Service的名 称为kafka,StatefulSet的名称为kafka,则StatefulSet里的3个Pod的DNS 名称分别为kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,这些DNS名称 可以直接在集群的配置文件中固定下来

1 简单示例

以一个简单的 nginx 服务 web.yaml为例:

apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
(base) [root@liuxinyuan-master yaml]$ kubectl create -f web.yaml
service "nginx" created
statefulset "web" created # 查看创建的 headless service 和 statefulset
(base) [root@liuxinyuan-master yaml]$kubectl get service nginx
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx None <none> 80/TCP 1m
(base) [root@liuxinyuan-master yaml]$ kubectl get statefulset web
NAME DESIRED CURRENT AGE
web 2 2 2m # 根据 volumeClaimTemplates 自动创建 PVC(在 GCE 中会自动创建 kubernetes.io/gce-pd 类型的 volume)
(base) [root@liuxinyuan-master yaml]$kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESSMODES AGE
www-web-0 Bound pvc-d064a004-d8d4-11e6-b521-42010a800002 1Gi RWO 16s
www-web-1 Bound pvc-d06a3946-d8d4-11e6-b521-42010a800002 1Gi RWO 16s # 查看创建的 Pod,他们都是有序的
(base) [root@liuxinyuan-master yaml]$ kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 5m
web-1 1/1 Running 0 4m # 使用 nslookup 查看这些 Pod 的 DNS
(base) [root@liuxinyuan-master yaml]$ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
/ # nslookup web-0.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.nginx
Address 1: 10.244.2.10
/ # nslookup web-1.nginx
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.nginx
Address 1: 10.244.3.12
/ # nslookup web-0.nginx.default.svc.cluster.local
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.nginx.default.svc.cluster.local
Address 1: 10.244.2.10

还可以进行其他的操作

# 扩容
(base) [root@liuxinyuan-master yaml]$ kubectl scale statefulset web --replicas=5 # 缩容
(base) [root@liuxinyuan-master yaml]$ kubectl patch statefulset web -p '{"spec":{"replicas":3}}' # 镜像更新(目前还不支持直接更新 image,需要 patch 来间接实现)
(base) [root@liuxinyuan-master yaml]$ kubectl patch statefulset web --type='json' -p='[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"gcr.io/google_containers/nginx-slim:0.7"}]' # 删除 StatefulSet 和 Headless Service
(base) [root@liuxinyuan-master yaml]$ kubectl delete statefulset web
(base) [root@liuxinyuan-master yaml]$ kubectl delete service nginx # StatefulSet 删除后 PVC 还会保留着,数据不再使用的话也需要删除
(base) [root@liuxinyuan-master yaml]$ kubectl delete pvc www-web-0 www-web-1

2 更新 StatefulSet

v1.7 + 支持 StatefulSet 的自动更新,通过 spec.updateStrategy 设置更新策略。目前支持两种策略

  • OnDelete:当 .spec.template 更新时,并不立即删除旧的 Pod,而是等待用户手动删除这些旧 Pod 后自动创建新 Pod。这是默认的更新策略,兼容 v1.6 版本的行为
  • RollingUpdate:当 .spec.template 更新时,自动删除旧的 Pod 并创建新 Pod 替换。在更新时,这些 Pod 是按逆序的方式进行,依次删除、创建并等待 Pod 变成 Ready 状态才进行下一个 Pod 的更新。

2.1 Partitions

RollingUpdate 还支持 Partitions,通过 .spec.updateStrategy.rollingUpdate.partition 来设置。当 partition 设置后,只有序号大于或等于 partition 的 Pod 会在 .spec.template 更新的时候滚动更新,而其余的 Pod 则保持不变(即便是删除后也是用以前的版本重新创建)。

# 设置 partition 为 3
(base) [root@liuxinyuan-master yaml]$ kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
statefulset "web" patched # 更新 StatefulSet
(base) [root@liuxinyuan-master yaml]$ kubectl patch statefulset web --type='json' -p='[{"op":"replace","path":"/spec/template/spec/containers/0/image","value":"gcr.io/google_containers/nginx-slim:0.7"}]'
statefulset "web" patched # 验证更新
(base) [root@liuxinyuan-master yaml]$ kubectl delete po web-2
pod "web-2" deleted
(base) [root@liuxinyuan-master yaml]$ kubectl get po -lapp=nginx -w
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 4m
web-1 1/1 Running 0 4m
web-2 0/1 ContainerCreating 0 11s
web-2 1/1 Running 0 18s

3 Pod 管理策略

v1.7 + 可以通过 .spec.podManagementPolicy 设置 Pod 管理策略,支持两种方式

  • OrderedReady:默认的策略,按照 Pod 的次序依次创建每个 Pod 并等待 Ready 之后才创建后面的 Pod
  • Parallel:并行创建或删除 Pod(不等待前面的 Pod Ready 就开始创建所有的 Pod)

3.1 Parallel 示例

---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
podManagementPolicy: "Parallel"
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi

可以看到,所有 Pod 是并行创建的

(base) [root@liuxinyuan-master yaml]$ kubectl create -f webp.yaml
service "nginx" created
statefulset "web" created (base) [root@liuxinyuan-master yaml]$ kubectl get po -lapp=nginx -w
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-0 0/1 ContainerCreating 0 0s
web-1 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 10s
web-1 1/1 Running 0 10s

4 部署zookeeper

另外一个更能说明 StatefulSet 强大功能的示例为 zookeeper.yaml。

---
apiVersion: v1
kind: Service
metadata:
name: zk-headless
labels:
app: zk-headless
spec:
ports:
- port: 2888
name: server
- port: 3888
name: leader-election
clusterIP: None
selector:
app: zk
---
apiVersion: v1
kind: ConfigMap
metadata:
name: zk-config
data:
ensemble: "zk-0;zk-1;zk-2"
jvm.heap: "2G"
tick: "2000"
init: "10"
sync: "5"
client.cnxns: "60"
snap.retain: "3"
purge.interval: "1"
---
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: zk-budget
spec:
selector:
matchLabels:
app: zk
minAvailable: 2
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: zk
spec:
serviceName: zk-headless
replicas: 3
template:
metadata:
labels:
app: zk
annotations:
pod.alpha.kubernetes.io/initialized: "true"
scheduler.alpha.kubernetes.io/affinity: >
{
"podAntiAffinity": {
"requiredDuringSchedulingRequiredDuringExecution": [{
"labelSelector": {
"matchExpressions": [{
"key": "app",
"operator": "In",
"values": ["zk-headless"]
}]
},
"topologyKey": "kubernetes.io/hostname"
}]
}
}
spec:
containers:
- name: k8szk
imagePullPolicy: Always
image: gcr.io/google_samples/k8szk:v1
resources:
requests:
memory: "4Gi"
cpu: "1"
ports:
- containerPort: 2181
name: client
- containerPort: 2888
name: server
- containerPort: 3888
name: leader-election
env:
- name : ZK_ENSEMBLE
valueFrom:
configMapKeyRef:
name: zk-config
key: ensemble
- name : ZK_HEAP_SIZE
valueFrom:
configMapKeyRef:
name: zk-config
key: jvm.heap
- name : ZK_TICK_TIME
valueFrom:
configMapKeyRef:
name: zk-config
key: tick
- name : ZK_INIT_LIMIT
valueFrom:
configMapKeyRef:
name: zk-config
key: init
- name : ZK_SYNC_LIMIT
valueFrom:
configMapKeyRef:
name: zk-config
key: tick
- name : ZK_MAX_CLIENT_CNXNS
valueFrom:
configMapKeyRef:
name: zk-config
key: client.cnxns
- name: ZK_SNAP_RETAIN_COUNT
valueFrom:
configMapKeyRef:
name: zk-config
key: snap.retain
- name: ZK_PURGE_INTERVAL
valueFrom:
configMapKeyRef:
name: zk-config
key: purge.interval
- name: ZK_CLIENT_PORT
value: "2181"
- name: ZK_SERVER_PORT
value: "2888"
- name: ZK_ELECTION_PORT
value: "3888"
command:
- sh
- -c
- zkGenConfig.sh && zkServer.sh start-foreground
readinessProbe:
exec:
command:
- "zkOk.sh"
initialDelaySeconds: 15
timeoutSeconds: 5
livenessProbe:
exec:
command:
- "zkOk.sh"
initialDelaySeconds: 15
timeoutSeconds: 5
volumeMounts:
- name: datadir
mountPath: /var/lib/zookeeper
securityContext:
runAsUser: 1000
fsGroup: 1000
volumeClaimTemplates:
- metadata:
name: datadir
annotations:
volume.alpha.kubernetes.io/storage-class: anything
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 20Gi
(base) [root@liuxinyuan-master yaml]$ kubectl create -f zookeeper.yaml

详细的使用说明见 zookeeper stateful application

StatefulSet 注意事项

  1. 推荐在 Kubernetes v1.9 或以后的版本中使用
  2. 所有 Pod 的 Volume 必须使用 PersistentVolume 或者是管理员事先创建好
  3. 为了保证数据安全,删除 StatefulSet 时不会删除 Volume
  4. StatefulSet 需要一个 Headless Service 来定义 DNS domain,需要在 StatefulSet 之前创建好

kubernetes StatefulSet控制器的更多相关文章

  1. (十一)Kubernetes StatefulSet控制器

    StatefulSet介绍 前面使用Deployment创建的Pod是无状态的,当挂载了volume之后,如果该Pod挂了,Replication Controller会再启动一个Pod来保证可用性, ...

  2. Kubernetes学习之路(十七)之statefulset控制器

    目录 一.statefulset简介 二.为什么要有headless?? 三.为什么要 有volumeClainTemplate?? 四.statefulSet使用演示 (1)查看statefulse ...

  3. kubernetes学习控制器之StatefulSet控制器

    StatefulSet介绍 一.StatefulSet概述 StatefulSet是用来管理stateful(有状态)应用的StatefulSet管理Pod时,确保Pod有一个按序增长的ID与Depl ...

  4. Kubernetes 学习14 kubernetes statefulset

    一.概述 1.在应用程序中我们有两类,一种是有状态一种是无状态.此前一直演示的是deployment管理的应用,比如nginx或者我们自己定义的myapp它们都属于无状态应用. 2.而对于有状态应用, ...

  5. 5.深入k8s:StatefulSet控制器

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 在上一篇中,讲解了容器持久化存储,从中我们知道什么是PV和PVC,这一篇我们讲通过Sta ...

  6. 容器编排系统K8s之StatefulSet控制器

    前文我们聊到了k8s的configmap和secret资源的说明和相关使用示例,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14194944.html:今天 ...

  7. k8s StatefulSet控制器-独立存储

    k8s-StatefulSet控制器-独立存储 1. StatefulSet控制器-独立存储 独享存储:StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当 ...

  8. 9、kubernetes之statefulset控制器

    一.StatefulSet 有状态副本集 必要的三个组件:headless service.StatefulSet.volumeClaimTemplate 准备pv apiVersion: v1 ki ...

  9. (六)Kubernetes Pod控制器-ReplicaSet和Deployment和DaemonSet

    Pod控制器相关知识 控制器的必要性 自主式Pod对象由调度器调度到目标工作节点后即由相应节点上的kubelet负责监控其容器的存活状态,容器主进程崩溃后,kubelet能够自动重启相应的容器.但对出 ...

随机推荐

  1. 1.kafka

    什么是Kafka  1.Apache Kafka是一个开源消息系统,由Scala写成. 2.Kafka是一个分布式消息队列.Kafka对消息保存时根据Topic进行归类,发送消息者称为Producer ...

  2. 如何使用 pytorch 实现 yolov3

    前言 看了 Yolov3 的论文之后,发现这论文写的真的是很简短,神经网络的具体结构和损失函数的公式都没有给出.所以这里参考了许多前人的博客和代码,下面进入正题. 网络结构 Yolov3 将主干网络换 ...

  3. IntelliJ IDEA 中文官方文档

    目录 认识IntelliJ IDEA IntelliJ IDEA 安装和设置 IntelliJ IDEA如何使用 IntelliJ IDEA中不容错过的快捷键 IntelliJ IDEA专业的使用技巧 ...

  4. CKKS加密方案

    本文内容来自"Protecting Privacy throughHomomorphic Encryption",主要学习里面的CKKS部分. CKKS是一种同态加密方案,其安全性 ...

  5. JS RegExp对象(正则表达式)

    笔记整理自:廖雪峰老师的JS教程 正则表达式语法:https://www.runoob.com/regexp/regexp-tutorial.html 目录 创建方式 方式一 方式二 简单使用 判断正 ...

  6. C 字符串奇数位小写字母转大写

    如题 C实现 #include<stdio.h> #include<string.h> #define COUNT 20 //最大接受字符串数,可以使用动态获取空间函数优化 v ...

  7. OC和C对比

    1.源文件对比 C语言中常见源文件.h头文件,.c文件 文件扩展名 源类型 .h 头文件,用于存放函数声明 .c C语言源文件,用于实现头文件中声明的方法 OC中的源文件.h头文件,.m与.mm的实现 ...

  8. K8s多节点部署+负载均衡+keepalived ——囊萤映雪

    K8s多节点部署+负载均衡+keepalived --囊萤映雪 1.多节点master2 部署 2.负载均衡部署+keepalived 1.多节点master2部署: #从master01节点上拷贝证 ...

  9. Docker私有仓库与Harbor部署使用

    Docker私有仓库与Harbor部署使用 目录 Docker私有仓库与Harbor部署使用 一.本地私有仓库 1. 下载registry镜像 2. 在daemon.json文件中添加私有镜像仓库地址 ...

  10. Linux用户配置文件、口令配置文件、组配置文件

    1.用户配置文件:保存用户信息 /etc/passwd 2.口令配置文件 /etc/shadow 每一行解释:登录名:加密口令:最后一次修改时间:最小时间间隔:最大时间间隔:警告时间:不活动时间:失效 ...