K8s: 控制器之StatefulSets对象

StatefulSet

1 ) 概述

  • Stateful,也就是有状态应用,微服务无状态是一个理想的这么一个环境
  • 有些应用是有状态的,比如这个web服务器,它只能运行在一台server上
  • 因为它要访问一些持久化的存储
  • 比如说 mysql 它就是一个典型的有状态的应用,不希望应用随时漂移到别的节点上,然后数据发生变化
  • 为什么说它有状态?
    • 就是因为它的数据是落在这个磁盘上的
    • 虽然云原生应用里面,尽量的把一些服务都变成云原生的应用
    • 在实际生活中,在实际企业开发中,很多应用它是有状态的
  • 那什么是无状态的呢?
    • 比如一个博客应用,它是无状态的,它不依赖于你底层的数据库服务地址
    • 这个应用可以部署多个
  • 在这个mysql服务器,它是有状态的应用,K8s为了应对,提出了 StatefulSets 的概念
  • StatefulSets 它是用来管理Deployment和扩展一组Pod,并且为这个pod提供序号唯一性的保证
  • 所以它和Deployment的不同是在于
    • 它管理了一组相同容器定义的pod, 它为每个Pod维护了一个固定的ID
    • 在Deployment,它的ID是一个Pod名称加后面随机字母的组合,它的名称是动态拼出来的
    • 但是,StatefulSet的pod, 它的容器名称有一个永久不变的ID, 如果建3个,就会变成 -0, -1, -2 这样的不变ID
  • StatefulSets 会定义你期望的一个状态,比如说你有3个副本,它会给你创建3个副本
  • StatefulSets 的使用场景
    • 有稳定唯一的网络标识符
    • 有一个稳定的持久化的存储,可以有序的去缩放,有序的去更新扩容
      • 有序的是指更新是从012345...按顺序更新,而不是随机的去更新
    • 这样的应用更适合 StatefulSets 来管理,而不是Deployment
  • StatefulSets 的限制
    • 必须有这个挂载 PersistentVolume 挂载卷,可以是本地,也可以是对象存储
    • 需要有一个外部的持久化化存储,基于 storage class来匹配,那么这里面有一点很重要
    • 注意,如果说删掉 StatefulSets 中的pod并不会删除它的关联的存储
    • 这样是保证数据的安全,而在Deployment里删除pod, 其创建的临时数据文件都会消失
    • 对于 StatefulSets 它其实更着重的是这些数据
  • 所以 K8s 它设计的时候,存储这个对象和 StatefulSets,是两个隔离的对象
  • 另外,StatefulSets 需要用 headless 服务来创建pod标识
  • headless叫无头服务
    • 就是我的请求, 有时候不想走负载均衡,直接想通过IP链接到后端
    • 这个时候在 K8s 中,它就提供这个headless这个服务
    • 在HTTP发请求的时候发一个post请求之前,会发一个head请求,这个headless请求会做一些事情
    • 比如说对方后端的这个IP地址是哪里?做一些 session 的认证
    • headless请求, 就是直接能够不发这个head请求,直接和后端的服务进行一个交互,直接进行CRUD的操作
    • 在这种情况下, 需要要把这个 clusterip 设成为 none
    • 就是 StatefulSets 里面的 pod 在容器里面不用固定的IP

2 )应用

  • 在这里面,我们会先创建一个Service,然后再创建这个StatefulSets

  • 新建 sfs-demo1.yaml

    yaml 复制代码
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mongodb
    spec:
      serviceName: mongodb  #必须配置 和service名字统一起来
      replicas: 2
      selector:
        matchLabels:
          app: mongodb
      template:
        metadata:
          labels:
            app: mongodb
        spec:
          containers:
            - name: mongo
              image: mongo:4.4          
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: mongodb
    spec:
      selector:
        app: mongodb
      type: ClusterIP
      # HeadLess  
      clusterIP: None
      ports:
        - port: 27017    #本 Service 的端口
          targetPort: 27017  #容器的端口
  • $ kubectl apply -f sfs-demo1.yaml

    conf 复制代码
    statefulset.apps/mongodb created
    service/mongodb created
  • $ kubectl get all

    conf 复制代码
    NAME            READY   STATUS    RESTARTS   AGE
    pod/mongodb-0   1/1     Running   0          20s
    pod/mongodb-1   1/1     Running   0          19s
    
    NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE
    service/kubernetes   ClusterIP   10.1.0.1     <none>        443/TCP     6d2h
    service/mongodb      ClusterIP   None         <none>        27017/TCP   20s
    
    NAME                       READY   AGE
    statefulset.apps/mongodb   2/2     20s
  • $ kubectl rollout restart statefulset mongodb 重启

  • $ kubectl scale statefulset mongodb --replicas=5 扩容

  • $ kubectl get all

    conf 复制代码
    NAME            READY   STATUS    RESTARTS   AGE
    pod/mongodb-0   1/1     Running   0          3m31s
    pod/mongodb-1   1/1     Running   0          3m33s
    pod/mongodb-2   1/1     Running   0          2m33s
    pod/mongodb-3   1/1     Running   0          21s
    pod/mongodb-4   1/1     Running   0          20s
    
    NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE
    service/kubernetes   ClusterIP   10.1.0.1     <none>        443/TCP     6d2h
    service/mongodb      ClusterIP   None         <none>        27017/TCP   6m49s
    
    NAME                       READY   AGE
    statefulset.apps/mongodb   5/5     6m49s
  • $ kubectl get svc

    conf 复制代码
    NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE
    kubernetes   ClusterIP   10.1.0.1     <none>        443/TCP     6d2h
    mongodb      ClusterIP   None         <none>        27017/TCP   8m49s
  • $ kubectl get endpoints mongodb -o yaml

    conf 复制代码
    apiVersion: v1
    kind: Endpoints
    metadata:
      annotations:
        endpoints.kubernetes.io/last-change-trigger-time: "2024-04-23T06:21:28Z"
      creationTimestamp: "2024-04-23T06:14:58Z"
      labels:
        service.kubernetes.io/headless: ""
      name: mongodb
      namespace: default
      resourceVersion: "292772"
      uid: e600cd76-37e9-48c1-90f8-fae2b31bbbd4
    subsets:
    - addresses:
      - hostname: mongodb-1
        ip: 10.244.1.107
        nodeName: node1.k8s
        targetRef:
          kind: Pod
          name: mongodb-1
          namespace: default
          resourceVersion: "292407"
          uid: 654c1164-9a0d-46c0-8148-61f71a6e7224
      - hostname: mongodb-0
        ip: 10.244.1.108
        nodeName: node1.k8s
        targetRef:
          kind: Pod
          name: mongodb-0
          namespace: default
          resourceVersion: "292437"
          uid: cef974da-f02d-4d93-bb00-0c74d534c866
      - hostname: mongodb-3
        ip: 10.244.1.109
        nodeName: node1.k8s
        targetRef:
          kind: Pod
          name: mongodb-3
          namespace: default
          resourceVersion: "292757"
          uid: caf43581-9e7c-48db-a761-1cb74e0ea871
      - hostname: mongodb-2
        ip: 10.244.2.67
        nodeName: node2.k8s
        targetRef:
          kind: Pod
          name: mongodb-2
          namespace: default
          resourceVersion: "292743"
          uid: 1eeba1cb-0e50-45fa-81d2-f4022dbd8b63
      - hostname: mongodb-4
        ip: 10.244.2.68
        nodeName: node2.k8s
        targetRef:
          kind: Pod
          name: mongodb-4
          namespace: default
          resourceVersion: "292770"
          uid: 4e3dc9f3-4f28-4802-af9a-705c12404ae5
      ports:
      - port: 27017
        protocol: TCP
  • $ kubectl exec -ti mongodb-0 -- mongo 测试数据存储

    conf 复制代码
    MongoDB shell version v4.4.29
    connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
    Implicit session: session { "id" : UUID("74389cfe-1776-43ef-a37a-61cf5a7a9d82") }
    MongoDB server version: 4.4.29
    Welcome to the MongoDB shell.
    For interactive help, type "help".
    For more comprehensive documentation, see
      https://docs.mongodb.com/
    Questions? Try the MongoDB Developer Community Forums
      https://community.mongodb.com
    ---
    The server generated these startup warnings when booting:
            2024-04-23T06:18:17.563+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
            2024-04-23T06:18:17.563+00:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
    ---
    >
  • $ exit 退出

    conf 复制代码
    bye
  • $ run mongodb-client --rm --tty -i --restart='Never' --image mongo:4.4 --command -- bash 连接数据库测试

    conf 复制代码
    If you don't see a command prompt, try pressing enter.
    root@mongodb-client:/#
  • $ mongo --host mongodb-0.mongodb

    conf 复制代码
    MongoDB shell version v4.4.29
    connecting to: mongodb://mongodb-0.mongodb:27017/?compressors=disabled&gssapiServiceName=mongodb
    Implicit session: session { "id" : UUID("83892098-096c-4521-acf4-54aa13312392") }
    MongoDB server version: 4.4.29
    Welcome to the MongoDB shell.
    For interactive help, type "help".
    For more comprehensive documentation, see
      https://docs.mongodb.com/
    Questions? Try the MongoDB Developer Community Forums
      https://community.mongodb.com
    ---
    The server generated these startup warnings when booting:
            2024-04-23T06:18:17.563+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
            2024-04-23T06:18:17.563+00:00: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never'
    ---
    >

关于run相关参数

  • $ kubectl run nginx --image=nginx
    • 启动一个 Nginx 实例
  • $ kubectl run hazelcast --image=hazelcast --port=5701
    • 启动一个 hazelcast 单个实例,并开放容器的5701端口
  • $ kubectl run hazelcast --image=hazelcast --env="DNS_DOMAIN=cluster" --env="POD_NAMESPACE=default"
    • 运行一个 hazelcast 单个实例,并设置容器的环境变量"DNS_DOMAIN=cluster" and "POD_NAMESPACE=default"
  • $ kubectl run nginx --image=nginx --replicas=5
    • 启动一个 replicated 实例去复制 nginx
  • $ kubectl run nginx --image=nginx --dry-run
    • 试运行,不创建他们的情况下,打印出所有相关的 API 对象
  • $ kubectl run nginx --image=nginx --overrides='{ "apiVersion": "v1", "spec": { ... } }'
    • 用可解析的 JSON 来覆盖加载 deploymentspec,来运行一个 nginx 单个实例
    • 替换 ... 为具体key, value
  • $ kubectl run -i --tty busybox --image=busybox --restart=Never
    • 运行一个在前台运行的 busybox 单个实例,如果退出不会重启
相关推荐
老实巴交的麻匪3 小时前
Logs 可观测性 | Grafana Loki 架构窥探与实践
运维·云原生·容器
塑遂3 小时前
Kubernetes高级调度01
容器·kubernetes
MarkGosling3 小时前
【开源项目】轻量加速利器 HubProxy自建 Docker、GitHub 下载加速服务
docker·容器·github
MarkGosling4 小时前
【开源项目】轻量加速利器 HubProxy 自建 Docker、GitHub 下载加速服务
运维·git·docker·容器·开源·github·个人开发
chanalbert4 小时前
Docker网络技术深度研究与实战手册
docker·容器·自动化运维
东风微鸣5 小时前
AI 赋能的故障排除:技术趋势与实践
docker·云原生·kubernetes·可观察性
KubeSphere 云原生5 小时前
云原生周刊:2025年的服务网格
云原生
Etual5 小时前
云原生联调利器:Telepresence实战
云原生
陌上阳光18 小时前
docker搭建ray集群
docker·容器·ray
这就是佬们吗18 小时前
初识 docker [上]
java·开发语言·笔记·docker·容器