
k8s有状态应用StatefullSet
1.需求
1.Pod之间并非相同的副本,每个Pod有一个独立标识
2.Pod独立标识要能够对应到一个固定的网络标识,并在发布升级后继续保持
3.每个Pod有一块独立的存储盘,并在发布升级后还能继续挂载原有的盘
4.应用发布时,按照固定顺序升级Pod
2.StatefulSet
StatefulSet部署有状态应用,解决Pod独立生命周期,保持启动顺序和唯一性
1.稳定,唯一的网络标识符,持久存储
2.有序,优雅的部署和扩展删除终止
3.有序,滚动更新
- 首先,每个 Pod 会有 Order 序号,会按照序号来创建,删除和更新 Pod;
- 其次,通过配置一个 headless Service,使每个 Pod 有一个唯一的网络标识 (hostname);
- 第三,通过配置 pvc 模板,就是 pvc template,使每个 Pod 有一块或者多块 pv 存储盘;
- 最后,支持一定数量的灰度发布。比如现在有三个副本的 StatefulSet,我们可以指定只升级其中的一个或者两个,更甚至是三个到新版本。通过这样的方式,来达到灰度升级的目的。
StatefulSet 中的 Pod 都是有序号的,从 0 开始一直到定义的 replica 数量减一。每个 Pod 都有独立的网络标识:一个 hostname、一块独立的 pvc 以及 pv 存储。这样的话,同一个 StatefulSet 下不同的 Pod,有不同的网络标识、有自己独享的存储盘,这就能很好地满足了绝大部分有状态应用的需求。
Pod的版本
StatefulSet 中,是由 StatefulSet Controller 来管理下属的 Pod,因此 StatefulSet 通过 Pod 的 label 来标识这个 Pod 所属的版本,这里叫 controller-revision-hash。这个 label 标识和 Deployment 以及 StatefulSet 在 Pod 中注入的 Pod template hash 是类似的。
3.稳定的网络和存储
- 稳定的网络ID
使用Headless Service 相比普通Service只是将spec.clusterIP定义为None来维护Pod网络身份,并添加serviceName:“nginx”字段指定StatefulSet控制器要使用这个Headless Service。DNS解析名称:
...svc.cluster.local
- 稳定的存储
StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当StatefulSet使用VolumeClaimTemplate创建一个PersistentVolume时,同样也会为每个Pod分配并创建一个编号的PVC
3.StatefulSet相关命令操作
# 升级 kubectl set image statefulset nginx-web nginx=nginx:latest # 查看状态 kubectl get sts nginx-web -o yaml # 查看版本状态 kubectl get pod -L controller-revision-hash
- currentReplica:表示当前版本的数量
- currentRevision: 表示当前版本号
- updateReplicas:表示新版本的数量
- **updateRevision:**表示当前要更新的版本号
4.管理模式
StatefulSet可以创建三种类型的资源。
- 第一种资源:ControllerRevision
通过这个资源,StatefulSet 可以很方便地管理不同版本的 template 模板。
举个例子:比如上文中提到的 nginx,在创建之初拥有的第一个 template 版本,会创建一个对应的 ControllerRevision。而当修改了 image 版本之后,StatefulSet Controller 会创建一个新的 ControllerRevision,大家可以理解为每一个 ControllerRevision 对应了每一个版本的 Template,也对应了每一个版本的 ControllerRevision hash。其实在 Pod label 中定义的 ControllerRevision hash,就是 ControllerRevision 的名字。通过这个资源 StatefulSet Controller 来管理不同版本的 template 资源。
- 第二个资源:PVC
如果在 StatefulSet 中定义了 volumeClaimTemplates,StatefulSet 会在创建 Pod 之前,先根据这个模板创建 PVC,并把 PVC 加到 Pod volume 中。
如果用户在 spec 的 pvc 模板中定义了 volumeClaimTemplates,StatefulSet 在创建 Pod 之前,根据模板创建 PVC,并加到 Pod 对应的 volume 中。当然也可以在 spec 中不定义 pvc template,那么所创建出来的 Pod 就不会挂载单独的一个 pv。
- 第三个资源:Pod
StatefulSet 按照顺序创建、删除、更新 Pod,每个 Pod 有唯一的序号。
5.工作流程
首先通过注册 Informer 的 Event Handler(事件处理),来处理 StatefulSet 和 Pod 的变化。在 Controller 逻辑中,每一次收到 StatefulSet 或者是 Pod 的变化,都会找到对应的 StatefulSet 放到队列。紧接着从队列取出来处理后,先做的操作是 Update Revision,也就是先查看当前拿到的 StatefulSet 中的 template,有没有对应的 ControllerRevision。如果没有,说明 template 已经更新过,Controller 就会创建一个新版本的 Revision,也就有了一个新的 ControllerRevision hash 版本号。
然后 Controller 会把所有版本号拿出来,并且按照序号整理一遍。这个整理的过程中,如果发现有缺少的 Pod,它就会按照序号去创建,如果发现有多余的 Pod,就会按照序号去删除。当保证了 Pod 数量和 Pod 序号满足 Replica 数量之后,Controller 会去查看是否需要更新 Pod。也就是说这两步的区别在于,Manger pods in order 去查看所有的 Pod 是否满足序号;而后者 Update in order 查看 Pod 期望的版本是否符合要求,并且通过序号来更新。
Update in order 其更新过程如上图所示,其实这个过程比较简单,就是删除 Pod。删除 Pod 之后,其实是在下一次触发事件,Controller 拿到这个 success 之后会发现缺少 Pod,然后再从前一个步骤 Manger pod in order 中把新的 Pod 创建出来。在这之后 Controller 会做一次 Update status,也就是之前通过命令行看到的 status 信息。
通过整个这样的一个流程,StatefulSet 达到了管理有状态应用的能力。
6.Spec字段解析
spec 中前几个字段,Replica 和 Selector 都是我们比较熟悉的字段。
- Replica 主要是期望的数量;
- Selector 是事件选择器,必须匹配 spec.template.metadata.labels 中定义的条件;
- Template:Pod 模板,定义了所要创建的 Pod 的基础信息模板;
- VolumeClaimTemplates:PVC 模板列表,如果在 spec 中定义了这个,PVC 会先于 Pod 模板 Template 进行创建。在 PVC 创建完成后,把创建出来的 PVC name 作为一个 volume 注入到根据 Template 创建出来的 Pod 中。
- ServiceName:对应 Headless Service 的名字。当然如果有人不需要这个功能的时候,会给 Service 定一个不存在的 value,Controller 也不会去做校验,所以可以写一个 fake 的 ServiceName。但是这里推荐每一个 Service 都要配置一个 Headless Service,不管 StatefulSet 下面的 Pod 是否需要网络标识;
- PodMangementPolicy:Pod 管理策略。前面提到过这个字段的可选策略为 OrderedReady 和 Parallel,默认情况下为前者;
- UpdataStrategy:Pod 升级策略。这是一个结构体,下面再详细介绍;
- RevisionHistoryLimit:保留历史 ControllerRevision 的数量限制(默认为 10)。需要注意的一点是,这里清楚的版本,必须没有相关的 Pod 对应这些版本,如果有 Pod 还在这个版本中,这个 ControllerRevision 是不能被删除的。
7.部署Sts
StatefulSet与Deployment区别:有身份
身份的三要素:
- 域名
- 主机名
- 存储PVC
使用yaml创建资源
apiVersion: v1 kind: Service metadata: name: web spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web6 spec: selector: matchLabels: app: nginx serviceName: "web6" replicas: 3 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" ] storageClassName: "managed-nfs-storage" resources: requests: storage: 1Gi查看域名解析,解析与deploy不一样,为每个pod维护了对应域名
nslookup web Server: 10.96.0.10 Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local Name: web Address 1: 10.244.115.126 10-244-115-126.web.default.svc.cluster.local Address 2: 10.244.148.177 10-244-148-177.web.default.svc.cluster.local Address 3: 10.244.148.172 10-244-148-172.web.default.svc.cluster.local Address 4: 10.244.148.176 10-244-148-176.web.default.svc.cluster.local每个pod之间的联系独立
8.存储volumeClaimTemplates
volumeClaimTemplates: - metadata: name: www spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "managed-nfs-storage" resources: requests: storage: 1Gi存储通过编号维护,解决每个pod都有独立的存储,持久化存储