k8s 控制器-Statefulset

Posted 笨小孩@GF 知行合一

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了k8s 控制器-Statefulset相关的知识,希望对你有一定的参考价值。

  • StatefulSet 是为了管理有状态服务的问题而设计

  • 扩展:有状态服务?
    StatefulSet 是有状态的集合,管理有状态的服务,它所管理的 Pod 的名称不能随意变化。数据持久化的目录也是不一样,每一个 Pod 都有自己独有的数据持久化存储目录。比如 mysql 主从、redis集群等。
     
  • Deployment 管理 pod,pod 名字怎么组成?
    replicaset-随机数
    无状态服务?
    RS、Deployment、DaemonSet 都是管理无状态的服务,它们所管理的 Pod 的 IP、名字,启停顺序等都是随机的。个体对整体无影响,所有 pod 都是共用一个数据卷的,部署的 tomcat 就是无状态的服务,tomcat 被删除,在启动一个新的 tomcat,加入到集群即可,跟 tomcat 的名字无关。
     
  • StatefulSet 由以下几个部分组成:

    1. Headless Service(没有 ip 的 service):用来定义 pod 网路标识,生成可解析的 DNS 记录service ip 存在哪?iptables 或者 ipvs 规则中

    2. volumeClaimTemplates:存储卷申请模板,创建 pvc,指定 pvc 名称大小,自动创建 pvc,且 pvc 由存储类供应。

    3. StatefulSet:管理 pod 的
     
  • 扩展:什么是 Headless service?
    Headless service 不分配 clusterIP,headless service 可以通过解析 service 的 DNS,返回所有Pod 的 dns 和 ip 地址 (statefulSet 部署的 Pod 才有 DNS),普通的 service,只能通过解析 service 的DNS 返回 service 的 ClusterIP。
  • 为什么要用 headless service(没有 service ip 的 service)?

  • 在使用 Deployment 时,创建的 Pod 名称是没有顺序的,是随机字符串

    用 statefulset 管理pod 时要求 pod 名称必须是有序的 ,每一个 pod 不能被随意取代,pod 重建后 pod 名称还是一样

    因为 pod IP 是变化的,所以要用 Pod 名称来识别。pod 名称是 pod 唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个 Pod 一个唯一的名称。

  • 1.headless service 会为 service 分配一个域名 <service name>.$<namespace name>.svc.cluster.local

    K8s 中资源的全局 FQDN 格式:
     Service_NAME.NameSpace_NAME.Domain.LTD.
     Domain.LTD.=svc.cluster.local. #这是默认 k8s 集群的域名。

    FQDN 全称 Fully Qualified Domain Name 即全限定域名:同时带有主机名和域名的名称

    FQDN = Hostname + DomainName

    如 主机名是 GF
    域名是 beyond.com
    FQDN= GF.beyond.com



    2.StatefulSet 会为关联的 Pod 保持一个不变的 Pod Name
    statefulset 中 Pod 的名字格式为$(StatefulSet name)-$(pod 序号)


    3.StatefulSet 会为关联的 Pod 分配一个 dnsName
    $<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local

     

  • 为什么要用 volumeClaimTemplate?

    对于有状态应用都会用到持久化存储,比如 mysql 主从,由于主从数据库的数据是不能存放在一个目录下的,每个 mysql 节点都需要有自己独立的存储空间

    而在 deployment 中创建的存储卷是一个共享的存储卷,多个 pod 使用同一个存储卷,它们数据是同步的,而 statefulset 定义中的每一个 pod 都不能使用同一个存储卷,这就需要使用 volumeClaimTemplate


    当在使用 statefulset 创建 pod 时,volumeClaimTemplate 会自动生成一个 PVC,从而请求绑定一个 PV,每一个 pod 都有自己专用的存储卷。

    Pod、PVC 和 PV 对应的关系图如下:


  •  Statefulset 资源清单文件编写技巧

  • #查看定义 Statefulset 资源需要的字段

  • [~]# kubectl explain statefulset
    KIND: StatefulSet
    VERSION: apps/v1
    DESCRIPTION:
     StatefulSet represents a set of pods with consistent identities. Identities
     are defined as:
     - Network: A single stable DNS and hostname.
     - Storage: As many VolumeClaims as requested. The StatefulSet guarantees
     that a given network identity will always map to the same storage identity.
    FIELDS:
     apiVersion <string> #定义 statefulset 资源需要使用的 api 版本
     kind <string> #定义的资源类型
     metadata <Object> #元数据
     spec <Object> #定义容器相关的信息

    #查看 statefulset.spec 字段如何定义?
    [~]# kubectl explain statefulset.spec
    KIND: StatefulSet
    VERSION: apps/v1
    RESOURCE: spec <Object>
    DESCRIPTION:
     Spec defines the desired identities of pods in this set.
     A StatefulSetSpec is the specification of a StatefulSet.
    FIELDS:
     podManagementPolicy <string> #pod 管理策略
     replicas <integer> #副本数
     revisionHistoryLimit <integer> #保留的历史版本
     selector <Object> -required- #标签选择器,选择它所关联的 pod
     serviceName <string> -required- #headless service 的名字
     template <Object> -required- #生成 pod 的模板
     updateStrategy <Object> #更新策略
     volumeClaimTemplates <[]Object> #存储卷申请模板



    #查看 statefulset 的 spec.template 字段如何定义?
    #对于 template 而言,其内部定义的就是 pod,pod 模板是一个独立的对象


    [~]# kubectl explain statefulset.spec.template
    KIND: StatefulSet
    VERSION: apps/v1
    RESOURCE: template <Object>
    DESCRIPTION:

    FIELDS:

     metadata <Object>
     spec <Object> #定义容器属性


    通过上面可以看到,statefulset 资源中有两个 spec 字段

    第一个 spec 声明的是 statefulset 定义多少个 Pod 副本(默认将仅部署 1 个 Pod)、匹配 Pod 标签的选择器、创建 pod 的模板、存储卷申请模板

    第二个 spec 是 spec.template.spec:主要用于 Pod 里的容器属性等配置。

    tatefulset.spec.template 里的内容是声明 Pod 对象时要定义的各种属性,所以这部分也叫做 PodTemplate(Pod 模板)。

    还有一个值得注意的地方是:在tatefulset.spec.selector 中定义的标签选择器必须能够匹配到spec.template.metadata.labels 里定义的 Pod 标签,否则 Kubernetes 将不允许创建 statefulset。
     


  • Statefulset 使用案例-部署 web 站点

  • 1、创建运行 nfs-provisioner 需要的 sa 账号
    vim serviceaccount.yaml

    2、对 sa 授权
    kubectl create clusterrolebinding nfs-provisioner --clusterrole=cluster-admin --serviceaccount=default:nfs-provisioner 

 3、安装 nfs-provisioner 程序
# mkdir /data/nfs_pro -p
#把/data/nfs_pro 变成 nfs 共享的目录
vim /etc/exports

vim nfs-deployment.yaml

 provisioner 相当于一个 pod,必须正常运行才可以

  • 4、#创建存储类
    # vim class-web.yaml

     
    vim statefulset.yaml

     #通过上面可以看到创建的 pod 是有序的 web-[ ]

  • #使用 kubectl run 运行一个提供 nslookup 命令的容器的,改命令来自于 dnsutils 包,通过对pod 主机名执行 nslookup,可以检查它们在集群内部的 DNS 地址:

    kubectl exec -it web-0 -- /bin/bash
    apt update

    apt install dnsutils -y
    nslookup web-0.nginx.default.svc.cluster.local

    #statefulset 创建的 pod 也是有 dns 记录的

    Server:        10.96.0.10
    Address:    10.96.0.10#53

    Name:    nginx.default.svc.cluster.local
    Address: 10.244.61.198
    Name:    nginx.default.svc.cluster.local
    Address: 10.244.179.6

     资源清单详细解读:

    apiVersion: v1 #定义 api 版本
    kind: Service #定义要创建的资源:service

    metadata: 
     name: nginx #定义 service 的名字
     labels:
     app: nginx #service 的标签
    spec:
     ports:
     - port: 80
     name: web
     clusterIP: None #创建一个没有 ip 的 service
     selector:
     app: nginx #选择拥有 app=nginx 标签的 pod
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata: 
     name: web
    spec:
     selector:
     matchLabels:
     app: nginx
     serviceName: "nginx" # 上面定义的 headless service 的名字
     replicas: 2 #副本数
     template: #定义 pod 的模板

     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: "nfs-web" #指定从哪个存储类申请 pv
         resources:
           requests: 
             storage: 1Gi #需要 1G 的 pvc,会自动跟符合条件的 pv 绑定


  • Statefulset 管理 pod-扩容、缩容、更新

  • Statefulset 实现 pod 的动态扩容
     

  • 如果觉得两个副本太少了,想要增加,只需要修改配置文件 statefulset.yaml 里的 replicas 的值即可,原来 replicas: 2,现在变成 replicaset: 3,修改之后,执行更新:

     也可以直接编辑控制器实现扩容,这个是把请求提交给了 apiserver,实时修改

     Statefulset 实现 pod 的动态缩容
    如果觉得 4 个 Pod 副本太多了,想要减少,只需要修改配置文件 statefulset.yaml 里的replicas 的值即可,把 replicaset:4 变成 replicas: 2,修改之后,执行更新:

     #Statefulset 实现 pod 里面容器 的更新
    kubectl edit statefulsets.apps web
    #修改镜像 nginx 变成- image: ikubernetes/myapp:v2,修改之后保存退出

     

  • k8s 配置管理中心-Configmap

  •  
  • Configmap 概述

  • 什么是 Configmap?
    Configmap 是 k8s 中的资源对象,用于保存非机密性的配置的,数据可以用 key/value 键值对的形式保存,也可通过文件的形式保存。

  • Configmap 能解决哪些问题?
    在部署服务的时候,每个服务都有自己的配置文件,如果一台服务器上部署多个服务:nginx、tomcat、apache 等,那么这些配置都存在这个节点上,假如一台服务器不能满足线上高并发的要求,需要对服务器扩容,扩容之后的服务器还是需要部署多个服务:nginx、tomcat、apache,新增加的服务器上还是要管理这些服务的配置,如果有一个服务出现问题,需要修改配置文件,每台物理节点上的配置都需要修改,这种方式肯定满足不了线上大批量的配置变更要求。


    所以,k8s 中引入了 Configmap资源对象,可以当成 volume 挂载到 pod 中,实现统一的配置管理。
  • 1、Configmap 是 k8s 中的资源, 相当于配置管理中心,可以有一个或者多个 Configmap;
    2、Configmap 可以做成 Volume,k8s pod 启动之后,通过 volume 形式映射到容器内部指定目录上;

  • Configmap 应用场景
    1、使用 k8s 部署应用,当你将应用配置写进代码中,更新配置时也需要打包镜像,configmap 可以将配置信息和 docker 镜像解耦,以便实现镜像的可移植性和可复用性,因为一个 configMap 其实就是一系列配置信息的集合,可直接注入到 Pod 中给容器使用。configmap 注入方式有两种,一种将configMap 做为存储卷,一种是将 configMap 通过 env 中 onfigMapKeyRef 注入到容器中。

    2、使用微服务架构的话,存在多个服务共用配置的情况,如果每个服务中单独一份配置的话,那么更新配置就很麻烦,使用 configmap 可以友好的进行配置共享。


    局限性
    ConfigMap 在设计上不是用来保存大量数据的。在 ConfigMap 中保存的数据不可超过 1 MiB。
    如果你需要保存超出此尺寸限制的数据,可以考虑挂载存储卷或者使用独立的数据库或者文件服务。

  • Configmap 创建方法

  • 编写 configmap 资源清单 YAML 文件

    # vim mysql-configmap.yaml

     使用 Configmap,把 configmap 做成 volume,挂载到 pod
    vim mysql-pod-volume.yaml

     

以上是关于k8s 控制器-Statefulset的主要内容,如果未能解决你的问题,请参考以下文章

k8s之StatefulSet

K8S使用Statefulset管理集群pod模式

从零开始入门 K8s | 有状态应用编排 - StatefulSet

从零开始入门 K8s | 有状态应用编排 - StatefulSet

k8s持久化状态存储原理

k8s运行DaemonSet控制器管理pod