k8s-statefulSet

在开始之前,我们先准备两个1G的存储卷PV

[root@master1 ~]# cat  pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
spec:
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteOnce
  hostPath:
     path: /tmp/pv001

---

apiVersion: v1
kind: PersistentVolume
metadata:
   name: pv002
spec:
   capacity:
     storage: 1Gi
   accessModes:
   - ReadWriteOnce
   hostPath:
     path: /tmp/pv002

这样就拥有了两个PV ,我这是里PVC声明过了,正常应该是可以用的

接下来申明一个如下所示的StatefulSet资源清单

[root@master1 ~]# cat  nginx-sts.yaml 
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
  namespace: default
spec:
  serviceName: "nginx"
  replicas: 3
  selector: 
     matchLabels:
       app: nginx
  template:
     metadata:
       labels:
          app: nginx
     spec:
        containers:
        - name: nginx
          image: nginx:1.7.9
          ports:
          - name: web
            containerPort: 80
          volumeMounts:
             - name: www
               mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
   - metadata:
        name: www
     spec:
       accessModes: [ "ReadWriteOnce"  ] 
       resources:
         requests:
            storage: 1Gi  

从上面的资源清单中可以看出和我们之前的deployment基本上是一致的,有通过声明的pod模板来创建pod的,资源清单中的volumeMounts进行关联的不是volumes而是一个新的属性volumeClaimTemplates该属性会自动创建一个pvc对象,其实这里就是一个pvc的模板,和pod木本类似,pvc被创建后会自动去关联当前系统中和他合适的pv进行Bound。除此之外,还多了一个serviceName :"nginx'的字段,serviceName就是管理当前statefulSet的服务名称,该服务必须在StatefulSet之前存在,并且负责该集合的网络标识,pod会遵循以下格式获取DNs主机名,pod-specific-string.serviceName.defalt.svc.clustes.local,其中pod-specific-string由statefulSet控制管理

  statefulSet的拓扑结构和其他用于部署的资源对象其实比较类似,比较大的区别在于statefulSet引入了pv和pvc对象来持久化存储服务产生的状态,这样所有的服务虽然可以被杀掉或者重启,但是其中的数据由于pv的原因不会丢失

    由于我们这里用volumeClaimTemplates声明的模板是挂载点的方式,不是volume,所以实际上相当于吧pv的存储挂载到容器中,所以会覆盖掉容器中的数据,在容器启动完成后我们可以手动在pv的存储里新建index保证容器的正常访问。

[root@master1 ~]# cat  headless-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: default
  labels:
     app: nginx
spec:
  ports:
  - name: http
    port: 80
  clusterIP: None
  selector:
    app: nginx

kubectl  apply -f   headless-svc.yaml

service/nginx created

k8s-statefulSet_第1张图片

 k8s-statefulSet_第2张图片

 可以看出这里通过volume模板自动生成了两个pvc对象,也自动和pv进行了绑定bound,这个时候我们可以快速通过一个--watch 

k8s-statefulSet_第3张图片

 replicas=3  但是pv只有2,所以wen2是pending。仔细观察整过程出现了两个pod,web-0和web-1,而且这两个pod是按照顺序进行创建的,web0启动后web-1才开始创建。如果生面statrfulSet概念中所提到的,statefulSet中pod拥有一个稳定的独一无二的身份标志。这个标志基于statefulSet控制器分配给每个pod的唯一顺序索引,我们这里的对象拥有两个副本

statefulSet中pod副本的创建会按照顺序升序处理,副本的更新和删除会按照顺序好降序处理

可以看到,这两个pod的hostname与pod名称是一直的,都被分配了对应的编号 

k8s-statefulSet_第4张图片

我们可以看到controlled by :statefulSet/web, 证明我们的pod是直接收到statefulSet控制管理的。

k8s-statefulSet_第5张图片

这里发现了三条dns记录,headless  service,cluster:none无头服务,几个pod几条记录

k8s-statefulSet_第6张图片

 删除完成后才pod状态,可以看到statefulSet控制器仍然会安装顺序创建出两个pod副本出来,而且pod的唯一标识依然没变,所以两个pod的网络标识还是固定的,我们依然可以通过web0.nginx去访问到这pod

 虽然pod已经重建了,对应podip已经变化了,但是访问这个pod的地址依然没有变,并且他们依然还是关联的之前从pvc,数据并不会丢失

通过headlessService,statefulSet就保证了pod网络标识的唯一稳定性,由于podip并不是固定的,所以我们访问有状态应用实例的时候,就必须使用dns记录的方式来访问了,所以很多有固定的pod ip的需求,或许可以用这种方式来代替

最后我们可以通过删除statefulSet对象来删除所有的pod,仔细观察也会发现是按照倒叙的方式进行删除的。

k8s-statefulSet_第7张图片

k8s-statefulSet_第8张图片管理策略  

 对于某些分布式系统来说,仅仅要求唯一性和身份标志,为了解决这个问题,我们值需要声明statefulSet的时候重新设置spec.podManagementPolicy策略即可

默认的管理策略是OrderedReady,表示让statefulSet控制器遵循上文演示的顺序性保证,除此之外还可以设置为parallel管理模式,表示让statefulSet控制器并行的终止所有pod,在启动或者终止另一个pod前,不必等待这些pod runnning 和 ready

更新策略

前面我们学习了deployment的升级策略,在statefulSet中同样也支持两种升级策略onDelete和rollingUpdate,同样可以通过spec.updateStrategy.type进行指定

  OnDelete该策略表示更新了statefulSet的模板后,只有手动删除旧的pod才会创建新的pod

rollingUpdate 表示当更新statefulSet模板后会自动删除就的pod并创建新的pod,如果更新发生了错误,这次滚动更新会停止,不过需要注意的是statefulSet的pod在部署的时候顺序是0~n,而在rollingUpdate时pod是按照逆序的方式n~0 一次删除并创建的

另外statefulSet的rollingUpdate的滚动升级还支持partitions的特性,在设置partition后,statefulSet的pod中序号大于或者等于partition的pod会在statefulSet的模板更新后滚动升级,而其余的pod保持不变,这个功能可以实现灰度发布

实际项目中我们很少会直接通过statefulSet来部署我们的有状态服务,使用更高级的operator来部署,etcd-operator

你可能感兴趣的:(nginx,docker,https)