kubernetes 部署mysql应用(kubernetes搭建)

这边仅用于测试环境,一般生产环境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: 10Gi
kubectl 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: 10Gi
kubectl 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: mysql
kubectl apply -f mysql-service.yaml

六、验证部署

6.1 检查pod状态

kubectl get pods -l app=mysql

6.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: mysql
kubectl 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 中部署,需投入大量精力优化存储性能、高可用架构和运维流程,且需充分评估业务对稳定性的容忍度。

原文链接:,转发请注明来源!