Loading [MathJax]/jax/input/TeX/jax.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >k8s负载资源StatefulSet工作细节

k8s负载资源StatefulSet工作细节

作者头像
你大哥
发布于 2021-10-11 03:28:28
发布于 2021-10-11 03:28:28
78900
代码可运行
举报
文章被收录于专栏:容器云实践容器云实践
运行总次数:0
代码可运行

在k8s中工作负载资源StatefulSet用于管理有状态应用。

什么是无状态?

组成一个应用的pod是对等的,它们之前没有关联和依赖关系,不依赖外部存储。

即我们上篇小作文中deployment创建的nginx pod ,他们是完全一样的,任何一个pod 被移除后依然可以正常工作。由于不依赖外部存储,它们可以被轻易的调度到任何 node 上。

什么是有状态?

显然无状态的反面就是有状态了,pod之间可能包含主从、主备的相互依赖关系,甚至对启动顺序也有要求。更关键的是这些pod 需要外部存储,一旦pod被清除或调度后,怎么把pod 和原来的外部数据联系起来?这就是StatefulSet厉害的地方。

StatefulSet将这些状态应用进行记录,在需要的时候恢复。


StatefulSet如何展开这些工作?

一、维护应用拓扑状态
通过dns记录为 pod 分配集群内唯一、稳定的网络标识。即只要保证pod 的名称不变,pod被调度到任何节点或者ip如何变更都能被找到。

在 k8s 中Service用来来将一组 Pod 暴露给外界访问的一种机制。当创建的service 中clusterIP为None 时(headless 无头服务), 不会进行负载均衡,也不会为该服务分配集群 IP。仅自动配置 DNS

这样我们集群中的 一个pod 将被绑定到一条DNS记录:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<pod-name>.<svc-name>.<namespace>.svc.cluster.local

通过解析这个地址就能找到pod的IP 。

下面我们创建一个headless service,将clusterIP配置为None

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#headless-service.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx-headless
spec:
  ports:
  - name: nginx-service-port
    port: 80
    targetPort: 9376
  clusterIP: None
  selector:
    app: nginx

这个service将会绑定 app=nginx标签的pod,我们通过kubectl apply -f headless-service.yml应用service 并通过get 查看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl get service
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes       ClusterIP   10.96.0.1    <none>        443/TCP   18d
nginx-headless   ClusterIP   None         <none>        80/TCP    4h48m

nginx-headless 这个headless service创建成功了。接着我们创建一个StatefulSet:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#nginx-statefulset.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nginx-statefulset
spec:
  serviceName: "nginx-headless"
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx-web
        image: nginx:1.17
        ports:
        - containerPort: 82

nginx-statefulset 将会绑定我们前面的service nginx-headless并创建三个nginx pod。

我们查看创建的pod ,StatefulSet 中的每个 Pod 根据 StatefulSet 的名称和 Pod 的序号派生出它的主机名。同时statefulset创建出来的pod 名称以(StatefulSetname)(order)开始编号。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl get pod 
NAME                  READY   STATUS    RESTARTS   AGE
nginx-statefulset-0   1/1     Running   0          18s
nginx-statefulset-1   1/1     Running   0          15s
nginx-statefulset-2   1/1     Running   0          12s

$ kubectl exec nginx-statefulset-0 -- sh -c hostname
nginx-statefulset-0

其实他们的创建顺序也是从0-2,当我们删除这些pod时,statefulset 马上重建出相同名称的Pod 。

我们通过statefulset 的event可以观测到这个过程:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl describe  nginx-statefulset
Events:
  Type    Reason            Age    From                    Message
  ----    ------            ----   ----                    -------
  Normal  SuccessfulCreate  7m43s  statefulset-controller  create Pod nginx-statefulset-0 in StatefulSet nginx-statefulset successful
  Normal  SuccessfulCreate  7m40s  statefulset-controller  create Pod nginx-statefulset-1 in StatefulSet nginx-statefulset successful
  Normal  SuccessfulCreate  7m37s  statefulset-controller  create Pod nginx-statefulset-2 in StatefulSet nginx-statefulset successful

现在我们来看一下 pod 是否存在于 DNS 记录中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
kubectl run -it --image busybox busybox --rm /bin/sh

运行一个一次性 pod busybox ,接着使用 ping 命令查询之前提到的规则构建名称nginx-statefulset-0.nginx-headless.default.svc.cluster.local

解析的IP与如下nginx-statefulset-0相符。

这样我们使用pod名称通过DNS就可以找到这个pod 再加上StatefulSet可以按顺序创建出不变名称的 pod ,即一个应用通过StatefulSet准确维护其拓扑状态


二、维护应用存储状态

**k8s为应对应用的数据存储需求提供了卷的概念(volume)以及提供持久化存储的PVC( PersistentVolumeClaim)PV( PersistentVolume)当一个pod 和 PVC绑定后,即使pod 被移除,PVC和PV仍然保留在集群中,pod 再次被创建后会自动绑定到之前的PVC。**他们看起来是这样的:

rs_pv_pvc

这里我们以讨论statefulset持久化存储为主,对于k8s存储本身不了解的同学可以参考k8s官方文档存储章节storage[1]

首先我们创建存储目录 /data/volumes/ 以及一个本地的local类型(使用节点上的文件或目录来模拟网络附加存储)的PV:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pv-local.yml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-local
spec:
  capacity:
    storage: 5Gi 
  volumeMode: Filesystem
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /data/volumes/ 
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - minikube

PV是集群中的一块存储,它声明了后端使用的真实存储,通常会由K8S管理员创建。我们在pv-local中声明了后端存储类型为local挂载到目录 /data/volumes/ , 存储卷类名为local-storage,1Gb容量,访问模式ReadWriteMany -- 卷可以被多个个节点以读写方式挂载。亲和的节点为minikube

我们通过get来查看这个PV:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS    REASON   AGE
pv-local   5Gi        RWX            Delete           Available                  local-storage            25m

此时PV的状态为available,还未与任何PVC绑定。我们通过创建PV使集群得到了一块存储资源,但此时还不属于你的应用,我们需要通过PVC去构建一个使用它的”通道“。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#app1-pvc.yml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app1-pvc
spec:
  storageClassName: local-storage
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

现在我们开辟好一个5Gb容量的存储通道(PVC),此时PV和PVC已通过 storageClassName自动形成绑定。这样PV和PVC的status 皆为Bound

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS    REASON   AGE
pv-local   5Gi        RWX            Delete           Bound    default/app-pvc   local-storage            25m

$ kubectl get pvc
NAME      STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS    AGE
app-pvc   Bound    pv-local   5Gi        RWX            local-storage   27m

上面我们创建好通道,接下来要在我们statefuset中绑定这个通道,才能顺利使用存储。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# nginx-statefulset.yml

apiVersion: apps/v1            
kind: StatefulSet              
metadata:
  name: nginx-statefulset
spec:
  serviceName: "nginx-headless"
  replicas: 3
  selector:
    matchLabels:
      app: nginx               
  template:
    metadata:                  
      labels:
        app: nginx
    spec:
      nodeName: minikube
      volumes: 
        - name: app-storage
          persistentVolumeClaim:          
            claimName: app-pvc
            
      containers:
      - name: nginx-web
        image: nginx:1.17
        ports:
        - containerPort: 80
          name: nginx-port
        volumeMounts:
          - mountPath: /usr/share/nginx/html
            name: app-storage

与之前的statefulset相比我们在pod 模板中添加了volume 已经 volumeMounts,这样使用这个statefulset 所创建的pod都将挂载 我们前面定义的PVC app-pvc,应用nginx-statefulset.yml后我们进入到pod 检验一下目录是否被正确挂载。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl exec -it nginx-statefulset-0 -- /bin/bash

root@nginx-statefulset-0:/# cat /usr/share/nginx/html/index.html
hello pv

查看本地目录文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@minikube:/# cat /data/volumes/index.html 
hello pv

接着我们在pod 中修改index.html内容为并将pod删除,检验重载后的 pod 存储数据是否能被找回。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
root@nginx-statefulset-0:/# echo "pod data" > /usr/share/nginx/html/index.html

删除带有标签app=nginx的pod ,由于statefulset的控制器使pod按顺序被重建:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl delete pod -l app=nginx
pod "nginx-statefulset-0" deleted
pod "nginx-statefulset-1" deleted
pod "nginx-statefulset-2" deleted

$ kubectl get pod 
NAME                  READY   STATUS              RESTARTS   AGE
nginx-statefulset-0   1/1     Running             0          9s
nginx-statefulset-1   1/1     Running             0          6s
nginx-statefulset-2   0/1     ContainerCreating   0          3s

毫无疑问,pod 数据完好无损:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl exec -it nginx-statefulset-0 -- /bin/bash
root@nginx-statefulset-0:/# cat /usr/share/nginx/html/index.html
pod data

也就是说虽然我们的pod被删除了,但是PV已经PV依然保留在集群中,当pod 被重建后,它依然会去找定义的claimName: app-pvc这个PVC,接着挂载到容器中。

这里我们一个PVC 绑定了多个节点,其实可以为每一个 statefulset中的pod 创建PVC,可以自行了解。

k8s存储可操作性非常强,这里只在statefulset下做了简单的演示。后续我们会对k8s存储做更深入的了解。


三、总结

这篇小作文我们一起学习了k8s中工作负载资源StatefulSet是如何管理有状态应用的,主要从维护应用拓扑状态和存储状态两个方面做了简单介绍。这样我们对statefulset这个工作资源有了大体了解:StatefulSet与Deployment 相比,它为每个管理的 Pod 都进行了编号,使Pod有一个稳定的启动顺序,并且是集群中唯一的网络标识。有了标识后使用PV、PVC对存储状态进行维护。


希望小作文对你有些许帮助,如果内容有误请指正。

您可以随意转载、修改、发布本文,无需经过本人同意。

通过博客阅读:iqsing.github.io

参考资料

[1]

storage:https://kubernetes.io/zh/docs/concepts/storage/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 容器云实践 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
kubernetes(十一) 存储& statefulset控制器
kubernetes支持持久卷的存储插件: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
alexhuiwang
2020/09/23
8060
kubernetes(十一) 存储& statefulset控制器
【K8S专栏】Kubernetes有状态应用管理
我们在《Kubernetes工作负载管理》中主要介绍了无状态应用的管理,当时也有提到有状态应用,但是由于那时候还没有解释数据如何持久化就没有做深度的介绍,而在这章,我们会着重介绍如何进行有状态应用的管理。
没有故事的陈师傅
2022/12/06
4960
「走进k8s」Kubernetes1.15.1的DaemonSet 与 StatefulSet 使用(30)
PS:StatefulSet 主要了解它的使用场景,还有概念和使用方法,名字唯一性的特点。在实际中不可能单独使用他。
IT架构圈
2019/09/04
1.2K0
「走进k8s」Kubernetes1.15.1的DaemonSet 与 StatefulSet 使用(30)
k8s之StatefulSet
是用来创建有状态应用,可以通过过某种方式记录这些状态,然后在 Pod 被重新创建时,能够为新 Pod 恢复这些状态。
编程黑洞
2023/03/06
3150
kubernetes常用控制器之StatefulSet
实例之间的不等关系以及实例对外数据有依赖关系的应用,就被称为"有状态应用"。 所谓实例之间的不等关系即对分布式应用来说,各实例,各应用之间往往有比较大的依赖关系,比如某个应用必须先于其他应用启动,否则其他应用将不能启动等。 对外数据有依赖关系的应用,最显著的就是数据库应用,对于数据库应用,我们是需要持久化保存其数据的,如果是无状态应用,在数据库重启数据和应用就失去了联系,这显然是违背我们的初衷,不能投入生产的。
极客运维圈
2020/03/23
8780
kubernetes常用控制器之StatefulSet
kubernetes之StatefulSet控制器
本文将带你了解k8s中的StatefulSet控制器,将通过实验的方式来说明StatefulSet的用法和配置,让你快速能够将StatefulSet类型的服务用到你的k8s集群中。
聂伟星
2020/10/25
2.1K0
Kubernetes K8S之存储Volume详解 PV概述PVC概述供应绑定使用持久化声明保护回收策略Persistent Volumes类型PV示例PV卷状态PV
与管理计算实例相比,管理存储是一个明显的问题。PersistentVolume子系统为用户和管理员提供了一个API,该API从如何使用存储中抽象出如何提供存储的详细信息。为此,我们引入了两个新的API资源:PersistentVolume和PersistentVolumeClaim。
踏歌行
2020/10/29
3.1K0
Kubernetes K8S之存储Volume详解
    




        PV概述PVC概述供应绑定使用持久化声明保护回收策略Persistent Volumes类型PV示例PV卷状态PV
深入理解StatefulSet,用Kubernetes编排有状态应用
作为一个后端工程师,因为负责的大部分项目都是Web服务这类的“无状态应用”,在平时工作中接触到的最常用的Kubernetes控制器是Deployment,但是Deployment只适合于编排“无状态应用”,它会假设一个应用的所有 Pod是完全一样的,互相之间也没有顺序依赖,也无所谓运行在哪台宿主机上。正因为每个Pod都一样,在需要的时候可以水平扩/缩,增加和删除Pod。
KevinYan
2020/12/15
1.2K0
深入理解StatefulSet,用Kubernetes编排有状态应用
kubernetes | 存储
基于centos7.9,docker-ce-20.10.18,kubelet-1.22.3-0
Amadeus
2022/10/25
4720
kubernetes | 存储
Kubernetes中StatefulSet介绍
使用Kubernetes来调度无状态的应用非常简单,那Kubernetes如何来管理调度有状态的应用呢?Kubernetes中提供了一个StatefulSet控制器来管理有状态的应用,本文就介绍StatefulSet的应用,解决以下几个问题:
大江小浪
2018/08/10
1.8K0
有状态应用的编排-statefulSet
在学习StatefulSet之前, 我们先看下什么是有状态应用, 什么是无状态应用。
用户11097514
2024/07/21
1660
k8s实践(13)--有状态服务StatefulSet详解
https://blog.csdn.net/hguisu/category_9999400.html
黄规速
2023/03/06
5.2K0
k8s实践(13)--有状态服务StatefulSet详解
12 . Kubernetes之Statefulset 和 Operator
(1)每个节点都有固定的身份ID,通过这个ID,集群中的成员可以相互发现并通信。 (2)集群的规模是比较固定的,集群规模不能随意变动。 (3)集群中的每个节点都是有状态的,通常会持久化数据到永久存储中。 (4)如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。
iginkgo18
2020/09/27
1.6K0
5.深入k8s:StatefulSet控制器及源码分析
在上一篇中,讲解了容器持久化存储,从中我们知道什么是PV和PVC,这一篇我们讲通过StatefulSet来使用它们。
luozhiyun
2020/08/11
1.1K0
5.深入k8s:StatefulSet控制器及源码分析
K8S 部署 Statefulset zookeeper
Zookeeper集群需要用到存储,这里需要准备持久卷(PersistentVolume,简称PV),我这里以yaml文件创建3个PV,供待会儿3个Zookeeper节点创建出来的持久卷声明
匿名用户的日记
2021/12/14
1.1K0
K8S 部署 Statefulset zookeeper
k8s实践(12)--K8s service服务详解
Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过 ReplicationController 能够动态地创建和销毁 Pod(例如,需要进行扩缩容,或者执行)。 每个 滚动升级 Pod 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。 这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 Pod 中的哪些 backend 呢?
黄规速
2022/04/14
9.2K0
k8s实践(12)--K8s service服务详解
kubernete编排技术三:StatefulSet
上一篇文章中,我们讲了deployment的编排技术,也提到了这种编排技术只能编排无状态的pod。但是在我们实际生产环境中,系统复杂很多。比如分布式系统,pod之间往往有依赖关系。再比如mysql数据库,主从节点需要通过binlog同步数据,读写请可能要求发送到不同节点上。对这种有状态的应用,kubernete的解决方案是StatefulSet。
jinjunzhu
2020/08/20
9280
K8S之按官方Dashboard目录来进行名词扫盲实战
这里与K8S不同的是这里没有SidecarPlus,但是多了Replica Sets,Replication Controllers,Daemon Sets
爽朗地狮子
2022/11/02
4930
Kubernetes K8S之资源控制器StatefulSets详解
kubernetes中内建了很多controller(控制器),这些相当于一个状态机,用来控制pod的具体状态和行为。
踏歌行
2020/10/15
2.5K0
kubernetes | statefulset控制器详解
可以看到与deployment不同,statefulset中的每个pod都分配到了独立的pv,且重启pod后存储对应关系不变
Amadeus
2023/04/17
7010
相关推荐
kubernetes(十一) 存储& statefulset控制器
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档