这边仅用于测试环境,一般生产环境mysql不建议使用容器部署。这里假设安装mysql版本为mysql 8.0.33
一、创建 MySQL 配置(ConfigMap)
# mysql-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
my.cnf: |
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-time-zone='+8:00' # 设置时区为东八区kubectl apply -f mysql-config.yaml二、创建 PVC(使用nfs-client存储类)
# cat ../mysql-pvc.yaml
# mysql-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce # MySQL 推荐单节点读写
storageClassName: nfs-client # 使用之前创建的 NFS StorageClass
resources:
requests:
storage: 10Gikubectl apply -f mysql-pvc.yaml三、创建 Secret(存储密码)
# 创建 MySQL 密码 Secret
kubectl create secret generic mysql-secret \
--from-literal=root-password="mysql@12DS" \
--from-literal=user-password="mysql@12DS"四、部署 MySQL(使用 StatefulSet)
# mysql-statefulset.yaml
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.0.33
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
- name: MYSQL_DATABASE
value: "mydb"
- name: MYSQL_USER
value: "user"
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: user-password
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
- name: config-volume
mountPath: /etc/mysql/conf.d
volumes:
- name: config-volume
configMap:
name: mysql-config
items:
- key: my.cnf
path: my.cnf
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: nfs-client # 使用 nfs-client 存储类
resources:
requests:
storage: 10Gikubectl apply -f mysql-statefulset.yaml由于K8S镜像不能下载,我这边是先通过docker 先下载镜像然后进行导入到K8S:
docker pull mysql:8.0.33
docker save -o mysql-8.0.33.tar mysql:8.0.33
ctr -n k8s.io images import mysql-8.0.33.tar
其他工作节点是一样,可以将mysql-8.0.33.tar拷贝到其他节点,然后导入,如:
scp mysql-8.0.33.tar root@node1:/root
scp mysql-8.0.33.tar root@node2:/root
然后在节点node1,node2,执行导入镜像命令:
ctr -n k8s.io images import mysql-8.0.33.tar五、创建 Service(暴露 MySQL)
# mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
type: ClusterIP
ports:
- port: 3306
selector:
app: mysqlkubectl apply -f mysql-service.yaml六、验证部署
6.1 检查pod状态
kubectl get pods -l app=mysql6.2 连接到 MySQL:
kubectl exec -it mysql-0 -- bash //进入容器
mysql -uroot -p
创建测试库:test,czm
可以发现NFS服务器对应目录有新增2个库czm 和test
说明mysql 8.0.33安装成功并且可以使用。
七、外部访问 MySQL(可选)
# mysql-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-nodeport
spec:
type: NodePort
ports:
- port: 3306
nodePort: 30306 # 自定义端口(30000-32767)
selector:
app: mysqlkubectl apply -f mysql-nodeport.yaml通过 节点IP:30306 访问 MySQL。
我这边是通过mysql客户端工具navicat for mysql 工具进行连接测试
至此K8S部署应用mysql完成,后续继续研究其他应用部署。
说明:
MySQL 数据库不建议直接部署在容器(尤其是 Kubernetes)中的核心原因,在于其 状态性(Stateful)特性与容器的无状态设计理念存在本质冲突,以及生产环境中面临的稳定性、数据安全和运维复杂度问题。以下是具体分析:
一、容器 / K8s 的设计理念与 MySQL 需求的冲突
容器的核心设计目标是 快速启停、水平扩展、无状态运行(如 Web 服务、API 服务),而 MySQL 作为典型的 有状态服务,存在以下矛盾点:
数据持久化的可靠性风险
容器本身是 “临时的”,生命周期可能因重启、调度、故障而终止。尽管 K8s 提供了 PV/PVC 等持久化方案,但:
存储性能依赖底层存储类(如 NFS、Ceph 等),若配置不当(如延迟高、IOPS 不足),会严重影响 MySQL 性能(尤其是写入密集场景)。
容器重启时,数据挂载可能因网络延迟、权限问题导致挂载失败,直接造成数据库不可用。
状态一致性与集群调度的冲突
K8s 的调度器可能因节点资源不足、亲和性规则变化等,将 MySQL Pod 调度到其他节点。此时:
数据库连接会被强制中断,需重新建立(应用层需处理重连逻辑)。
若涉及主从复制,节点 IP 变化可能导致复制链路断裂,需额外配置固定网络标识(如 Headless Service),增加复杂度。
二、生产环境中的核心痛点
1. 数据安全与恢复风险
数据丢失隐患:容器故障时,若 PV 存储层出现问题(如分布式存储集群故障),可能导致数据损坏或丢失。
备份与恢复复杂:容器化环境中,需额外配置定时备份(如通过 CronJob 调用 mysqldump),但备份文件的存储、校验、恢复流程比物理机 / 虚拟机更复杂,且依赖 K8s 集群本身的稳定性。
2. 性能与资源隔离问题
资源竞争:容器共享宿主机的 CPU、内存、IO 资源,若同一节点上有其他高负载容器(如大数据任务),可能导致 MySQL 出现 CPU 争抢、内存溢出(OOM)、IO 延迟飙升 等问题,直接影响数据库响应速度。
性能损耗:容器的虚拟化层(如 Docker 的 namespace/cgroups)会带来轻微性能损耗,对 MySQL 这类对性能敏感的服务可能产生累积影响(尤其高并发场景)。
3. 高可用与故障处理的局限性
主从切换的复杂性:MySQL 主从架构依赖固定的网络标识、同步机制,在 K8s 中需通过 Operator(如 mysql-operator)实现自动切换,但:
切换逻辑可能因网络分区、脑裂等问题失效,导致数据不一致。
相比成熟的物理机主从架构(如 MGR、Percona XtraDB Cluster),容器化方案的稳定性和成熟度更低。
状态恢复速度慢:MySQL 故障重启时,需执行日志恢复(redo/undo log)、表修复等操作,容器的启动速度可能因镜像拉取、挂载延迟进一步延长,导致业务中断时间增加。
4. 运维复杂度陡增
参数调优困难:MySQL 的性能依赖大量系统级参数(如 innodb_buffer_pool_size、max_connections),需与宿主机资源(内存、CPU)强绑定,而容器的资源限制(resources.limits)可能导致参数配置失效或性能瓶颈。
监控与排障复杂:需同时监控 K8s 集群(Pod 状态、节点资源)和 MySQL 本身(连接数、锁等待、慢查询),故障定位需跨两层系统(如 “Pod 正常运行但 MySQL 无响应” 可能是存储故障,也可能是数据库死锁)。
版本升级风险:容器化环境中升级 MySQL 镜像可能导致配置文件、数据格式不兼容,而回滚操作需同时处理容器镜像和持久化数据,比物理机 / 虚拟机的升级流程更复杂。
三、哪些场景可以考虑容器化 MySQL?
并非所有场景都绝对禁止,以下情况可尝试:
开发 / 测试环境:快速搭建临时数据库,数据丢失影响小。
轻量业务:数据量小(GB 级)、并发低、对可用性要求不高(如内部工具)。
有成熟 Operator 支持:使用专为 MySQL 设计的 K8s Operator(如 Oracle MySQL Operator、Percona Operator),简化高可用、备份等运维流程。
四、总结
MySQL 容器化的核心矛盾是 “状态性服务” 与 “容器无状态设计” 的不匹配,以及生产环境中 数据安全、性能稳定性、运维复杂度 等问题。对于企业级生产环境,更推荐:
物理机或虚拟机部署(直接控制硬件资源和存储)。
托管数据库服务(如 AWS RDS、阿里云 RDS),由厂商解决高可用、备份、扩容等问题。
若坚持在 K8s 中部署,需投入大量精力优化存储性能、高可用架构和运维流程,且需充分评估业务对稳定性的容忍度。
