k8s之StatefulSet介绍(六)

复制有状态的Pod
replicaSet经过一个pod模版建立多个pod副本。这些副本除了它们的名字和IP地址不一样外,没有别的差别。若是pod模版里描述了一个关联到特定持久卷声明的数据卷,那么ReplicaSet的全部副本都将共享这个持久卷声明,也就是绑定到同一个持久卷声明。
由于是在pod模版里关联持久卷声明的,又会依据pod模版建立多个副本,则不能对每一个副本都指定独立的持久卷声明。因此也不能经过一个ReplicaSet来运行一个每一个实例都须要独立存储的分布式数据存储服务,至少经过单个ReplicaSet是作不到的。老实说,以前你学习到的全部API对象都不能提供这样的数据存储服务,还须要一个其余的对象--StatefulSet
 
咱们先看不使用StatefulSet的状况下有没有方法实现多个副本有本身的持久卷声明。
三种取巧的方法。
第一种方法,不使用ReplicaSet,使用Pod建立多个pod,每一个pod都有独立的持久卷声明。须要手动建立它们,当有的pod消失后(节点故障),须要手动建立它们。所以不是一个好方法。
第二种方法,多个replicaSet ,每一个rs只有一个pod副本。但这看起来很笨重,并且没办法扩缩容。
第三种方法,使用同一个ReplicaSet,你们也都挂载同一个持久卷声明,应用内部作好互斥,建立多个data数据目录,每个pod用一个标记为在用,后面应用不能选被标记为在用的目录。这样作很难保证协调的一点没问题,同时你们用同一个持久卷,读写io将成为整个应用的瓶颈。
 
除了上面的存储需求,集群应用也会要求每个实例拥有生命周期内惟一标识。pod能够随时被删掉,而后被新的pod替代。当一个ReplicaSet中的pod被替换时,尽管新的pod也可能使用被删除pod数据卷中的数据,但它倒是拥有全新主机名和IP的崭新pod.在一些应用中,当启动的实例拥有彻底新的网络标识,但还使用旧实例的数据时,极可能引发问题,好比etcd存储服务。
固然也能够建立多个service ,每个replicaset对应一个service,那么同样很笨重,且显得很低级。辛运的是,Kubernetes为咱们提供了这类需求的完美解决方案--StatefulSet.
 
了解StatefulSet
能够建立一个StatefulSet资源代替ReplicaSet来运行这类pod.它们是专门定制的一类应用,这类应用中每个实例都是不可替代的个体,都拥有稳定的名字和状态。
对比StatefulSet 与 ReplicaSet 或 ReplicationController
RS或RC管理的pod副本比较像牛,它们都是无状态的,任什么时候候它们均可以被一个全新的pod替换。而后有状态的pod须要不一样的方法,当一个有状态的pod挂掉后,这个pod实例须要在别的节点上重建,可是新的实例必须与被替换的实例拥有相同的名称、网络标识和状态。这就是StatefulSet如何管理pod的。
StatefulSet 保证了pod在从新调度后保留它们的标识和状态。它让你方便地扩容、缩容。与RS相似,StatefulSet也会指按期望的副本数,它决定了在同一时间内运行的宠物数。也是依据pod模版建立的,与RS不一样的是,StatefulSet 建立的pod副本并非彻底同样的。每一个pod均可以拥有一组独立的数据卷(持久化状态)。另外pod的名字都是规律的(固定的),而不是每一个新pod都随机获取一个名字。
 
提供稳定的网络标识
StatefulSet 建立的pod的名称,按照从零开始的顺序索引,这个会体如今pod的名称和主机名称上,一样还会体如今pod对应的固定存储上。
有状态的pod与普通的pod不同的是,有状态的pod有时候须要经过其主机名来定位,而无状态的不须要,由于无状态的都同样,随机选一个就行,但对于有状态的来讲,每个pod都不同,一般但愿操做的是特定的一个。基于这个缘由,一个StatefulSet要求你建立一个用来记录每一个pod网络标记的headless Service。经过这个Service,每一个pod将拥有独立的DNS记录,这样集群里它的伙伴或者客户端就能够经过主机名找到它。好比说一个属于default命名空间,名为foo的控制服务,它的一个pod名称为A-0,那么完整域名为:a-0.foo.default.svc.cluster.local。而在ReplicaSet是行不通的。
此外咱们能够在容器中经过dig foo.default.svc.cluster.local对应的SRV记录,获取一个StatefulSet中全部pod的名称.
 
StatefulSet扩缩容的特色
扩容,会按照索引进行
缩容,也会按照索引,删除索引值最大的 pod
缩容StatefulSet任什么时候候只会操做一个pod实例,因此会很慢,不是由于索引要顺序进行,而是为了不数据丢失。举例来讲,一个分布式存储应用副本数为2,若是同时下线两个,一份数据记录就会丢失。
基于以上缘由,StatefulSet在有实例不健康的状况下是不容许进行缩容操做的。一个不健康,你又缩容一个这样至关于两个同时下线。
持久卷的建立和删除
扩容Statefulset增长一个副本,会建立两个或更多的API对象(一个pod和一个与之关联的持久卷声明)。但对于缩容来将,只会删除一个pod,而遗留下以前建立的声明。由于当一个声明被删除后,与之绑定的持久卷就会被回收或删除,其上面的数据就会丢失。基于这个缘由,你须要释放特定的持久卷时,须要手动删除对应的持久卷声明。
 
StatefulSet的保障机制。
一个有状态的pod总会被一个彻底一致的pod替换(二者相同的名称,主机名和存储等)。这个替换发生在kubernetes发现旧pod不存在时(例如手动删除这个pod).
那么当Kubernetes不能肯定一个pod的状态呢?若是它建立一个彻底一致的pod,那系统中就会有两个彻底一致的pod在同时运行。这两个pod会绑定到相同的存储,因此这两个相同标记的进程会同时写相同的文件。
为了保证两个拥有相同标记和绑定相同持久卷声明的有状态的pod实例不会同时运行,statefulset遵循at-most-one语义。也就是说一个StatefulSet必须在准确确认一个pod再也不运行后,才会去建立它的替换pod。这对如何处理节点故障有很大帮助。具体实现,内部的,暂不深刻。
讲了那么多StatefulSet实现有状态pod的好处,下面看看如何建立。
 
咱们假设使用gec建立三个pv

 

kind: list
apiVersion: v1
item:
-   apiVersion: v1
  kind: PersistenVolume
  metadata:
    name: pv-a
  spec:
    capacity:
      storage: 1Mi
    accessModes:
    -    ReadWriteOnce
    persistenVolumeReclaimPolicy: Recycle  卷被声明释放后,空间会被回收再利用
    gcePersistentDisk:
      poName: pv-a
      fsType: nfs4
-   apiVersion: v1
  kind: PersistenVolume
  metadata:
    name: pv-b
...

 

准备好pv后,咱们接下来建立statefulset
 
如咱们以前将到的,在部署一个StatefulSet以前,须要建立一个用于在有状态的pod之间提供网络标识的headless Service

 

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  clusterIP: None        (StatefulSet的控制Service必须时None即headless模式)
  selector:
    app: kubia
  ports:
  -   name: http
    port: 80

 

建立StatefulSet详单

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: kubia
spec:
  serviceName: kubia
  replicas: 2
  template:
    metadta:
      labels:
        app: kubia
    spec:
      containers:
      -   name: kubia
        image: luksa/kubia-pet
        ports:
        -   name: kubia
          containerPort: 8080

volumeMounts:

        - name: data
         mountPath: /var/data   volumeClaimTemplates:   - metadata:     name: data     spec:       resources:         requests:           storage: 1Mi       accessModes:       - ReadWriteOnce

 

建立:
kubectl create -f kubia-statefulset.yaml
 
列出pod:
kubectl get pod
Name READY
kubia-0 0/1 ...
看到会一个个进行
kubectl get pod
Name READY
kubia-0 1/1 ...
kubia-1 0/1 ...
 
查看pvc
kubectl get pvc
Name STATUS VOlUME
data-kubia-0 Bound pv - c ...
data-kubia-1 Bound pv - a ...
 
能够看到生成的持久卷声明的名称由 volumeClaimTeplate 字段中定义的名称和每一个pod的名称组成。
 
如今你的数据存储集群节点都已经运行,能够开始使用它们了。由于以前建立的Service处于headless模式,因此不能经过service来访问你的pod。须要直接链接每一个单独的pod来访问(或者建立一个普通的Service,可是这样仍是不容许你访问指定的pod)
 
咱们来建立一个普通的service以下:

apiVersion: v1
kind: service
metadata:
  name: kubia-public
spec:
  selector:
    app: kubia
  ports:
  -   port: 80
    targetPort: 8080

 

 

StatefulSet 已经运行起来了,那么咱们看下如何更新它的pod模版,让它使用新的镜像。同时你也会修改副本数为3.一般会使用kubectl edit命令来更新StatefulSet
kubectl edit statefulset kubia
你会看到新的pod实例会使用新的镜像运行,那已经存在的两个副本呢?经过他们的寿命能够看出它们没有更新。这是符合预期的。由于,首先StatefulSet更像ReplicaSet,而不是Deployment,因此在模版被修改后,它们不会重启更新,须要手动删除这些副本,而后StatefulSet会根据新的模版从新调度启动它们。
kubectl delete po kubia-0 kubia-1
注意: 从Kubernetes1.7版本开始,statefulSet支持与Deployment和DaemonSet同样的滚动升级。经过kubectl explain 获取StatefulSet的spec.updateStrategy 相关文档来获取更多信息。
 
前面咱们提到StatefulSet的保障机制,那么当一个节点故障了,会出现什么状况。
statefulset在明确知道一个pod再也不运行以前,它不能或者不该当建立一个替换pod。只有当集群的管理者告诉它这些信息时候,它才能明确知道。为了作到这一点,管理者须要删除这个pod,或者删除整个节点。
当手动中止一个node的网卡,使用kubectl get node,会显示Status notReady
由于控制台不会再收到该节点发送的状态更新,该节点上吗的全部pod状态都会变为Unknown。
当一个pod状态为Unknown时会发生什么
若该节点过段时间正常链接,而且从新汇报它上面的pod状态,那这个pod就会从新被标记为Runing。但若是这个pod的未知状态持续几分钟后(这个时间是能够配置的),这个pod就会自动从节点上驱逐。这是由主节点(kubernetes的控制组件)处理的。它经过删除pod的资源来把它从节点上驱逐。
当kubelet发现这个pod标记为删除状态后,它开始终止运行该pod。在上面的示例中,kubelet已不能与主节点通讯(由于网卡断了),这意味着这个pod会一直运行着。查看
kubectl describe po kubia-0
发现status一直为Terminating,缘由是NodeLost,在信息中说明的是节点不回应致使不可达。
这时候你想要手动删除pod
kubectl delete po kubia-0
执行完成后,你的想法是会再次运行一个kubia-0
可是kubectl get po会发现kubia-0 状态为 Unknown 而且仍是以前那个旧pod ,由于启动时长没变。
为何会这样?由于在删除pod以前,这个pod已经被标记为删除。这是由于控制组件已经删除了它(把它从节点驱逐)。这时你用kubectl describe po kubia-0 查看状态依然是Terminating。
这时候只能进行强制删除
kubectl delete po kubia-0 --force --grace-period 0
你须要同时使用--force和 --grace-period 0两个选项。而后kubectl 会对你作的事发出
警告信息。若是你再次列举pod,就能够看到一个新的kubia-0 pod被建立出来。
警告: 除非你确认节点再也不运行或者不会再能够访问(永远不会再能够访问),不然不要强制删除有状态的pod.
相关文章
相关标签/搜索