📝本文首发于 栏轩·阁
欢迎访问阅读原文,获取更好的阅读体验。
一、前置准备
部署 MySQL 前,需要先完成以下环境搭建(具体步骤见之前的两篇教程):
- Docker Desktop 启用 K8s(建议使用kind 模式,因为 LoadBalancer 支持映射所有端口)
- 安装 KubeSphere
- 激活 KubeSphere(申请免费 License,否则无法使用扩展中心安装插件)
本文基于以下环境:
宿主机:Windows 11 + WSL 2 Ubuntu 22.04 Docker Desktop:K8s 启用,kind 模式 KubeSphere:已安装并激活二、概念速览
在开始之前,先快速了解几个 K8s 概念,后面会用到:
| 概念 | 作用 | 类比(Docker) |
|---|---|---|
| 工作负载(Deployment) | 管理 Pod 的生命周期,保证容器始终运行 | docker run+ 自动重启 |
| 持久卷声明(PVC) | 申请一块持久化存储空间 | docker volume |
| 保密字典(Secret) | 存储敏感信息(密码、密钥等) | 环境变量文件 |
| 配置字典(ConfigMap) | 存储配置文件 | 挂载配置文件 |
| 服务(Service) | 暴露 Pod 的网络入口 | docker port映射 |
| LoadBalancer | 将服务暴露到宿主机(kind 模式下自动映射端口) | 自动端口转发 |
三、创建企业空间和项目
登录 KubeSphere Web 控制台(http://localhost:30880,账号admin/P@88w0rd),依次创建:
- 企业空间→ 给团队用的顶层隔离单元
- 项目(命名空间)→ 资源隔离的项目空间,所有 MySQL 资源都会创建在此项目下
项目在 K8s 中对应namespace,后续的
kubectl命令中-n mysql就是指定项目名称。
四、创建保密字典(Secret)
MySQL 需要配置 root 密码,敏感信息应该放在 Secret 中,而不是写在配置文件里。
在项目左侧菜单 →配置→保密字典→创建:
- 名称:
mysql-secret - 键:
mysql-root-password - 值:
123456(你的密码)
这样密码就以密文形式存储在 K8s 中,工作负载引用时以环境变量注入,不会明文暴露。
五、创建配置字典(ConfigMap)
MySQL 的配置文件(my.cnf)放在 ConfigMap 中,方便修改和管理。
在项目左侧菜单 →配置→配置字典→创建:
名称:mysql-config
配置数据(键my.cnf,值如下):
[client] default-character-set=utf8mb4 [mysql] default-character-set=utf8mb4 [mysqld] init_connect='SET collation_connection = utf8mb4_unicode_ci' init_connect='SET NAMES utf8mb4' character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci skip-character-set-client-handshake skip-name-resolve max_connections=1000配置说明
| 配置项 | 作用 |
|---|---|
character-set-server=utf8mb4 | 设置 MySQL 默认字符集为 utf8mb4(支持 emoji) |
collation-server=utf8mb4_unicode_ci | 设置排序规则 |
skip-name-resolve | 跳过 DNS 反向解析,加快连接速度 |
max_connections=1000 | 最大连接数,开发环境够用 |
参考 YAML 格式:
kind:ConfigMapapiVersion:v1metadata:name:mysql-confignamespace:mysqldata:my.cnf:|[client] default-character-set=utf8mb4 [mysql] default-character-set=utf8mb4 [mysqld] init_connect='SET collation_connection = utf8mb4_unicode_ci' init_connect='SET NAMES utf8mb4' character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci skip-character-set-client-handshake skip-name-resolve max_connections=1000六、创建持久卷声明(PVC)
MySQL 的数据需要持久化,否则 Pod 重启后数据就丢了。
在项目左侧菜单 →存储→持久卷声明→创建:
存储类选择
| 存储类 | 说明 | 适用场景 |
|---|---|---|
| hostPath | 直接使用宿主机磁盘路径 | 单节点开发环境,简单直接 |
| standard | 通过 CSI 驱动分配存储 | 集群环境,功能更完善 |
对于 Docker Desktop 单节点环境,用hostPath就够了。如果选 standard,在 Docker Desktop 上通常也能用,但需要确保 provisioner 已安装。
访问模式
| 模式 | 说明 |
|---|---|
| ReadWriteOnce(RWO) | 只能被一个节点挂载读写 ✅ MySQL 选这个 |
| ReadOnlyMany(ROX) | 可以被多个节点同时只读挂载 |
| ReadWriteMany(RWX) | 可以被多个节点同时读写挂载 |
MySQL 是单点数据库,选ReadWriteOnce即可。
配置参数
- 名称:
mysql-pvc - 存储类:
hostpath - 访问模式:
ReadWriteOnce - 容量:
5Gi(根据实际需求调整)
七、创建工作负载(Deployment)
这是最核心的一步,把 MySQL 容器跑起来。
在项目左侧菜单 →工作负载→部署→创建:
7.1 基本信息
- 名称:
mysql - 版本:
v1
7.2 容器镜像
- 镜像:
mysql:8.0(或指定版本如mysql:8.0.46) - 容器名称:
mysql
⚠️国内网络问题:如果拉取官方镜像超时,可以使用国内镜像加速地址:
https://docker.1ms.run https://docker.1panel.live在 Docker Desktop 的 Docker Engine 配置中设置 registry-mirrors,或者提前用
docker pull手动拉取(Docker 配置了加速后更快)。
7.3 环境变量
从之前创建的 Secret 中引用密码:
| 环境变量 | 来源 | 值 |
|---|---|---|
MYSQL_ROOT_PASSWORD | 引用 Secretmysql-secret中的mysql-root-password | 自动注入 |
MYSQL_DATABASE | 直接填写 | test(可选,自动创建的默认数据库) |
使用 Secret 引用密码的好处:密码不会明文出现在工作负载 YAML 中,其他人查看配置也看不到密码。
7.4 挂载存储
需要挂载两个路径:
| 挂载类型 | 来源 | 挂载路径 | 作用 |
|---|---|---|---|
| 持久卷声明 | mysql-pvc | /var/lib/mysql | 存储 MySQL 数据文件 |
| 配置字典 | mysql-config(挂载my.cnf) | /etc/mysql/my.cnf | 挂载 MySQL 配置文件 |
⚠️注意:配置字典挂载时,子路径要填写
my.cnf,否则 ConfigMap 会以目录形式挂载,覆盖整个/etc/mysql/目录,导致 MySQL 找不到其他默认配置。
7.5 创建完成
点击创建,等待 Pod 启动完成。可以在工作负载页面查看状态:
Pod 状态从ContainerCreating→Running即表示启动成功。
八、创建服务(Service)
Pod 默认只能在集群内部访问(ClusterIP),外部无法连接。需要创建一个 Service 来暴露端口。
在工作负载详情页→更多操作→创建服务:
8.1 配置服务端口
| 参数 | 值 | 说明 |
|---|---|---|
| 名称 | mysql | 服务名称 |
| 内部端口(Service Port) | 3306 | 服务对外暴露的端口 |
| 容器端口(Target Port) | 3306 | MySQL 容器监听的端口 |
| 协议 | TCP | MySQL 使用 TCP 协议 |
⚠️常见错误:Service Port 和 Target Port 都可以自定义,但Target Port 必须和容器内应用的监听端口一致。MySQL 默认监听 3306,Target Port 也要填 3306。如果填错,连接会成功建立 TCP 连接但读不到 MySQL 握手包,报错:
Can not read response from server. Expected to read 4 bytes, read 0 bytes
8.2 选择外部访问方式
K8s Service 的三种访问类型:
| 类型 | 宿主机能否访问 | 说明 |
|---|---|---|
| ClusterIP | ❌ | 仅集群内部可访问,外部无法连接 |
| NodePort | ⚠️ | 在节点上开一个端口,但 Docker Desktop 的 kind 模式下无法直接访问 |
| LoadBalancer | ✅ | 自动映射到localhost,外部可直接访问 |
选择 LoadBalancer。因为 KubeSphere 运行在 WSL 的 Docker Desktop 上,kind 模式自带cloud-provider-kind,创建 LoadBalancer 服务后会自动生成一个 kindccm 代理容器,把localhost:<端口>映射到你的服务。
8.3 确认服务创建成功
创建后,在服务页面可以看到:
名称 类型 Cluster IP External IP 端口 mysql LoadBalancer 10.96.xx.xxx 172.18.0.x 3306:3xxxx/TCP同时docker ps可以看到 kindccm 代理容器自动创建:
kindccm-xxx 0.0.0.0:3306->3306/tcp九、验证部署
9.1 查看日志
点击工作负载,下拉到容器副本列表,点击右侧的容器日志:
看到以下信息表示 MySQL 启动成功:
/usr/sbin/mysqld: ready for connections. Version: '8.0.46' socket: '/var/run/mysqld/mysqld.sock' port: 33069.2 通过 KubeSphere Web 终端
在工作负载详情页,点击 Pod 的终端图标,进入容器内部:
进入后执行:
mysql-uroot-p# 输入密码 123456看到 MySQL 提示符mysql>即表示正常。
9.3 通过 WSL 命令行
也可以直接在 WSL Ubuntu 终端用kubectl进入容器:
# 查看 MySQL Pod 名称kubectl get pods-A|grepmysql# 进入容器内部kubectlexec-it-nmysql mysql-5444fbf78-hjjq8 -- /bin/bash# 进入后连接 MySQLmysql-uroot-p9.4 从 IDE 连接
在 IntelliJ IDEA、DataGrip、Navicat 等数据库工具中:
| 参数 | 值 |
|---|---|
| Host | localhost |
| Port | 3306 |
| User | root |
| Password | 123456 |
如果连接失败,按以下顺序排查:
- 检查
kubectl get pods -n <项目名>是否 Running- 检查
kubectl get svc -n <项目名>是否 LoadBalancer 类型且有 EXTERNAL-IP- 检查
docker ps是否有 kindccm 代理容器,端口映射是否正确- 检查 Service 的
targetPort是否等于 MySQL 容器监听端口(默认 3306)
十、部署第二个 MySQL 实例
如果要部署第二个 MySQL(比如测试环境),直接在 KubeSphere 中重复上述步骤即可:
- 新的持久卷声明(如
mysql02-pvc) - 新的工作负载(如
mysql02) - 新的服务,端口设为
3307,targetPort仍为3306
关键点:Service Port 是对外端口(可以自定义),Target Port 始终是容器内 MySQL 的监听端口(3306)。
创建完成后,kind 会自动创建一个新的 kindccm 代理容器,将localhost:3307映射到新的 MySQL 实例。
查看所有 kindccm 代理:
dockerps--format"table {{.Names}}\t{{.Ports}}"|grepkindccm输出示例:
kindccm-xxx 0.0.0.0:3306->3306/tcp # 第一个 MySQL kindccm-yyy 0.0.0.0:3307->3307/tcp # 第二个 MySQL kindccm-zzz 0.0.0.0:30880->30880/tcp # KubeSphere 控制台每个 LoadBalancer 服务都由独立的 kindccm 代理管理,互不干扰。
十一、总结
| 阶段 | 操作 | 关键点 |
|---|---|---|
| Secret | 存储 MySQL 密码 | 引用到环境变量,不暴露明文 |
| ConfigMap | 存储 my.cnf 配置 | 设置 utf8mb4 字符集 |
| PVC | 申请持久化存储 | hostPath + ReadWriteOnce |
| 工作负载 | 运行 MySQL 容器 | 挂载 PVC 和 ConfigMap |
| Service | 暴露外部访问 | LoadBalancer类型 |
| 验证 | 连接测试 | localhost:3306 |
部署 MySQL 的流程覆盖了 K8s 的配置、存储、工作负载、网络四个核心模块,理解了这个流程,部署其他中间件(Redis、PostgreSQL 等)也是类似的思路。