一、开场故事:我的周末是怎么被MySQL毁掉的?

上周六傍晚,我正蹲在客厅地板上拼乐高航母,手机突然炸了——运维群的报警消息刷得比火锅沸腾还快:
​“生产MySQL主库宕机!数据目录满导致无法写入!”​

我手忙脚乱套上衬衫冲去公司,一边骂娘一边查原因:

  • 宿主机磁盘没监控,悄悄被日志占满了;
  • MySQL数据没持久化,上次重启容器数据丢了一半;
  • 从库还没来得及扩,主库一崩整个业务就瘫了……

等我把数据从半小时前的备份里捞出来,客厅的乐高航母早凉了,火锅里的牛肉卷也变成了“考古标本”。那一刻我发誓:​再也不让MySQL把我折腾得像个救火队员!​

二、容器化救场:把MySQL装进“智能集装箱”

后来我痛定思痛,用Docker+K8s重构了MySQL部署方案——不是为了赶云原生时髦,是真的能“躺平”了

1. Docker基础:给MySQL找个“安全屋”

很多人觉得docker run mysql很简单?错!这就像把贵重物品扔在路边纸箱里,分分钟被偷被淋。​正确的做法是给MySQL建个“带锁的智能集装箱”​​:

  • 数据持久化:给MySQL买“永不丢失的保险”​
    docker volume create mysql-data创建命名卷,相当于给MySQL租了个带锁的储物柜——数据存到卷里,哪怕容器删了重启,数据还在。启动命令改成:

docker run -d \
  --name mysql-safe \
  -v mysql-data:/var/lib/mysql \  # 挂载持久化卷
  -p 3306:3306 \
  -e MYSQL_ROOT_PASSWORD=$(openssl rand -base64 16) \  # 随机强密码,别用“123456”!
  mysql:8.0

安全配置:别让密码“裸奔”​
生产环境别直接写密码!用Docker Secrets把密码存到安全地方,容器启动时自动注入:

echo "your_super_strong_pwd" | docker secret create mysql-root -
docker run -d --name mysql-secret \
  --secret mysql-root \
  -v mysql-data:/var/lib/mysql \
  mysql:8.0
  • 容器里的MySQL会自动读取/run/secrets/mysql-root作为密码——比你藏银行卡密码还安全。

  • 资源限制:别让MySQL“吃撑”​
    不限制资源的话,MySQL会被其他进程抢CPU/内存,轻则卡顿,重则OOM崩溃。用--cpus--memory锁死配额:

docker run -d --name mysql-limited \
  --cpus=4 \          # 最多用4核
  --memory=8g \       # 最多8G内存
  --memory-swap=0 \   # 禁止用Swap(MySQL最怕这个!)
  -v mysql-data:/var/lib/mysql \
  mysql:8.0

2. K8s进阶:给MySQL建个“专属动物园”

Docker解决的是单机问题,​K8s才是管理有状态服务(比如MySQL)的神器——尤其是StatefulSet,简直是MySQL的“专属动物园管理员”:

  • 为什么选StatefulSet?​
    它能给每个MySQL Pod分配固定身份​(比如mysql-0主库、mysql-1从库)、专属存储​(PVC绑定到每个Pod)、有序部署​(先起主库再造从库)——再也不会出现“从库连不上主库”的混乱。

  • 实战:用StatefulSet搭主从集群
    我们用3个Pod搭1主2从集群,核心配置就两点:

    1. Headless Service​:给Pod分配固定DNS(比如mysql-0.mysql-headless),方便从库找主库;
    2. Init Container​:自动初始化主从复制——第一个Pod(mysql-0)当主库,其他Pod自动跑脚本连主库同步数据:

initContainers:
- name: init-mysql
  image: mysql:8.0
  command: ["sh", "-c"]
  args:
    - |
      if [ "${HOSTNAME#*-}" = "0" ]; then
        # 主库:创建复制用户
        mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "CREATE USER 'repl'@'%' IDENTIFIED BY 'repl_pwd';"
        mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';"
      else
        # 从库:连主库同步
        MASTER_IP=$(getent hosts mysql-0.mysql-headless | awk '{print $1}')
        mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "CHANGE MASTER TO MASTER_HOST='${MASTER_IP}', MASTER_USER='repl', MASTER_PASSWORD='repl_pwd';"
        mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "START SLAVE;"
      fi

备份:用Velero当“动物园医生”​
定期备份是救命稻草!用Velero每天凌晨自动备份MySQL的PVC:

velero schedule create mysql-daily --schedule="0 2 * * *" \
  --include-namespaces=default \
  --volume-snapshot-locations=mysql-storage

万一集群崩了,velero restore create --from-backup mysql-daily一键恢复——比我当年手忙脚乱找备份快100倍!

三、优化秘籍:让MySQL跑成“数据库博尔特”

容器化的MySQL不仅要“能跑”,还要“跑得快”。分享几个压箱底的优化技巧:

1. 配置文件:给MySQL穿“合身的衣服”

MySQL的性能全靠配置!用ConfigMapmy.cnf从镜像里拆出来,随时改不用重建镜像:

# ConfigMap定义my.cnf
data:
  my.cnf: |
    [mysqld]
    innodb_buffer_pool_size = 4G  # 缓冲池占内存50%-70%,别太小!
    max_connections = 200         # 最大连接数,根据业务调
    slow_query_log = 1            # 开启慢查询,找出“拖油瓶”
    slow_query_log_file = /var/log/mysql/slow.log

然后在StatefulSet里挂载这个ConfigMap——改配置就像换衣服,超方便!

2. 文件系统:选对“跑道”很重要

Docker的存储驱动影响IO性能!​优先用overlay2​(默认驱动,性能好),别用devicemapper(慢得像蜗牛)。检查方法:

docker info | grep "Storage Driver"  # 看是不是overlay2

3. 弹性伸缩:只加“备用运动员”

MySQL主库不能随便扩,但从库可以!用kubectl scale加从库,再配合ProxySQL做读写分离——读请求丢给从库,写请求给主库,轻松扛住高并发

kubectl scale statefulset mysql --replicas=5  # 加2个从库

四、监控:让MySQL“裸奔”变“透明”

容器化后,看不到MySQL状态等于瞎子走路。用这两个方案搞定监控:

1. 指标监控:给MySQL戴“计步器”

mysqld-exporter当Sidecar容器,收集QPS、连接数、慢查询指标,Prometheus抓取,Grafana画图——打开仪表盘就能看到MySQL“心跳”:

# MySQL Pod加Sidecar
containers:
- name: mysql
  # ... 原有配置 ...
- name: mysqld-exporter
  image: prom/mysqld-exporter:v0.14.0
  env:
  - name: DATA_SOURCE_NAME
    value: "root:${MYSQL_ROOT_PASSWORD}@tcp(localhost:3306)/"
  ports:
  - containerPort: 9104
    name: metrics

2. 日志收集:装个“摄像头”

用Fluentd收集MySQL的慢查询、错误日志,发给Elasticsearch,Kibana可视化——再也不用手动翻/var/log/mysql了:

# Fluentd配置收集慢日志
<source>
  @type tail
  path /var/log/mysql/slow.log
  tag mysql-slow
</source>
<match mysql-slow>
  @type elasticsearch
  host elasticsearch-logging
  port 9200
</match>

五、结尾:从“救火队员”到“咖啡观察员”

现在再看我的周末:

  • 乐高航母拼完了,火锅里的牛肉卷还热乎;
  • 手机里的报警消息安静得像睡着了;
  • 打开Grafana,MySQL的QPS稳得像直线,慢查询数为0。

容器化不是“技术炫技”,是把运维从“救火”变成“预防”​——用Docker把MySQL装进“安全屋”,用K8s给它建“动物园”,用优化让它跑成“博尔特”,用监控让它“透明可见”。

最后一句话总结​:
以前我用生命守护MySQL,现在MySQL用容器守护我的咖啡时间。

附录:懒人必备链接

  • Docker MySQL官方文档:https://hub.docker.com/_/mysql
  • K8s StatefulSet教程:https://kubernetes.io/docs/tutorials/stateful-application/mysql/
  • Prometheus MySQL Exporter:https://github.com/prometheus/mysqld_exporter

(全文完)

作者​:曾经的周末救火队员,现在的容器化“躺平”运维——专注用技术把自己从加班里捞出来。

小贴士​:如果觉得部署麻烦,直接用云厂商的RDS容器版——但自己动手丰衣足食的快乐,谁试谁知道! 😉

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐