Kubernetes学习笔记(九):StatefulSet--部署有状态的多副本应用

StatefulSet如何提供稳定的网络标识和状态

ReplicaSet中的Pod都是无状态,可随意替代的。又因为ReplicaSet中的Pod是根据模板生成的多副本,无法对每个副本都指定单独的PVC。

来看一下StatefulSet如何解决的。

提供稳定的网络标识

StatefulSet创建Pod都有一个从零开始的顺序索引,这会体现在Pod的名称和主机名上,同样也会体现在Pod对应的固定存储上。所以这些名字是可预先知道的,不同于ReplicaSet的随机生成名字。

因为他们的名字都是固定的,而且彼此状态都不同,通常会操作他们其中的一个。如此情况,一般都会创建一个与之对应的headless Service,通过这个Service,每个Pod将拥有独立的DNS记录。

扩容一个StatefulSet会使用下一个顺序索引创建一个新的Pod,缩容会删除索引值最高的。并且缩容任何时候只会操作一个Pod。

如何提供稳定的存储

StatefulSet可以拥有一个或多个PVC模板,这些PVC会在创建Pod前创建出来,绑定到一个Pod实例上。

扩容的时候会创建一个Pod以及若干个PVC,删除的时候只会删除Pod。StatefulSet缩容时不会删除PVC,扩容时会重新挂上。

使用StatefulSet

定义三个PV

定义pv-(a|b|c)

# stateful-pv-list.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-a
spec:
  capacity:
    storage: 1Mi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  hostPath:
    path: /tmp/pva
---
apiVersion: v1
kind: PersistentVolume
# 以下忽略

headless的Service

# stateful-service-headless.yaml
apiVersion: v1
kind: Service
metadata:
  name: rwfile
spec:
  clusterIP: None
  selector:
    app: rwfile
  ports:
  - port: 80

定义StatefulSet

先创建两个Pod副本。使用volumeClaimTemplates定义了PVC模板。

# stateful.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: rwfile
spec:
  replicas: 2
  serviceName: rwfile
  selector:
    matchLabels:
     app: rwfile
  template:
    metadata:
      labels:
        app: rwfile
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/orzi/rwfile
        name: rwfile
        ports:
        - containerPort: 8000
        volumeMounts:
        - name: data
          mountPath: /tmp/data
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      resources:
        requests:
          storage: 1Mi
      accessModes:
      - ReadWriteOnce

创建三个PV,一个headless的Service,一个StatefulSet

-> [root@kube0.vm] [~] k create -f stateful-pv-list.yaml
persistentvolume/pv-a created
persistentvolume/pv-b created
persistentvolume/pv-c created

-> [root@kube0.vm] [~] k create -f stateful-service-headless.yaml
service/rwfile created

-> [root@kube0.vm] [~] k create -f stateful.yaml
statefulset.apps/rwfile created

查看

-> [root@kube0.vm] [~] k get all -o wide
NAME                    READY   STATUS      RESTARTS   AGE   IP            NODE       NOMINATED NODE   READINESS GATES
pod/rwfile-0            1/1     Running     0          12s   10.244.1.52   kube1.vm   <none>           <none>
pod/rwfile-1            1/1     Running     0          8s    10.244.2.56   kube2.vm   <none>           <none>

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   81s   <none>
service/rwfile       ClusterIP   None         <none>        80/TCP    23s   app=rwfile

NAME                      READY   AGE   CONTAINERS   IMAGES
statefulset.apps/rwfile   2/2     12s   rwfile       registry.cn-hangzhou.aliyuncs.com/orzi/rwfile

查看PV和PVC,可以看到已经有两个PVC绑定了PV

-> [root@kube0.vm] [~] k get pv,pvc -o wide
NAME                    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                   STORAGECLASS   REASON   AGE     VOLUMEMODE
persistentvolume/pv-a   1Mi        RWO            Recycle          Bound       default/data-rwfile-0                           7m20s   Filesystem
persistentvolume/pv-b   1Mi        RWO            Recycle          Bound       default/data-rwfile-1                           7m20s   Filesystem
persistentvolume/pv-c   1Mi        RWO            Recycle          Available                                                   7m20s   Filesystem

NAME                                  STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE     VOLUMEMODE
persistentvolumeclaim/data-rwfile-0   Bound    pv-a     1Mi        RWO                           6m55s   Filesystem
persistentvolumeclaim/data-rwfile-1   Bound    pv-b     1Mi        RWO                           6m51s   Filesystem

请求Pod

启动代理

-> [root@kube0.vm] [~] k proxy
Starting to serve on 127.0.0.1:8001

发送请求

-> [root@kube0.vm] [~] curl http://localhost:8001/api/v1/namespaces/default/pods/rwfile-0/proxy/ -d "a=123"
data stored in : rwfile-0

-> [root@kube0.vm] [~] curl http://localhost:8001/api/v1/namespaces/default/pods/rwfile-0/proxy/
a=123

删除测试

删除rwfile-0,然后查看,从时间上看确实是被删除重建的。

-> [root@kube0.vm] [~] k delete po rwfile-0
pod "rwfile-0" deleted

-> [root@kube0.vm] [~] k get po
NAME                READY   STATUS      RESTARTS   AGE
rwfile-0            1/1     Running     0          7s
rwfile-1            1/1     Running     0          19m

看一下之前存储的数据还在不在

-> [root@kube0.vm] [~] curl http://localhost:8001/api/v1/namespaces/default/pods/rwfile-0/proxy/
a=123

还是在的,此次测试实际上也证明了StatefulSet提供了稳定的网络标识和存储。

发现StatefulSet的伙伴节点

使用DNS解析headless的Service的FQDN。
例子以后再写吧。。

如何处理节点失效

除非确定节点无法运行或者不会在访问,否则不要强制删除有状态的Pod

k delete pod rwfile-0 --force --grace-period 0

小结

  • StatefulSet创建Pod都有一个从零开始的顺序索引
  • 通常会创建一个与StatefulSet对应的headless Service。
  • 扩容一个StatefulSet会使用下一个顺序索引创建一个新的Pod,缩容会删除索引值最高的。
  • 新建StatefulSet需要指定headless ServiceName和volumeClaimTemplates。
  • 使用DNS发现StatefulSet的伙伴节点
  • 强制删除:k delete pod rwfile-0 --force --grace-period 0
posted @ 2020-06-21 15:03  虾敏四把刀  阅读(192)  评论(0编辑  收藏