草庐IT

【K8S系列】深入解析StatefulSet(二)

颜淡慕潇 2023-04-20 原文

序言

那些看似不起波澜的日复一日,一定会在某一天让你看见坚持的意义。

文章标记颜色说明:

  • 黄色:重要标题
  • 红色:用来标记结论
  • 绿色:用来标记一级论点
  • 蓝色:用来标记二级论点

Kubernetes (k8s) 是一个容器编排平台,允许在容器中运行应用程序和服务。今天学习一下StatefulSet-存储状态。

希望这篇文章能让你不仅有一定的收获,而且可以愉快的学习,如果有什么建议,都可以留言和我交流

这是这篇文章所在的专栏,欢迎订阅:【深入解析k8s】专栏

 专栏介绍

简单介绍一下这个专栏要做的事:

主要是深入解析每个知识点,帮助大家完全掌握k8s,一下是已更新的章节

序号文章
第一讲深入解析 k8s:入门指南(一)
第二讲深入解析 k8s:入门指南(二)
第三讲深入解析Pod对象(一)
第四讲深入解析Pod对象(二)
第五讲深入解析无状态服务
第六讲深入解析有状态服务
第七讲深入解析控制器

第八讲

深入解析 ReplicaSet
第九讲深入解析滚动升级
第十讲深入解析StatefulSet(一)

1 前情提要

 1.1 StatefulSet 两种状态

StatefulSet 的设计,它把真实世界里的应用状态,抽象为了两种:

  • 拓扑状态
  • 存储状态

在前面一篇文章中,我们已经了解了拓扑状态,今天主要学习一下存储状态

2 PVC

 StatefulSet 对存储状态的管理机制,主要使用的是一个叫作 Persistent Volume Claim 的功能。所以我们需要先来看下这个功能的介绍与使用。 

2.1 PVC基本介绍 

持久卷(Persistent Volume)是一种独立于 Pod 的存储资源。持久卷可以独立于 Pod 的生命周期存在,并且可以在 Pod 重新调度后仍然保留数据。

在 Kubernetes 中,要使用持久卷,需要创建一个持久卷声明(Persistent Volume Claim)

Persistent Volume Claim (PVC) 是一种用于声明对持久存储资源的需求的资源对象

PVC 允许将应用程序和存储资源的生命周期分开,以便在应用程序重新部署或迁移时保留持久存储数据

2.2 PVC 的工作原理

Persistent Volume Claim(PVC)是在 Kubernetes 中定义一个存储资源的方式。PVC 允许 Pod 请求特定大小和访问模式的存储。

PVC 实际上是一个声明,它声明了 Pod 需要的存储资源。

Kubernetes 系统会根据 PVC 的要求选择或创建一个相应的持久卷来满足 Pod 的需求

如果 PV 满足 PVC 的要求,则将 PV 绑定到 PVC,并将 PVC 暴露给应用程序使用。

PVC 可以在多个 Pod 之间共享,但每次只能绑定到一个 PV 上。

2.3 PVC 的访问模式

PVC 的访问模式指定了允许哪些节点以哪种方式使用持久卷。以下是 PVC 的三种访问模式:

  • ReadWriteOnce:允许单个节点以读写模式挂载持久卷。
  • ReadOnlyMany:允许多个节点以只读模式挂载持久卷。
  • ReadWriteMany:允许多个节点以读写模式挂载持久卷。

需要注意的是,不是所有的存储插件都支持所有的访问模式。因此,在使用 PVC 的时候,需要确保所使用的存储插件支持所需的访问模式。

2.4 PVC 和 Pod 的关系

  1. 关系:PVC 和 Pod 是紧密相关的。
  2. 请求:一个 Pod 可以请求一个或多个 PVC,并将 PVC 挂载到容器中。
  3. 挂载:在 Pod 被调度到节点上时,Kubernetes 系统会为 Pod 中声明的每个 PVC 创建一个持久卷,并将其挂载到 Pod 上。
  4. 删除当 Pod 被删除时,与之关联的 PVC 不会被删除,这些 PVC 可以在之后的 Pod 中继续使用

2.5 代码示例

2.5.1 yaml 示例

下面是一个 PVC 的 YAML 文件示例:

apiVersion: v1
kind: PersistentVolumeClaim # PVC资源类型
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

在这个示例中,创建了一个名为 my-pvc 的 PVC,并指定了访问模式为 ReadWriteOnce,请求的存储容量为 1Gi。

2.5.2 PVC 的 Pod yaml 

接下来,可以创建一个使用这个 PVC 的 Pod。

下面是一个使用 my-pvc 的 Pod 的 YAML 文件示例:

apiVersion: v1
kind: Pod                   #资源类型
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx
    volumeMounts:
    - name: my-pvc-volume
      mountPath: /data
  volumes:
  - name: my-pvc-volume     #当前pod对应的pvc名称
    persistentVolumeClaim:
      claimName: my-pvc     #使用刚刚创建声明的pvc

在这个示例中,创建了一个名为 my-pod 的 Pod,并将其容器的 /data 目录挂载到 my-pvc-volume 卷中。该卷使用 my-pvc PVC。

Tips: 

当创建 my-pod Pod 时,Kubernetes 会自动扫描所有可用的 PV,并选择一个 PV 来满足 my-pvc PVC 的要求

如果找到了可用的 PV,则将其绑定到 my-pvc,并将 my-pvc-volume 卷挂载到容器中的 /data 目录。

2.6 结论

PVC 是 Kubernetes 中非常有用的资源对象,它允许将应用程序和存储资源的生命周期分开,并在应用程序重新部署或迁移时保留持久存储数据

通过上面的示例,可以了解如何创建 PVC,并将其用于 Pod。

拓展一下: 

Kubernetes 中 PVC 和 PV 的设计,实际上类似于“接口”和“实现”的思想

  1. 开发者只要知道并会使用“接口”,即:PVC;
  2. 而运维人员则负责给“接口”绑定具体的实现,即:PV。

这种解耦就避免了因为向开发者暴露过多的存储系统细节而带来的隐患。

此外,这种职责的分离,往往也意味着出现事故时可以更容易定位问题和明确责任,从而避免“扯皮”现象的出现。

3 存储状态

3.1 问题

思考一下这个问题:

 3.2 问题解答

前面已经了解到,当 Pod 被删除时,与之关联的 PVC 不会被删除,这些 PVC 可以在之后的 Pod 中继续使用。

来看下StatefulSet 怎么做到的

首先: 

StatefulSet 的控制器直接管理的是 Pod。

因为,StatefulSet 里的不同 Pod 实例,不像 ReplicaSet 中那样都是完全一样的,而是有了细微区别的。

比如,每个 Pod 的 hostname、名字等都是不同的、携带了编号的。而 StatefulSet 区分这些实例的方式,就是通过在 Pod 的名字里加上事先约定好的编号。

 其次:

Kubernetes 通过 Headless Service,为这些有编号的 Pod,在 DNS 服务器中生成带有同样编号的 DNS 记录

只要 StatefulSet 能够保证这些 Pod 名字里的编号不变,那么 Service 里类似于

web-0.nginx.default.svc.cluster.local 这样的 DNS 记录也就不会变,而这条记录解析出来的 Pod 的 IP 地址,则会随着后端 Pod 的删除和再创建而自动更新。这是 Service 机制本身的能力,不需要 StatefulSet 操心。

最后: 

StatefulSet 还为每一个 Pod 分配并创建一个同样编号的 PVC

这样,Kubernetes 就可以通过 Persistent Volume 机制为这个 PVC 绑定上对应的 PV,从而保证了每一个 Pod 都拥有一个独立的 Volume。

在这种情况下,即使 Pod 被删除,它所对应的 PVC 和 PV 依然会保留下来

所以,当这个 Pod 被重新创建出来之后,Kubernetes 会为它找到同样编号的 PVC,挂载这个 PVC 对应的 Volume,从而获取到以前保存在 Volume 里的数据。

 3.3 yaml示例

apiVersion: apps/v1
kind: StatefulSet #资源类型
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: mypvc
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates: #pvc声明
  - metadata:
      name: mypvc
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi

在这个yaml中:添加了一个 volumeClaimTemplates 字段。

它跟 Deployment 里 Pod 模板(PodTemplate)的作用类似。凡是被这个 StatefulSet 管理的 Pod,都会声明一个对应的 PVC;

而这个 PVC 的定义,就来自于 volumeClaimTemplates 这个模板字段。更重要的是,这个 PVC 的名字,会被分配一个与这个 Pod 完全一致的编号。

这个自动创建的 PVC,与 PV 绑定成功后,就会进入 Bound 状态,这就意味着这个 Pod 可以挂载并使用这个 PV 了。 

3.4 创建

 使用 kubectl create 创建了 StatefulSet 之后,就会看到 Kubernetes 集群里出现了两个 PVC:

kubectl create -f statefulset.yaml

3.5 查看结果

执行创建命令:

kubectl get pvc -l app=nginx

 结果如下:

NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
mypvc-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           48s
mypvc-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO           48s

前面已讲到过,这个 StatefulSet 创建出来的所有 Pod,都会声明使用编号的 PVC

可以看到,这些 PVC,都以“<PVC 名字 >-<StatefulSet 名字 >-< 编号 >”的方式命名,并且处于 Bound 状态。 

3.6 总结

1. 可以看出StatefulSet 其实就是一种特殊的 Deployment,它的特别之处在于,赋予了pod在整个集群里唯一的、可被的访问身份主要通过它对创建的每个 Pod 都进行了编号

2. 就是这个编号给了pod一个唯一的身份,并且,这个编号还会体现在 Pod 的名字和 hostname 等标识信息上,这不仅代表了 Pod 的创建顺序,也是 Pod 的重要网络标识

3. 有了编号后,StatefulSet 就使用 Kubernetes 里的两个标准功能:

  1. Headless Service
  2. PV/PVC

实现了对 Pod 的拓扑状态和存储状态的维护。

4 投票

有关【K8S系列】深入解析StatefulSet(二)的更多相关文章

  1. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

  5. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  6. ruby-on-rails - 我更新了 ruby​​ gems,现在到处都收到解析树错误和弃用警告! - 2

    简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und

  7. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  8. 阿里云RDS——产品系列概述 - 2

    基础版云数据库RDS的产品系列包括基础版、高可用版、集群版、三节点企业版,本文介绍基础版实例的相关信息。RDS基础版实例也称为单机版实例,只有单个数据库节点,计算与存储分离,性价比超高。说明RDS基础版实例只有一个数据库节点,没有备节点作为热备份,因此当该节点意外宕机或者执行重启实例、变更配置、版本升级等任务时,会出现较长时间的不可用。如果业务对数据库的可用性要求较高,不建议使用基础版实例,可选择其他系列(如高可用版),部分基础版实例也支持升级为高可用版。基础版与高可用版的对比拓扑图如下所示。优势 性能由于不提供备节点,主节点不会因为实时的数据库复制而产生额外的性能开销,因此基础版的性能相对于

  9. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

  10. ruby - 如何使用 Nokogiri 解析纯 HTML 表格? - 2

    我想用Nokogiri解析HTML页面。页面的一部分有一个表,它没有使用任何特定的ID。是否可以提取如下内容:Today,3,455,34Today,1,1300,3664Today,10,100000,3444,Yesterday,3454,5656,3Yesterday,3545,1000,10Yesterday,3411,36223,15来自这个HTML:TodayYesterdayQntySizeLengthLengthSizeQnty345534345456563113003664354510001010100000344434113622315

随机推荐