[MYSQL/K8s] 基于 Kubenetes 集群安装 MYSQL

0 序

  • 本篇的目的不在于安装mysql,而在于安装部署完成K8s后,以MYSQL为例展示如何基于K8s集群完整地部署一个程序服务。

MYSQL 较为典型——service / pod / secret / pv / pvc 均可涉及。

1 部署步骤

step1 配置 mysql.yaml

mkdir -p ~/k8s-deployments/

touch ~/k8s-deployments/mysql.yaml
vim ~/k8s-deployments/mysql.yaml

编辑内容:

# mysql-configmap.yaml | ConfigMap: MySQL 配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
  namespace: mysql
data:
  my.cnf: |
    [mysqld]
    character-set-server=utf8mb4
    collation-server=utf8mb4_unicode_ci
    max_connections=200
    innodb_buffer_pool_size=256M

---

# mysql-secret.yaml | Secret: MySQL 密码(生产环境建议使用 Vault 或 External Secrets)
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: mysql
type: Opaque
stringData:
  MYSQL_ROOT_PASSWORD: "YourStrongPassword123!"
  MYSQL_USER: "appuser"
  MYSQL_PASSWORD: "AppUserPass123!"

---

# mysql-pvc.yaml | PVC: 数据存储(使用 local-path-provisioner )
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: mysql
spec:
  # 指定 local-path-provisioner
  storageClassName: local-path
  accessModes:
    # MySQL 单实例只需 RWO
    - ReadWriteOnce
  resources:
    requests:
      # 根据实际需求调整
      storage: 20Gi

---
# mysql-statefulset.yaml | StatefulSet: MySQL 有状态的工作负载 (与 无状态的 Deployment 相对)
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: mysql
spec:
  serviceName: mysql
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        ports:
        - containerPort: 3306
          name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: MYSQL_ROOT_PASSWORD
        - name: MYSQL_DATABASE
          value: "app_database"
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql    # MySQL 数据目录
        - name: mysql-config
          mountPath: /etc/mysql/conf.d
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        livenessProbe:
          exec:
            command: ["mysqladmin", "ping", "-p${MYSQL_ROOT_PASSWORD}"]
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          exec:
            command: ["mysqladmin", "ping", "-p${MYSQL_ROOT_PASSWORD}"]
          initialDelaySeconds: 5
          periodSeconds: 2
      volumes:
      - name: mysql-data
        persistentVolumeClaim:
          # 引用上面定义的 PVC
          claimName: mysql-pvc
      - name: mysql-config
        configMap:
          name: mysql-config

---

# mysql-service.yaml | Service: 暴露 MySQL 端口
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: mysql
spec:
  selector:
    app: mysql
  ports:
    - port: 3306
      targetPort: 3306
  type: ClusterIP

当然,也可将本文件分拆为几个文件来进行部署:

mysql-deployment.yaml

mysql-secret.yaml
mysql-configmap.yaml

mysql-namespace.yaml

mysql-pv-pvc.yaml

mysql-service.yaml

...

step2 基于 mysql.yaml 部署/启动运行

kubectl create -f mysql.yaml
或 kubectl apply -f mysql.yaml

[补充] kubectl delete -f mysql.yaml

step3 查验 MYSQL 的运行情况

查验 k8s 的 service/pod/statefulset、secret、pv/pvc

//查看 service/pod/statefulset/
# kubectl get all --namespace mysql
NAME          READY   STATUS    RESTARTS   AGE
pod/mysql-0   1/1     Running   0          4h14m

NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/mysql   ClusterIP   10.100.xxx.19   <none>        3306/TCP   4h14m

NAME                     READY   AGE
statefulset.apps/mysql   1/1     4h14m

//查看 secret
# kubectl get secret --namespace mysql
NAME           TYPE     DATA   AGE
mysql-secret   Opaque   3      4h15m

//查看 pv / pvc
# kubectl get pv --namespace mysql
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
pvc-10e35004-c24f-443d-9268-e5603172c382   20Gi       RWO            Delete           Bound    mysql/mysql-pvc   local-path              4h17m
# kubectl get pvc --namespace mysql
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pvc   Bound    pvc-10e35004-c24f-443d-9268-e5603172c382   20Gi       RWO            local-path     4h18m

获取 Kubernetes 中 MySQL Pod 的连接信息

1. 查看 Pod 的 IP 和端口

# 获取 Pod 的详细信息,包括 IP 地址
kubectl get pod <mysql-pod-name> -o wide

# 查看 Pod 的详细描述(包含端口映射)
kubectl describe pod <mysql-pod-name>

2. 查看 Service 信息(推荐方式)

通常 MySQL 会通过 Service 暴露,这样更稳定:

# 列出所有 Service
kubectl get svc

# 查看 MySQL Service 详情
kubectl describe svc <mysql-service-name>

# 获取 Service 的 ClusterIP 和端口
kubectl get svc <mysql-service-name> -o jsonpath='{.spec.clusterIP}:{.spec.ports[0].port}'

3. 通过环境变量查看(若是通过 Secret 配置的)

# 查看 Pod 的环境变量
kubectl exec <mysql-pod-name> -- env | grep -i mysql

# 查看 Secret 中的连接信息
kubectl get secret <mysql-secret-name> -o yaml
# 解码 base64 密码
echo "<base64-encoded-password>" | base64 -d

4. 查看 ConfigMap 或部署配置

# 查看使用的 ConfigMap
kubectl get configmaps --namespace <mysql-namespace>
kubectl get configmap <mysql-configmap> --namespace <mysql-namespace> -o yaml

# 查看 Deployment/StatefulSet 的配置
kubectl get deployments --namespace <mysql-namespace>
kubectl get deployment <mysql-deployment> --namespace <mysql-namespace> -o yaml

kubectl get statefulsets --namespace <mysql-namespace>
//如: kubectl get statefulsets -n mysql
//NAME    READY   AGE
//mysql   1/1     4h39m
kubectl get statefulset <mysql-statefulset> --namespace <mysql-namespace> -o yaml

5. 端口转发(本地测试用)

# 将本地端口映射到 Pod 端口
kubectl port-forward <mysql-pod-name> 3306:3306

# 然后本地可以用 localhost:3306 连接
mysql -h localhost -P 3306 -u root -p

典型连接信息示例

信息项 获取方式
主机地址 Service 的 ClusterIP 或 Service 名称
端口 默认 3306,查看 kubectl get svc
用户名 通常是 root 或自定义用户,查看 Secret/环境变量
密码 查看 Secret:kubectl get secret

最佳实践建议

  1. 使用 Service DNS 连接:在集群内通过 <service-name>.<namespace>.svc.cluster.local 连接
  2. 使用 Secret 管理凭证:不要硬编码密码
  3. 考虑使用 Helm Chart:如 bitnami/mysql,会自动配置好连接信息

连接验证

[root@vm-a k8s-deployments]# kubectl exec -it mysql-0 -n mysql  -- mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8568
Server version: 8.0.45 MySQL Community Server - GPL

Copyright (c) 2000, 2026, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT user, host FROM mysql.user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| root             | %         |
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+
5 rows in set (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| app_database       |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
  • 推荐方式: 直接进入Pod内
# 找到 mysql 相关的 pod
kubectl get pods -n mysql -l app=mysql

# 进入 pod 内部,然后在 pod 里连接 mysql
kubectl exec -it <mysql-pod-name> -n mysql -- /bin/bash

# 在 pod 内部使用服务名连接
mysql -h mysql.mysql.svc.cluster.local -P 3306 -u root -p

如: 
[root@vm-a k8s-deployments]# kubectl exec -it mysql-0 -n mysql -- /bin/bash
bash-5.1# mysql -h mysql.mysql.svc.cluster.local -P 3306 -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10316
Server version: 8.0.45 MySQL Community Server - GPL

Copyright (c) 2000, 2026, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> exit;

Z FAQ for K8s 安装部署 MYSQL

Q: service 的 type 为 ClsuterIP ,无法基于<serviceName>.<namespace>.svc.cluster.local的【服务域名】在宿主机上访问,如何解决?

问题描述

[root@vm-a k8s-deployments]# ssh mysql.mysql.svc.cluster.local -p 3306 -v
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 58: Applying options for *
ssh: Could not resolve hostname mysql.mysql.svc.cluster.local: Name or service not known

原因分析

这个错误表明 DNS 解析失败,无法找到 mysql.mysql.svc.cluster.local 这个域名。

mysql.mysql.svc.cluster.local 是 Kubernetes 集群内部的 DNS 名称,只能在 Pod 内部或通过集群 DNS 解析。你的宿主机(vm-a)无法直接解析这个域名。

解决方案

方案 1:进入 Pod 内部执行(推荐)

# 找到 mysql 相关的 pod
kubectl get pods -n mysql -l app=mysql

# 进入 pod 内部,然后在 pod 里连接 mysql
kubectl exec -it <mysql-pod-name> -n mysql -- /bin/bash

# 在 pod 内部使用服务名连接
mysql -h mysql.mysql.svc.cluster.local -P 3306 -u root -p

方案 2:使用 kubectl port-forward 转发端口

# 将本地端口映射到 mysql 服务
kubectl port-forward svc/mysql 3306:3306 -n mysql

# 然后在另一个终端连接本地端口
mysql -h 127.0.0.1 -P 3306 -u root -p

方案 3:直接使用 Pod IP(临时方案)

# 获取 mysql pod 的 IP
kubectl get pods -n mysql -o wide

# 使用 Pod IP 连接(不推荐,IP 会变)
mysql -h <pod-ip> -P 3306 -u root -p

方案 4:使用 NodePort 或 LoadBalancer 暴露服务

如果你确实需要从集群外部访问,可以修改 Service 类型:

# 查看当前 service 类型
kubectl get svc mysql -n mysql

# 修改为 NodePort(示例)
kubectl patch svc mysql -n mysql -p '{"spec":{"type":"NodePort"}}'

# 或者使用 LoadBalancer(如果有云提供商支持)
kubectl patch svc mysql -n mysql -p '{"spec":{"type":"LoadBalancer"}}'

快速排查命令

# 确认 mysql 服务是否存在
kubectl get svc -n mysql

# 确认 DNS 服务是否正常
kubectl get pods -n kube-system -l k8s-app=kube-dns

# 测试集群 DNS 解析(在 pod 内执行)
kubectl run -it --rm debug --image=busybox:1.28 --restart=Never -- nslookup mysql.mysql.svc.cluster.local

总结

场景 推荐方案
临时调试 kubectl exec 进入 Pod
本地开发 kubectl port-forward
生产环境外部访问 NodePort / LoadBalancer / Ingress

Q: 如何将 mysql 的 service type 从 ClusterIP 换为 NodePort?

将 MySQL 的 ClusterIP 改为 NodePort 的方法:

方法1:直接修改现有 Service(保留原配置)

# 1. 修改 Service 类型为 NodePort
kubectl patch svc mysql -n mysql -p '{"spec":{"type":"NodePort"}}'

# 2. 查看分配的 NodePort
kubectl get svc mysql -n mysql

输出示例:

NAME    TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
mysql   NodePort   10.100.174.19   <none>        3306:30001/TCP   4h49m

30001 就是自动分配的 NodePort,范围 30000-32767

方法2:指定固定 NodePort(推荐)

# 指定具体的节点端口(例如 30001)
kubectl patch svc mysql -n mysql -p '{"spec":{"type":"NodePort","ports":[{"port":3306,"targetPort":3306,"nodePort":30001}]}}'

方法3:通过 YAML 编辑(最灵活)

# 导出当前配置备份
kubectl get svc mysql -n mysql -o yaml > mysql-svc-backup.yaml

# 编辑 Service
kubectl edit svc mysql -n mysql

修改内容:

spec:
  type: NodePort          # 改为 NodePort
  ports:
    - port: 3306
      targetPort: 3306
      nodePort: 30001     # 可选:指定端口(30000-32767)
      protocol: TCP

保存退出后自动生效。

修改后连接方式

# 获取节点 IP
kubectl get nodes -o wide

# 验证网络联通性
ssh <node-ip> -p 3306 -v
如: ssh 10.100.174.19 -p 3306 -v

# 连接 MySQL(用任意节点的 IP + NodePort,即可在 K8s 集群的宿主机及其所在网络上进行连接)
mysql -h <node-ip> -P 30001 -u root -p

回滚操作(如需恢复 ClusterIP)

kubectl patch svc mysql -n mysql -p '{"spec":{"type":"ClusterIP"}}'

完整检查命令

# 确认修改成功
kubectl get svc mysql -n mysql

# 查看 Endpoints(确认后端 Pod 正常)
kubectl get endpoints mysql -n mysql

# 测试连接(在集群外执行)
mysql -h <node-ip> -P <node-port> -u root -p

Y 推荐文献

X 参考文献

posted @ 2026-04-20 01:51  千千寰宇  阅读(5)  评论(0)    收藏  举报