K8S-Statefulset控制器

在 Kubernetes 的世界里,服务通常分为有状态和无状态两种类型。对于无状态服务,我们可以轻松地使用 Deployment 或 RC 来管理,但当面对需要稳定网络标识和持久化存储的有状态服务时,StatefulSet 就成为了最佳选择。本文将深入解析 StatefulSet 控制器的核心概念、工作原理及实际应用。

一、StatefulSet 核心概念解析

有状态服务 vs 无状态服务

Kubernetes 中存在两种服务类型,它们的管理方式有着本质区别:

  • 无状态服务:由 RC、Deployment、DaemonSet 等控制器管理,其 Pod 的 IP、名称、启停顺序都是随机的,个体对整体无影响,所有 Pod 共享相同的数据卷(如 Tomcat 集群)

  • 有状态服务:由 StatefulSet 管理,其 Pod 名称固定不变,每个 Pod 拥有独立的持久化存储目录,适用于需要稳定标识和状态的服务(如 MySQL 主从、Redis 集群等)

StatefulSet 的三大组成部分

  1. Headless Service:用于定义 Pod 的网络标识,生成可解析的 DNS 记录
  2. volumeClaimTemplates:存储卷申请模板,自动创建 PVC,为每个 Pod 提供独立存储
  3. StatefulSet 控制器:核心管理组件,负责 Pod 的创建、更新和维护

Headless Service 详解

Headless Service 是 StatefulSet 的关键组件,它与普通 Service 的最大区别是不分配 ClusterIP。通过解析其 DNS 可以直接返回所有关联 Pod 的 DNS 和 IP 地址(这是 StatefulSet 部署的 Pod 独有的特性)。

为什么需要 Headless Service?

  • StatefulSet 要求 Pod 名称必须有序且固定,重建后名称保持不变
  • Pod IP 是变化的,需要用固定的 Pod 名称作为唯一标识符
  • 提供稳定的网络标识,确保服务发现的可靠性

Headless Service 会为自身分配固定域名:

plaintext

复制代码
<service name>.<namespace name>.svc.cluster.local

而每个 Pod 则会获得如下格式的 DNS 名称:

plaintext

复制代码
<pod name>.<service name>.<namespace name>.svc.cluster.local

二、StatefulSet 资源清单编写指南

StatefulSet 的资源清单包含几个关键部分,我们可以通过kubectl explain命令查看详细定义:

bash

运行

复制代码
# 查看StatefulSet的顶级字段
kubectl explain statefulset

# 查看spec字段详情
kubectl explain statefulset.spec

# 查看Pod模板字段
kubectl explain statefulset.spec.template

StatefulSet 清单的核心字段说明:

  • spec.replicas:指定副本数量
  • spec.selector:标签选择器,必须匹配 Pod 模板中的标签
  • spec.serviceName:关联的 Headless Service 名称(必填)
  • spec.template:Pod 模板定义
  • spec.volumeClaimTemplates:存储卷申请模板

注意:StatefulSet 中有两个 spec 字段,外层 spec 用于定义 StatefulSet 属性,内层 spec(spec.template.spec)用于定义 Pod 容器属性

三、StatefulSet 实战:部署 Web 站点

下面通过一个实例演示如何使用 StatefulSet 部署 Web 服务:

1. 编写资源清单文件

创建statefulset.yaml文件,包含 Headless Service 和 StatefulSet 定义:

yaml

复制代码
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
  labels:
     app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: "None"  # 定义为Headless Service
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx-svc"  # 关联Headless Service
  replicas: 2  # 两个副本
  template:
    metadata:
     labels:
       app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: web

2. 部署并验证

bash

运行

复制代码
# 应用配置
kubectl apply -f statefulset.yaml

# 查看StatefulSet
kubectl get statefulset

# 查看创建的Pod(名称是有序的)
kubectl get pods -l app=nginx

# 查看Headless Service
kubectl get svc -l app=nginx

执行结果会显示两个有序命名的 Pod:web-0web-1,以及一个类型为 ClusterIP 且 CLUSTER-IP 为 None 的 Headless Service。

3. 验证 DNS 解析

创建一个测试 Pod 验证 DNS 解析功能:

yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
spec:
  containers:
  - name: busybox
    image: busybox:1.28
    command: ["sh","-c","sleep 3600"]

部署后进入容器测试:

bash

运行

复制代码
# 进入测试Pod
kubectl exec -it pod-second -- /bin/sh

# 解析单个Pod的DNS
nslookup web-0.nginx-svc.default.svc.cluster.local

# 解析Headless Service(会返回所有Pod的IP)
nslookup nginx-svc.default.svc.cluster.local

四、StatefulSet 管理操作

动态扩容

有两种方式可以实现 StatefulSet 的扩容:

  1. 修改配置文件中的replicas值后应用:

bash

运行

复制代码
kubectl apply -f statefulset.yaml
  1. 直接编辑 StatefulSet 配置:

bash

运行

复制代码
kubectl edit sts web
# 修改spec.replicas的值

扩容时,StatefulSet 会按照序号递增的顺序创建新 Pod(如 web-2、web-3 等)。

动态缩容

缩容操作与扩容类似,只需减小replicas的值。需要注意的是,StatefulSet 会按照序号递减的顺序删除 Pod(先删除序号最大的)。

bash

运行

复制代码
# 修改配置文件后应用
kubectl apply -f statefulset.yaml

版本更新

更新 StatefulSet 管理的 Pod 镜像:

bash

运行

复制代码
# 编辑StatefulSet配置
kubectl edit sts web
# 修改spec.template.spec.containers.image的值

更新时,StatefulSet 会按照序号从高到低的顺序逐个更新 Pod,确保服务的连续性。

五、经典面试题:Service 与 Headless Service 的区别

特性 普通 Service Headless Service
ClusterIP 分配唯一的 ClusterIP 无 ClusterIP
DNS 解析 返回 Service 的 ClusterIP 返回所有关联 Pod 的 IP 列表
适用场景 无状态服务、负载均衡 有状态服务、需要明确知道每个 Pod
Pod 标识 随机名称 固定有序名称

通过nslookup命令可以直观看到区别:

  • 普通 Service 解析返回 ClusterIP
  • Headless Service 解析返回所有 Pod 的 IP 地址
相关推荐
菜地里的小菜鸟5 天前
failed to get imageFs info: non-existent label “docker-images
k8s·failedtogetimagefsin·k8s报错
菜地里的小菜鸟7 天前
kubectl debug
k8s·kubectldebug
腾飞开源9 天前
01_K8s干货笔记之认识K8s
运维·笔记·云原生·容器·kubernetes·k8s·容器化部署
小匠石钧知12 天前
02_在多个RockyLinux10虚拟机上安装k8s集群
云原生·容器·kubernetes·k8s
ShirleyWang01218 天前
让headlamp控制台能访问
linux·服务器·python·k8s·k3s
spider_xcxc18 天前
K8s 部署学习笔记
docker·容器·kubernetes·云计算·k8s
ShirleyWang01218 天前
Day02 K3s NGF(Nginx Gateway Fabric)单 Worker 环境网关更新与故障处置 SOP
linux·服务器·python·k8s·k3s
ShirleyWang01218 天前
DAY01 K3s 私有化部署排障复盘与 SOP
linux·服务器·k8s·k3s·企业部署
XUHUOJUN21 天前
AKS 不是安装在 Windows Server 上,而是运行在 Windows Server 之上的 Azure 平台能力
windows·架构·k8s·azure local·azure stack
Geek-Chow22 天前
Connecting kubectl to a Private EKS Cluster Over an Internal Domain
kubernetes·k8s·aws