必须用statefulset部署mysql:①确保有序启停(mysql-0→mysql-1→mysql-2);②每个pod绑定独立pvc,重建不丢数据;③通过headless service提供稳定dns标识,保障主从连接可靠。

直接上手部署 WordPress 个人博客到 Kubernetes,关键不是“能不能跑”,而是“数据会不会丢、扩缩容会不会炸、升级会不会断”。结论很明确:必须拆开 MySQL 和 WordPress,MySQL 用 StatefulSet + PVC,WordPress 用 Deployment + Service + 可选 Ingress,否则一扩容就多套数据库,一重启就丢配置。
MySQL 必须用 StatefulSet,别用 Deployment
用 Deployment 部署 MySQL 看似简单,但会埋下三个硬伤:
- 滚动更新时可能多个 Pod 同时写同一份 NFS 或本地
hostPath,导致 InnoDB 崩溃; - 副本数 >1 时,多个 MySQL 实例争抢同一个数据目录,启动直接失败(报错类似
mysqld: Can't start server: Bind on TCP/IP port. Got error: 98: Address already in use); - 没有稳定的网络标识(如
mysql-0.mysql),WordPress 无法可靠连接主实例。
正确做法是用 StatefulSet,并绑定独立 PVC:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: "mysql"
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.4
envFrom:
- secretRef:
name: mysql-secret
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
注意:volumeClaimTemplates 会为每个 Pod 自动生成带序号的 PVC(如 mysql-data-mysql-0),这是 Deployment 做不到的。
WordPress 的环境变量不能硬编码,优先用 Secret + ConfigMap
把数据库密码写死在 YAML 里等于裸奔。Kubernetes 提供了更安全的注入方式:
-
Secret存敏感字段:如WORDPRESS_DB_PASSWORD、MYSQL_ROOT_PASSWORD; -
ConfigMap存非敏感字段:如WORDPRESS_DB_HOST(值应为mysql,即 Service 名)、WORDPRESS_DB_NAME; - WordPress 官方镜像支持前缀式环境变量注入,例如用
envFrom+prefix: WORDPRESS_DB_,就能自动映射WORDPRESS_DB_USER→$DB_USER。
错误示例(明文密码):
env: - name: WORDPRESS_DB_PASSWORD value: "my-secret-pass"
正确做法:
kubectl create secret generic wordpress-db-secret \ --from-literal=password=your-real-password \ --from-literal=user=wordpress \ --from-literal=host=mysql
然后在 WordPress Deployment 中引用:
envFrom:
- secretRef:
name: wordpress-db-secret
prefix: WORDPRESS_DB_
Service 类型选 ClusterIP 还是 NodePort?看访问场景
个人博客通常不需要公网直连 MySQL,但 WordPress 前端得能被访问。这里分两层看:
- MySQL
Service必须设为clusterIP: None(无头服务),否则 DNS 解析会返回集群 IP,而StatefulSet要求直接解析到 Pod IP(如mysql-0.mysql.namespace.svc.cluster.local); - WordPress
Service:- 本地测试:用
NodePort,比如nodePort: 30080,然后浏览器访问http://<node-ip>:30080</node-ip>; - 生产或长期使用:用
ClusterIP+Ingress,配合域名(如blog.example.com)和 TLS 证书,更可控也更安全;
- 本地测试:用
别用 LoadBalancer——除非你在云厂商环境且愿意付费。它在本地集群(如 minikube、k3s)里基本不生效,还容易卡在 Pending 状态。
PV/PVC 绑定失败?先查 StorageClass 和节点挂载能力
常见现象:PVC 一直 Pending,kubectl describe pvc 显示 no persistent volumes available for this claim。
根本原因往往不是 YAML 写错,而是底层存储没就绪:
- 确认
StorageClass是否存在且默认启用:kubectl get sc; - 如果用 NFS,确保所有节点(包括 master)都装了
nfs-utils,否则 kubelet 挂载失败; - 如果用
hostPath,注意它只适用于单节点测试,且路径必须提前在对应节点上创建好(如/mnt/data),权限设为755,属主设为mysql(UID 999)或www-data(UID 33); - 检查
PV的accessModes是否匹配PVC(如ReadWriteOnce不能绑定到要求ReadWriteMany的 PVC)。
最容易被忽略的一点:MySQL 容器启动时需要往挂载点写文件,如果 NFS 服务端配了 root_squash(默认行为),而容器以非 root 用户运行(MySQL 8.4 默认 UID 999),就会因权限不足卡在初始化阶段,日志里反复出现 chown: changing ownership of '/var/lib/mysql/': Operation not permitted。解决方法是 NFS 服务端改用 no_root_squash,或改用 mountOptions 加 uid=999,gid=999。











