这是我参与 8 月更文挑战的第 22 天,活动详情查看: 8月更文挑战
- 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。
StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod实例都创建了一个DNS域名,这个域名的格式为:
比如一个3节点的Kafka的StatefulSet集群对应的Headless Service的名称为kafka,StatefulSet的名称为kafka,则StatefulSet里的3个Pod的DNS名称分别为kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,这些DNS名称可以直接在集群的配置文件中固定下来。
使用statefulSet部署一个应用
部署一个statefulSet的应用的前提是部署pv,有pv可以使用。这样在statefulSet的yaml文件里指定的pvc部署完以后会有pv可以绑定。
作为开始,使用如下示例创建一个StatefulSet。它和StatefulSets概念中的示例相似。它创建了一个Headless Service的nginx用来发布 StatefulSet web中的Pod的IP地址。
cat statefulset.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:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
部署一个statefulSet的应用的前提是部署pv,有pv可以使用。这样在statefulSet的yaml文件里指定的pvc部署完以后会有pv可以绑定。
作为开始,使用如下示例创建一个StatefulSet。它和StatefulSets概念中的示例相似。它创建了一个Headless Service的nginx用来发布 StatefulSet web中的Pod的IP地址。
cat statefulset.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:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
部署一个statefulSet的应用的前提是部署pv,有pv可以使用。这样在statefulSet的yaml文件里指定的pvc部署完以后会有pv可以绑定。
作为开始,使用如下示例创建一个StatefulSet。它和StatefulSets概念中的示例相似。它创建了一个Headless Service的nginx用来发布 StatefulSet web中的Pod的IP地址。
cat statefulset.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:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
通过statefulset部署pod,并且观察pod创建的过程
你需要使用两个终端窗口。在第一个终端中,使用kubectl get来查看 StatefulSet的Pods的创建情况。
kubectl get pods -w -l app=nginx
在另一个终端中,使用 kubectl apply -f statefulset.yaml来创建定义在statefulset.yaml中的 Headless Service 和StatefulSet。
kubectl apply -f statefulset.yaml
上面的命令创建了两个 Pod,每个都运行了一个NGINX web 服务器。获取nginx Service 和web StatefulSet来验证是否成功的创建了它们。
查看service
kubectl get service nginx
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx None <none> 80/TCP 12s
查看statefulset
kubectl get statefulset web
显示如下:
NAME READY AGE
web 2/2 20m
顺序创建 Pod
对于一个拥有 N 个副本的 StatefulSet,Pod 被部署时是按照 {0..N-1}的序号顺序创建的。在第一个终端中使用 kubectl get 检查输出。这个输出最终将看起来像下面的样子。
kubectl get pods -w -l app=nginx
****NAME READY STATUS RESTARTS AGE****
****web-0**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-0**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-0**** ****0**** ****/1 ContainerCreating**** ****0**** ****0s****
****web-0**** ****1**** ****/1 Running**** ****0**** ****19s****
****web-1**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-1**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-1**** ****0**** ****/1 ContainerCreating**** ****0**** ****0s****
****web-1**** ****1**** ****/1 Running**** ****0**** ****18s****
请注意在web-0 Pod处于Running和Ready 状态后web-1 Pod才会被启动。
对于一个拥有 N 个副本的 StatefulSet,Pod 被部署时是按照 {0..N-1}的序号顺序创建的。在第一个终端中使用 kubectl get 检查输出。这个输出最终将看起来像下面的样子。
kubectl get pods -w -l app=nginx
****NAME READY STATUS RESTARTS AGE****
****web-0**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-0**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-0**** ****0**** ****/1 ContainerCreating**** ****0**** ****0s****
****web-0**** ****1**** ****/1 Running**** ****0**** ****19s****
****web-1**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-1**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-1**** ****0**** ****/1 ContainerCreating**** ****0**** ****0s****
****web-1**** ****1**** ****/1 Running**** ****0**** ****18s****
请注意在web-0 Pod处于Running和Ready 状态后web-1 Pod才会被启动。
对于一个拥有 N 个副本的 StatefulSet,Pod 被部署时是按照 {0..N-1}的序号顺序创建的。在第一个终端中使用 kubectl get 检查输出。这个输出最终将看起来像下面的样子。
kubectl get pods -w -l app=nginx
****NAME READY STATUS RESTARTS AGE****
****web-0**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-0**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-0**** ****0**** ****/1 ContainerCreating**** ****0**** ****0s****
****web-0**** ****1**** ****/1 Running**** ****0**** ****19s****
****web-1**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-1**** ****0**** ****/1 Pending**** ****0**** ****0s****
****web-1**** ****0**** ****/1 ContainerCreating**** ****0**** ****0s****
****web-1**** ****1**** ****/1 Running**** ****0**** ****18s****
请注意在web-0 Pod处于Running和Ready 状态后web-1 Pod才会被启动。
检查 Pod 的顺序索引
获取 StatefulSet 的 Pod。
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 1m
web-1 1/1 Running 0 1m
如同StatefulSets 概念中所提到的, StatefulSet中的Pod拥有一个具有黏性的、独一无二的身份标志。这个标志基于StatefulSet控制器分配给每个 Pod的唯一顺序索引。 Pod的名称的形式为-。web StatefulSet 拥有两个副本,所以它创建了两个 Pod:web-0 和 web-1
使用稳定的网络身份标识
每个Pod都拥有一个基于其顺序索引的稳定的主机名(statefulset创建的pod的主机名由statefulset的名称和有序索引组成)。使用kubectl exec 在每个 Pod 中执行hostname
for i in 0 ****1 **; **do kubectl exec web- $i -- sh -c **'hostname' **; done
显示如下:
web-0
web-1
使用kubectl run运行一个提供nslookup命令的容器,该命令来自于dnsutils包。通过对Pod的主机名执行nslookup,你可以检查他们在集群内部的DNS地址。
kubectl exec -it web-1 -- /bin/bash
apt-get install dnsutils -y
nslookup web-0.nginx.default.svc.cluster.local
删除statefulSet
在一个终端中查看 StatefulSet 的 Pod。
kubectl get pod -w -l app = nginx
在另一个终端中使用 kubectl delete 删除 StatefulSet 中所有的 Pod。
kubectl delete pod -l app=nginx
pod "web-0" deleted
pod "web-1" deleted
等待 StatefulSet 重启它们,并且两个 Pod 都变成 Running 和 Ready 状态。
kubectl get pod -w -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 0s
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 34s
使用 kubectl exec 和 kubectl run 查看 Pod 的主机名和集群内部的 DNS 表项
for i in 0 ****1 **; **do kubectl exec web- $i -- sh -c **'hostname' ****; **done
web-0
web-1
web-2
部署和扩缩 容
1.对于包含N个副本的StatefulSet,当部署Pod时,它们是依次创建的,顺序为 0..N-1。
2.当删除 Pod 时,它们是逆序终止的,顺序为 N-1..0。
3.在将缩放操作应用到Pod之前,它前面的所有Pod 必须是 Running 和 Ready 状态。
4.在 Pod 终止之前,所有的继任者必须完全关闭。
StatefulSet 不应将 pod.Spec.TerminationGracePeriodSeconds 设置为 0。这种做法是不安全的,要强烈阻止。更多的解释请参考 强制删除 StatefulSet Pod。
在上面的 nginx 示例被创建后,会按照 web-0、web-1的顺序部署Pod。在 web-0 进入 Running 和 Ready 状态前不会部署 web-1。在 web-1 进入 Running 和 Ready 状态前不会部署 web-2。如果 web-1 已经处于 Running 和 Ready 状态,而 web-2 尚未部署,在此期间发生了 web-0 运行失败,那么 web-2 将不会被部署,要等到 web-0 部署完成并进入 Running 和 Ready 状态后,才会部署 web-2。如果用户想将示例中的 StatefulSet 收缩为 replicas=1,首先被终止的是 web-2。在 web-2 没有被完全停止和删除前,web-1 不会被终止。当 web-2 已被终止和删除、web-1 尚未被终止,如果在此期间发生 web-0 运行失败,那么就不会终止 web-1,必须等到 web-0 进入 Running 和 Ready 状态后才会终止 web-1。