糖呀糖啦~Pleiades
首页
归档
关于
友链
切换模式
返回顶部
首页
技术实践
书斋絮语
晴天札记
糖呀糖啦~Pleiades
首页
技术实践
书斋絮语
晴天札记
首页
归档
关于
友链
【Kubernetes】StatefulSet
技术实践
·
29 天前
糖呀糖 xyz
在 Kubernetes 系统中, Pod 的管理对象 RC、Deployment、DaemonSet 和 Job 都面向 **无状态的服务**。 但现实中很多服务是有状态的,特别是一些复杂的中间件集群,例如 MySQL 集群、MongoDB 集群、Akka 集群、ZooKeeper 集群等,这些 **应用集群** 有 4 个共同点: - 每个节点都有固定的身份 ID,通过这个 ID,集群中的成员可以相互发现并通信; - 集群的规模是比较固定的,集群规模不能随意变动 - 集群中的每个节点都是有状态的,通常会持久化数据到永久存储中 - 如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。 # Pod 命名规则 注意,通过 RC 或者 Deployment 创建的 Pod 不是完全固定的: ## 通过 RC 创建的 Pod 命名为:`
-xxxx` - RC 名称是固定部分 - xxxx 是随机生成的字符串 - 当 Pod 被删除重建时,随机字符串会改变 ## 通过 Deployment 创建的 Pod 命名为:`
-
-xxxx` - deployment-name shi guding d bufen - replicaset-hash 是基于 Pod template 生成的哈希值 - xxxx 是随机生成的字符串 也可以在 YAML 中定义 Pod 的名称: ```yaml apiVersion: v1 kind: Pod metadata: name: my-pod-name # 直接定义 Pod 名称 ``` 所以,如果通过 RC 或 Deployment 控制 Pod 副本数量来实现上述有状态的集群,就会发现第一点无法满足,因为 Pod 的名称是随机产生的, Pod 的 IP 地址也是在运行期才确定且有可能改变的,所以无法事先为每个 Pod 都确定唯一不变的 ID。 为了能够在其他节点上恢复某个失败的节点,这种集群中的 Pod 需要挂载某种共享存储,所以从 Kubernetes 1.4 版本开始引入了 PetSet 这个新的资源对象,并在 1.5 版本时更名为 StatefulSet。 所以 StatefulSet 从本质上来说,可以看做 Deployment / RC 的一个特殊变种。 # StatefulSet 特性 - StatefulSet 里的每个 Pod 都有`稳定`、`唯一`的`网络标识`,可以用来`发现集群内的其他成员`。eg. StatefulSet 的名称为 kakfa,那么第一个 Pod 叫 `kafka-0`、第二个叫 `kafka-1` - StatefulSet 控制的 Pod 副本的`启停顺序是受控`的,操作第 n 个 Pod 时,前 n-1 个 Pod 已经是运行且准备好的状态 - StatefulSet 里的 Pod 采用`稳定的` `持久化存储卷`,通过 PV 或者 PVC 来实现,删除 Pod 时默认不会删除与 StatefulSet 相关的存储卷 # Headless Service StatefulSet 除了要与 PV 卷捆绑使用以存储 Pod 的状态数据,还要与 Headless Service 配合使用,即 在每个 StatefulSet 定义中都要生命它属于哪个 Headless Service。 Headless Service 与 普通 Service 的关键区别在于,它没有 Cluster IP,如果解析 Headless Service 的 DNS 域名,则返回的是该 Service 对应的全部 Pod 的 Endpoint 列表。 StatefulSet 在 Headless Service 的基础上又为 StatefulSet 控制的每个 Pod 实例都创建了一个 DNS 域名,这个域名的格式为 `$(podname).$(headless service name)` 比如一个 3 节点的 Kafka 的 StatefulSet 集群对应的 Headless Service 的名称为 kafka,StatefulSet 的名称为 kafka,则 StatefulSet 里的 3 个 Pod 的 DNS 名称分别为 kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,这些 DNS 名称可以直接在集群的配置文件中固定下来。 ## Headless Service 定义文件 ```yaml apiVersion: v1 kind: Service metadata: name: mysql spec: clusterIP: None # 关键点:设置为 None 使其成为 Headless selector: app: mysql ports: - port: 3306 ``` - 没有固定的 Cluster IP - 直接返回所有 Pod 的 IP - 可以访问特定的 Pod ## DNS 域名解析 假设有一个 MySQL 集群: ```yaml # Headless Service apiVersion: v1 kind: Service metadata: name: mysql spec: clusterIP: None selector: app: mysql ports: - port: 3306 --- # StatefulSet apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: mysql # 关联到上面的 Headless Service replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql ``` 会创建如下的 DNS 记录: ### 单个 Pod 域名 mysql-0.mysql.default.svc.cluster.local mysql-1.mysql.default.svc.cluster.local mysql-2.mysql.default.svc.cluster.local ### Service 域名 mysql.default.svc.cluster.local ## 实际应用场景 以 MySQL 主从复制为例: ### 主库(master) ```bash # 总是访问 mysql-0 mysql -h mysql-0.mysql ``` ### 从库(slave) ```bash # 可以访问 mysql-1 或 mysql-2 mysql -h mysql-1.mysql mysql -h mysql-2.mysql ``` 为什么这么设计: - 固定身份 - 每个 Pod 有唯一的网络标识 - 重启后 Pod 名称和网络标识不变 - 便于其他服务定位特定 Pod - 有序部署 - Pod 按顺序创建:mysql-0, mysql-1, mysql-2 - 按相反顺序删除:mysql-2, mysql-1, mysql-0 - 确保数据一致性 - 主从架构 - 容易识别主节点(通常是 -0) - 从节点可以找到主节点 - 便于配置复制关系 # 有状态 和 无状态 ## 无状态(Stateless) 假设一个自助餐厅的服务员: - 每个服务员都可以为任何客人服务 - 不需要记住客人之前点过什么 - 服务员可以随时更换,不影响服务质量 - 客人的每次请求都是独立的 比如: ### Web 服务器 - 处理 HTTP 请求 - 不需要记住用户上一次的请求 - 每个请求都是独立的 - 任何服务器实例都能处理请求 ### 无状态 API `GET /api/products/1` - 不知道之前的请求 - 响应仅依赖于当前请求参数 ## 有状态(Stateful) 一个特定的理发店的理发师: - 需要记住客人的发型偏好 - 要知道上次理发的长度 - 不能随意更换理发师 - 服务是连续的,有上下文关联 比如: ### 数据库 - 需要持久化存储数据 - 主从节点有固定的角色 - 需要维护数据一致性 - 每个实例都是独特的 ### 购物车会话 ```bash Session ID: abc123 Cart Items: [item1, item2] ``` - 需要记住用户的购物记录 - 需要追踪会话状态 ## 为什么要区分有状态无状态 ### 部署策略不同 - 无状态:可以随意部署、销毁 - 例如 ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: webserver ``` - 有状态:需要特殊处理 ```yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql ``` ### 数据处理方式 - 无状态:不需要考虑数据持久化 - 有状态:需要持久化存储(PV / PVC) ```yaml volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi ``` ### 扩展性考虑 - 无状态:可以随意扩展 ```bash kubectl scale deployment webserver --replicas=5 ``` - 有状态:需要考虑数据同步 ```bash kubectl scale statefulset mysql --replicas=3 # 需要考虑数据复制 ``` ### 故障恢复 - 无状态:直接重启新实例 - 有状态:需要恢复数据和状态 ## 实际应用建议 ### 优先考虑无状态设计 - 更容易扩展 - 更容易维护 - 更适合云原生架构 ### 状态外部化 - 将状态存储在专门的存储服务中 - 使用缓存服务(如 Redis) - 使用数据库服务 ### 合理使用 有状态服务 - 必要的数据库服务 - 需要持久化的消息队列 - 分布式存储系统 # References - claude 3.5 sonnet - Kubernetes 权威指南:从 Docker 到 Kubernetes 实践全接触(第 4 版)
Kubernetes
取消回复
提交评论
糖呀糖 xyz
我们谈论生活,讨论技术,借由文字,抵达心灵。
热门文章
【Kubernetes】第一个实例 - Java Web 应用
Obsidian 迁移全记录(又名:纯小白的闭坑指南)
使用宝塔面板对网站、数据库等进行定时备份到腾讯云 COS 对象存储
2025 年
在细雨中呼喊,在困顿中挣扎
Ubuntu 22.04 server 安装教程
Debian 12.2 安装方法
最新评论
tl.s: 很实用 🦆🦆
tl.s: 绘图很清晰,图示质量很高
tl.s: 写的很详细,赞👍
Deep Router: 大佬好强!!!
tls: 写的很详细,很清晰!
tl.s: 讲的很清楚,语言组织很好 🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆
tl.s: 好棒🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆🦆
热门标签
Kubernetes
Ubuntu
Linux
Python3
生活
2025
Debian
技术实践
在细雨中呼喊
读书笔记
笔记软件
Obsidian
2024
openEuler
Kuboard
粤ICP备2024349207号