六、StatefulSet - 有状态应用管理
1. StatefulSet 基础概念
1.1 什么是 StatefulSet?
回顾一个问题:
在第五章中,我们用 Deployment 部署了 Nginx、PHP 应用,它们有一个共同特点:无状态。
无状态应用的特点:- Pod 之间完全相同,可以互相替换- Pod 名称是随机的(nginx-xxxx-yyyyy)- Pod 重启后 IP 会变化,但不影响使用- 可以任意顺序启动、停止、删除- 不需要持久化存储(或使用共享存储)但是,如果我们要部署 MySQL 集群呢?
MySQL 主从集群的要求:1. 每个实例需要有固定的网络标识(主库是master-0,从库是slave-1、slave-2)2. 必须先启动主库,再启动从库3. 每个实例需要独立的持久化存储(不能共享数据目录)4. 从库需要知道主库的固定地址来同步数据5. Pod 重启后,必须保持原来的身份和数据Deployment 做不到这些!这时候就需要 StatefulSet。
StatefulSet 是什么?
StatefulSet 是 Kubernetes 中专门用于管理有状态应用的控制器。
用一个生活化的比喻来理解:
Deployment 就像工厂流水线上的工人:- 每个工人穿着统一的工作服- 谁干活都一样,可以随意替换- 编号是临时的(工人-a1b2c3)- 换班顺序无所谓
StatefulSet 就像学校里的学生:- 每个学生有固定的学号(student-0, student-1, student-2)- 学号是按顺序分配的,不会重复- 每个学生有自己的课桌(独立存储)- 排队必须按学号顺序来- 转学回来后,还是用原来的学号和课桌1.2 StatefulSet vs Deployment
核心区别对比:
| 特性 | Deployment | StatefulSet |
|---|---|---|
| Pod 名称 | 随机后缀(nginx-7d8-9f2) | 有序编号(web-0, web-1, web-2) |
| Pod 启动顺序 | 并发启动 | 按序启动(0→1→2) |
| Pod 停止顺序 | 随机停止 | 反序停止(2→1→0) |
| 网络标识 | 不稳定(IP 变化) | 稳定(固定 DNS 名称) |
| 存储 | 共享存储或无状态 | 每个 Pod 独立的 PVC |
| 适用场景 | Web 应用、API 服务 | 数据库、消息队列、Zookeeper |
| Pod 替换 | 新 Pod 是全新的 | 新 Pod 继承原身份和存储 |
详细说明:
1. Pod 名称 - 固定且有序
# Deployment 的 Pod 名称(随机)nginx-deployment-7d8b9f2c-x7k9mnginx-deployment-7d8b9f2c-p4q2nnginx-deployment-7d8b9f2c-m8w5t
# StatefulSet 的 Pod 名称(固定编号)mysql-0 # 第一个 Pod,编号从 0 开始mysql-1 # 第二个 Podmysql-2 # 第三个 Pod为什么需要固定名称?
- MySQL 主从配置中,从库需要连接
mysql-0.mysql-service(主库的固定 DNS) - Redis 集群中,节点需要通过固定名称相互发现
- Zookeeper 需要固定的 server.id 标识
2. 启动和停止顺序
StatefulSet 停止(反序): 先删除 Pod2 → 再删除 Pod1 → 最后删除 Pod0
为什么需要顺序?
- MySQL 主从:必须先启动主库(Pod0),从库才能连接它
- Etcd 集群:需要先有 leader 节点,其他节点才能加入
- 优雅关闭:先关闭从节点,最后关闭主节点,避免数据丢失
3. 稳定的网络标识(固定 DNS)
StatefulSet 必须配合 Headless Service 使用,每个 Pod 有固定的 DNS 名称:
DNS 格式:<pod-name>.<service-name>.<namespace>.svc.cluster.local
示例:mysql-0.mysql-service.default.svc.cluster.localmysql-1.mysql-service.default.svc.cluster.localmysql-2.mysql-service.default.svc.cluster.local即使 Pod 重启,DNS 名称也不变!
# Pod mysql-1 崩溃前的 IPmysql-1: 10.244.1.100
# Pod mysql-1 重启后的 IPmysql-1: 10.244.2.200 # IP 变了
# 但 DNS 名称不变,其他 Pod 仍然可以通过名称访问nslookup mysql-1.mysql-service# 自动解析到新 IP: 10.244.2.2004. 独立的持久化存储
Deployment(共享存储或无存储): ┌─────┐ ┌─────┐ ┌─────┐ │ Pod0│ │ Pod1│ │ Pod2│ └─────┘ └─────┘ └─────┘ └───────┴───────┘ ↓ ┌────────────┐ │ Shared PVC │ ← 所有 Pod 共享一个存储 └────────────┘
StatefulSet(独立存储): ┌─────┐ ┌─────┐ ┌─────┐ │ Pod0│ │ Pod1│ │ Pod2│ └─────┘ └─────┘ └─────┘ ↓ ↓ ↓ ┌──────┐ ┌──────┐ ┌──────┐ │ PVC-0│ │ PVC-1│ │ PVC-2│ ← 每个 Pod 有独立的 PVC └──────┘ └──────┘ └──────┘为什么需要独立存储?
- MySQL 的每个实例必须有自己的数据目录
- Pod 重启后,新 Pod 会自动绑定到原来的 PVC,数据不丢失
- 扩容时,新 Pod 会自动创建新的 PVC
1.3 StatefulSet 适用场景
✅ 适合使用 StatefulSet:
-
数据库集群
- MySQL 主从/MGR 集群
- PostgreSQL 集群
- MongoDB 副本集
- Redis 主从/Sentinel/Cluster
-
分布式存储
- Ceph
- GlusterFS
- MinIO 集群
-
分布式协调服务
- Etcd 集群
- Zookeeper 集群
- Consul 集群
-
消息队列
- Kafka 集群
- RabbitMQ 集群
- Pulsar 集群
-
有状态的大数据组件
- Elasticsearch 集群
- Cassandra 集群
- HBase 集群
❌ 不适合使用 StatefulSet:
- 无状态 Web 应用 - Nginx、Apache、前端静态资源服务
- 无状态 API 服务 - RESTful API、微服务(不需要固定标识的)
- 批处理任务 - 使用 Job/CronJob 更合适
1.4 快速实验:对比 Deployment 和 StatefulSet
实验目标: 直观感受两者的区别
步骤1:创建 Deployment
cd /root/k8s-yaml
cat > nginx-deployment.yaml <<EOFapiVersion: apps/v1kind: Deploymentmetadata: name: nginx-deployspec: replicas: 3 selector: matchLabels: app: nginx-deploy template: metadata: labels: app: nginx-deploy spec: containers: - name: nginx image: nginx:1.20 ports: - containerPort: 80EOF
kubectl apply -f nginx-deployment.yaml
# 查看 Pod 名称(随机后缀)kubectl get pods -l app=nginx-deploy预期输出:
NAME READY STATUS RESTARTS AGEnginx-deploy-7d8b9f2c-x7k9m 1/1 Running 0 10snginx-deploy-7d8b9f2c-p4q2n 1/1 Running 0 10snginx-deploy-7d8b9f2c-m8w5t 1/1 Running 0 10s步骤2:创建 StatefulSet
# 先创建 Headless Service(必须的!)cat > nginx-headless.yaml <<EOFapiVersion: v1kind: Servicemetadata: name: nginx-stsspec: clusterIP: None # Headless Service selector: app: nginx-sts ports: - port: 80EOF
kubectl apply -f nginx-headless.yaml
# 创建 StatefulSetcat > nginx-statefulset.yaml <<EOFapiVersion: apps/v1kind: StatefulSetmetadata: name: nginx-stsspec: serviceName: nginx-sts # 关联 Headless Service replicas: 3 selector: matchLabels: app: nginx-sts template: metadata: labels: app: nginx-sts spec: containers: - name: nginx image: nginx:1.20 ports: - containerPort: 80EOF
kubectl apply -f nginx-statefulset.yaml
# 观察 Pod 启动过程(会看到按顺序启动)watch kubectl get pods -l app=nginx-sts预期输出(注意启动顺序):
# 第一阶段:只有 Pod-0 启动NAME READY STATUS RESTARTS AGEnginx-sts-0 1/1 Running 0 5s
# 第二阶段:Pod-0 Ready 后,Pod-1 启动NAME READY STATUS RESTARTS AGEnginx-sts-0 1/1 Running 0 15snginx-sts-1 1/1 Running 0 5s
# 第三阶段:Pod-1 Ready 后,Pod-2 启动NAME READY STATUS RESTARTS AGEnginx-sts-0 1/1 Running 0 25snginx-sts-1 1/1 Running 0 15snginx-sts-2 1/1 Running 0 5s步骤3:测试固定 DNS
# 测试 StatefulSet 的 Pod(有固定 DNS)kubectl exec -it nginx-sts-0 -- nslookup nginx-sts-1.nginx-sts
# 预期输出:# Server: 10.96.0.10# Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local## Name: nginx-sts-1.nginx-sts# Address 1: 10.244.2.100 nginx-sts-1.nginx-sts.default.svc.cluster.local
# 每个 StatefulSet Pod 都有固定 DNSkubectl exec -it nginx-sts-0 -- nslookup nginx-sts-0.nginx-stskubectl exec -it nginx-sts-0 -- nslookup nginx-sts-2.nginx-sts步骤4:测试删除 Pod 后的行为
# 删除 Deployment 的一个 PodDEPLOY_POD=$(kubectl get pods -l app=nginx-deploy -o jsonpath='{.items[0].metadata.name}')kubectl delete pod $DEPLOY_PODkubectl get pods -l app=nginx-deploy# 输出:新 Pod 名称完全不同
# 删除 StatefulSet 的一个 Podkubectl delete pod nginx-sts-1kubectl get pods -l app=nginx-sts# 输出:新 Pod 名称完全相同# nginx-sts-1 ← 名称不变!步骤5:清理实验资源
kubectl delete deployment nginx-deploykubectl delete statefulset nginx-stskubectl delete svc nginx-sts实验总结:
| 特性 | Deployment 表现 | StatefulSet 表现 |
|---|---|---|
| Pod 名称 | 随机后缀 | 固定编号(0、1、2) |
| 启动顺序 | 并发启动 | 顺序启动(0→1→2) |
| 固定 DNS | ❌ 不支持 | ✅ 支持 |
| Pod 重建 | 新名称 | 名称不变 |
2. StatefulSet 设计原理
2.1 StatefulSet 的组成部分
一个完整的 StatefulSet 应用需要三个对象:
┌─────────────────────────────────────────────────┐│ StatefulSet 架构 │├─────────────────────────────────────────────────┤│ 1. Headless Service(必须) ││ 提供稳定的网络标识 ││ 2. StatefulSet(核心) ││ 管理 Pod 的创建、更新、删除 ││ 3. PersistentVolumeClaim(可选) ││ 为每个 Pod 自动创建独立的存储 │└─────────────────────────────────────────────────┘1. Headless Service
apiVersion: v1kind: Servicemetadata: name: mysql-servicespec: clusterIP: None # 关键!设置为 None selector: app: mysql ports: - port: 3306作用:为每个 Pod 创建固定的 DNS 记录(<pod-name>.<service-name>)
2. StatefulSet 定义
apiVersion: apps/v1kind: StatefulSetmetadata: name: mysqlspec: serviceName: mysql-service # 关联 Headless Service replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0 volumeClaimTemplates: # PVC 模板(可选) - metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi3. 自动创建的 PVC
# 命名规则:<pvc-name>-<statefulset-name>-<ordinal>data-mysql-0 # mysql-0 的 PVCdata-mysql-1 # mysql-1 的 PVCdata-mysql-2 # mysql-2 的 PVC2.2 管理策略
1. Pod 管理策略(podManagementPolicy)
spec: podManagementPolicy: OrderedReady # 或 Parallel- OrderedReady(默认):按顺序启动(0→1→2),前一个 Ready 才启动下一个
- Parallel:并发启动,不等待
2. 更新策略(updateStrategy)
spec: updateStrategy: type: RollingUpdate # 或 OnDelete rollingUpdate: partition: 0 # 金丝雀发布- RollingUpdate:自动滚动更新,反序更新(2→1→0)
- OnDelete:手动删除 Pod 才更新
3. Partition 金丝雀发布
partition: 2 # 只更新编号 >= 2 的 Pod假设有 5 个 Pod(0-4),partition: 2更新后:mysql-0 (v1) mysql-1 (v1) mysql-2 (v2) mysql-3 (v2) mysql-4 (v2)2.3 升级和回滚
升级:
kubectl set image statefulset/mysql mysql=mysql:8.0.35kubectl rollout status statefulset/mysql回滚:
StatefulSet 不支持 kubectl rollout undo,需手动回滚:
kubectl set image statefulset/mysql mysql=mysql:8.0.30为什么不支持自动回滚?
- 有状态应用的回滚涉及数据兼容性
- 需要人工判断和干预
2.4 扩缩容
扩容:
kubectl scale statefulset mysql --replicas=5# 顺序创建:mysql-3 → mysql-4缩容:
kubectl scale statefulset mysql --replicas=3# 反序删除:mysql-4 → mysql-3# PVC 不会被删除(数据保留)清理 PVC:
kubectl delete statefulset mysqlkubectl get pvc # PVC 仍然存在kubectl delete pvc -l app=mysql # 手动删除3. 实战:用 StatefulSet 搭建 MySQL 主从集群
3.1 实验架构
┌──────────────────────────────────────────────────┐│ MySQL 主从复制集群 │├──────────────────────────────────────────────────┤│ mysql-0 (主库 Master) ← 写入数据 ││ ↓ ││ mysql-1 (从库 Slave) ← 同步数据 ││ mysql-2 (从库 Slave) ← 同步数据 ││ ││ 读写分离: ││ - 写操作 → mysql-0 ││ - 读操作 → mysql-1, mysql-2(负载均衡) │└──────────────────────────────────────────────────┘实验目标:
- 部署 1 主 2 从的 MySQL 集群
- 配置主从复制
- 验证数据同步
- 测试 Pod 故障恢复
3.2 步骤1:创建 ConfigMap
cd /root/k8s-yaml
cat > mysql-configmap.yaml <<EOFapiVersion: v1kind: ConfigMapmetadata: name: mysql-configdata: master.cnf: | [mysqld] log-bin=mysql-bin # 开启 binlog server-id=1 # 主库 ID
slave.cnf: | [mysqld] server-id=2 # 从库 ID(会被动态修改) read_only=1 # 只读模式EOF
kubectl apply -f mysql-configmap.yaml3.3 步骤2:创建 Service
cat > mysql-service.yaml <<EOFapiVersion: v1kind: Servicemetadata: name: mysqlspec: clusterIP: None # Headless Service selector: app: mysql ports: - name: mysql port: 3306---apiVersion: v1kind: Servicemetadata: name: mysql-read # 读请求负载均衡spec: selector: app: mysql ports: - name: mysql port: 3306EOF
kubectl apply -f mysql-service.yaml两个 Service 的作用:
mysql: Headless,提供固定 DNSmysql-read: 普通 Service,读请求负载均衡
3.4 步骤3:创建 StatefulSet
cat > mysql-statefulset.yaml <<'EOF'apiVersion: apps/v1kind: StatefulSetmetadata: name: mysqlspec: serviceName: mysql replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: initContainers: - name: init-mysql image: reg.westos.org/library/mysql:8.0 command: - bash - "-c" - | set -ex # 提取 Pod 编号 [[ $(hostname) =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} echo "Pod ordinal: $ordinal"
# mysql-0 用主库配置,其他用从库配置 if [[ $ordinal -eq 0 ]]; then cp /mnt/config-map/master.cnf /mnt/conf.d/ else cp /mnt/config-map/slave.cnf /mnt/conf.d/ # 动态设置 server-id sed -i "s/server-id=2/server-id=$((100 + $ordinal))/" /mnt/conf.d/slave.cnf fi cat /mnt/conf.d/*.cnf volumeMounts: - name: conf mountPath: /mnt/conf.d - name: config-map mountPath: /mnt/config-map
containers: - name: mysql image: reg.westos.org/library/mysql:8.0 env: - name: MYSQL_ROOT_PASSWORD value: "Westos123" - name: MYSQL_DATABASE value: "testdb" ports: - name: mysql containerPort: 3306 volumeMounts: - name: data mountPath: /var/lib/mysql subPath: mysql - name: conf mountPath: /etc/mysql/conf.d livenessProbe: exec: command: ["mysqladmin", "ping", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"] initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: exec: command: ["mysql", "-uroot", "-p${MYSQL_ROOT_PASSWORD}", "-e", "SELECT 1"] initialDelaySeconds: 10 periodSeconds: 5
volumes: - name: conf emptyDir: {} - name: config-map configMap: name: mysql-config - name: data emptyDir: {} # 简化版:使用 emptyDirEOF
kubectl apply -f mysql-statefulset.yaml关键点说明:
1. initContainers 的作用:
- 根据 Pod 编号生成不同配置
- mysql-0 使用主库配置
- mysql-1/2 使用从库配置
2. Pod 编号提取:
[[ $(hostname) =~ -([0-9]+)$ ]] || exit 1ordinal=${BASH_REMATCH[1]}3. 动态 server-id:
- mysql-0: server-id = 1
- mysql-1: server-id = 101
- mysql-2: server-id = 102
3.5 步骤4:观察启动过程
# 观察 Pod 启动顺序watch kubectl get pods -l app=mysql
# 查看 init 容器日志kubectl logs mysql-0 -c init-mysqlkubectl logs mysql-1 -c init-mysql
# 查看 MySQL 日志kubectl logs mysql-0 -c mysql预期输出(按顺序启动):
NAME READY STATUS RESTARTS AGEmysql-0 1/1 Running 0 30s ← 先启动
NAME READY STATUS RESTARTS AGEmysql-0 1/1 Running 0 60smysql-1 1/1 Running 0 25s ← mysql-0 Ready 后启动
NAME READY STATUS RESTARTS AGEmysql-0 1/1 Running 0 90smysql-1 1/1 Running 0 55smysql-2 1/1 Running 0 20s ← mysql-1 Ready 后启动3.6 步骤5:配置主从复制
在主库创建复制用户:
kubectl exec -it mysql-0 -c mysql -- mysql -uroot -pWestos123 <<EOFCREATE USER 'repl'@'%' IDENTIFIED BY 'Repl123!@#';GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';FLUSH PRIVILEGES;SHOW MASTER STATUS;EOF记录输出:
+------------------+----------+| File | Position |+------------------+----------+| mysql-bin.000003 | 157 |+------------------+----------+配置从库(mysql-1 和 mysql-2):
# 配置 mysql-1kubectl exec -it mysql-1 -c mysql -- mysql -uroot -pWestos123 <<EOFSTOP SLAVE;CHANGE MASTER TO MASTER_HOST='mysql-0.mysql', MASTER_USER='repl', MASTER_PASSWORD='Repl123!@#', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=157;START SLAVE;SHOW SLAVE STATUS\GEOF
# 配置 mysql-2kubectl exec -it mysql-2 -c mysql -- mysql -uroot -pWestos123 <<EOFSTOP SLAVE;CHANGE MASTER TO MASTER_HOST='mysql-0.mysql', MASTER_USER='repl', MASTER_PASSWORD='Repl123!@#', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=157;START SLAVE;SHOW SLAVE STATUS\GEOF检查从库状态:
kubectl exec -it mysql-1 -c mysql -- mysql -uroot -pWestos123 -e "SHOW SLAVE STATUS\G" | grep -E "Slave_IO_Running|Slave_SQL_Running"预期输出:
Slave_IO_Running: Yes ← 必须是 YesSlave_SQL_Running: Yes ← 必须是 Yes3.7 步骤6:测试主从同步
在主库写入数据:
kubectl exec -it mysql-0 -c mysql -- mysql -uroot -pWestos123 <<EOFUSE testdb;CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);INSERT INTO users (name) VALUES ('Alice'), ('Bob'), ('Charlie');SELECT * FROM users;EOF在从库查询数据:
# 从库1kubectl exec -it mysql-1 -c mysql -- mysql -uroot -pWestos123 -e "SELECT * FROM testdb.users;"
# 从库2kubectl exec -it mysql-2 -c mysql -- mysql -uroot -pWestos123 -e "SELECT * FROM testdb.users;"预期输出(数据已同步):
+----+---------+---------------------+| id | name | created_at |+----+---------+---------------------+| 1 | Alice | 2024-01-15 10:30:00 || 2 | Bob | 2024-01-15 10:30:00 || 3 | Charlie | 2024-01-15 10:30:00 |+----+---------+---------------------+继续插入,观察实时同步:
# 主库插入kubectl exec -it mysql-0 -c mysql -- mysql -uroot -pWestos123 -e \ "INSERT INTO testdb.users (name) VALUES ('David'), ('Eve');"
# 从库查询kubectl exec -it mysql-1 -c mysql -- mysql -uroot -pWestos123 -e \ "SELECT * FROM testdb.users;"3.8 步骤7:测试读写分离
创建测试 Pod:
kubectl run mysql-client --image=reg.westos.org/library/mysql:8.0 --rm -it --restart=Never -- bash在测试 Pod 中:
# 写操作 → 主库mysql -h mysql-0.mysql -uroot -pWestos123 -e \ "INSERT INTO testdb.users (name) VALUES ('Frank');"
# 读操作 → 负载均衡mysql -h mysql-read -uroot -pWestos123 -e "SELECT * FROM testdb.users;"
# 多次查询观察负载均衡for i in {1..5}; do mysql -h mysql-read -uroot -pWestos123 -e \ "SELECT @@hostname AS pod_name, COUNT(*) AS count FROM testdb.users;"done3.9 步骤8:测试 Pod 故障恢复
删除从库 Pod:
kubectl delete pod mysql-2watch kubectl get pods -l app=mysql验证:
- Pod 名称不变(mysql-2)
- DNS 名称不变(mysql-2.mysql)
- 由于使用 emptyDir,数据丢失(需重新配置主从)
生产环境使用 PVC:
- Pod 重建自动挂载原 PVC
- 数据不丢失,MySQL 自动恢复
3.10 步骤9:扩缩容
扩容到 4 个副本:
kubectl scale statefulset mysql --replicas=4watch kubectl get pods -l app=mysql
# 配置新从库 mysql-3kubectl exec -it mysql-3 -c mysql -- mysql -uroot -pWestos123 <<EOFCHANGE MASTER TO MASTER_HOST='mysql-0.mysql', MASTER_USER='repl', MASTER_PASSWORD='Repl123!@#', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=157;START SLAVE;EOF缩容回 3 个:
kubectl scale statefulset mysql --replicas=3# mysql-3 被删除3.11 清理资源
kubectl delete statefulset mysqlkubectl delete svc mysql mysql-readkubectl delete configmap mysql-config4. 总结
4.1 核心要点
StatefulSet 三大特性:
- 固定标识:Pod名称和DNS不变(mysql-0, mysql-1, mysql-2)
- 有序管理:按序启动/停止/更新(0→1→2 或 2→1→0)
- 独立存储:每个Pod自动创建独立PVC,Pod重建后数据保留
vs Deployment:
- Deployment:无状态,Pod可替换,并发管理
- StatefulSet:有状态,Pod不可替换,有序管理
4.2 适用场景
✅ 使用 StatefulSet:
- 数据库集群(MySQL、PostgreSQL、MongoDB)
- 消息队列(Kafka、RabbitMQ)
- 分布式存储(Ceph、MinIO)
- 协调服务(Etcd、Zookeeper)
❌ 不要使用:
- Web应用、API服务 → 用Deployment
- 批处理任务 → 用Job/CronJob
4.3 重要限制
StatefulSet 只提供基础能力,不提供:
- ❌ 自动故障切换(主库挂了不会自动提升从库)
- ❌ 自动备份和恢复
- ❌ 自动监控告警
- ❌ 业务逻辑处理(如主从复制配置)
解决方案:
- 简单场景:手动配置 + StatefulSet
- 生产环境:使用 Operator(Percona、Vitess、Strimzi等)
- 关键业务:考虑托管服务(RDS、云数据库)
4.4 常用命令
# 基本操作kubectl get statefulsetkubectl describe sts <name>kubectl get pods -l app=mysql
# 扩缩容kubectl scale sts mysql --replicas=5
# 更新kubectl set image sts/mysql mysql=mysql:8.0.35kubectl rollout status sts/mysql
# 回滚(手动)kubectl set image sts/mysql mysql=mysql:8.0.30
# 删除(保留PVC)kubectl delete sts mysqlkubectl get pvckubectl delete pvc -l app=mysql # 手动清理PVC4.5 生产最佳实践
# 1. 必须使用持久化存储volumeClaimTemplates:- metadata: name: data spec: storageClassName: fast-ssd accessModes: ["ReadWriteOnce"] resources: requests: storage: 100Gi
# 2. 配置健康检查livenessProbe: exec: command: ["mysqladmin", "ping"]readinessProbe: exec: command: ["mysql", "-e", "SELECT 1"]
# 3. 设置资源限制resources: requests: memory: "2Gi" cpu: "1000m" limits: memory: "4Gi" cpu: "2000m"
# 4. Pod反亲和(分散到不同节点)affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: mysql topologyKey: kubernetes.io/hostname第七章:daemonset和job
1.介绍daemonset,他的作用和适用场景,他的实现逻辑,需要配置什么,他的更新和回滚策略 2.介绍job和cronjob,介绍作用和适用场景,介绍配置项 3.实战 搭建一个daemonset实例,如Fluentd 创建一个job执行一次性任务 学会用cronjob进行定期备份etcd 提前备份系统快照,故意弄坏etcd,学会用备份恢复etcd