1. 为什么选择Docker部署MySQL
第一次接触Docker时,我正面临一个典型开发困境:每次在新环境部署MySQL都要重复安装配置,版本差异经常导致"在我机器上能跑"的尴尬。传统虚拟机方案又太重,直到发现Docker这个轻量级容器解决方案。
Docker的核心优势在于环境隔离和快速部署。想象每个容器就像打包好的集装箱,里面装着完整运行环境。部署MySQL时,我们不用关心底层系统差异,直接拉取官方镜像就能获得一致性的数据库服务。这对于需要频繁切换开发环境的程序员、需要快速搭建演示环境的售前、以及刚入门的新手来说都是福音。
2. 环境准备与安装
2.1 Docker安装避坑指南
在Ubuntu 20.04上安装Docker时,新手常会遇到两个坑:
- 使用
apt install docker安装的是旧版docker.io包 - 未将用户加入docker组导致每次都要sudo
正确安装姿势:
bash复制# 卸载旧版本
sudo apt remove docker docker-engine docker.io containerd runc
# 设置仓库
sudo apt update
sudo apt install ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装引擎
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io
# 避免sudo
sudo usermod -aG docker $USER
newgrp docker # 立即生效
重要提示:安装后务必执行
docker run hello-world验证。我曾遇到因未关闭代理导致镜像拉取失败的情况,如果报错可尝试systemctl restart docker。
2.2 镜像加速配置
国内用户建议配置镜像加速器。阿里云容器镜像服务提供免费加速地址,登录后进入"镜像工具->镜像加速器"获取专属地址:
bash复制sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
3. MySQL容器化实战
3.1 单节点快速部署
官方MySQL镜像提供了丰富的环境变量配置。以下命令创建了一个带密码的MySQL 8.0实例:
bash复制docker run -d \
--name mysql_dev \
-e MYSQL_ROOT_PASSWORD=my-secret-pw \
-e MYSQL_DATABASE=app_db \
-e MYSQL_USER=dev_user \
-e MYSQL_PASSWORD=dev_pwd \
-p 3306:3306 \
-v /opt/mysql_data:/var/lib/mysql \
mysql:8.0 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
参数解析:
-d:后台运行--name:容器别名(重要!避免使用随机名称)-e:环境变量(密码等敏感信息建议改用docker secrets)-p:端口映射(主机端口:容器端口)-v:数据卷挂载(绝对必要!否则容器删除数据丢失)
血泪教训:我曾因忘记挂载volume导致测试数据全丢。现在养成了习惯 - 所有数据库容器必须显式指定volume。
3.2 生产级配置建议
开发环境可以简单部署,但生产环境需要更多考量:
-
内存限制:防止单个容器耗尽主机资源
bash复制
--memory 2g --memory-swap 4g -
CPU限制:
bash复制
--cpus 2 -
重启策略:
bash复制
--restart unless-stopped -
时区同步:
bash复制
-e TZ=Asia/Shanghai
完整生产示例:
bash复制docker run -d \
--name mysql_prod \
--memory 4g --memory-swap 6g \
--cpus 2 \
--restart unless-stopped \
-e MYSQL_ROOT_PASSWORD=prodpwd123 \
-e TZ=Asia/Shanghai \
-v /data/mysql:/var/lib/mysql \
-v /etc/mysql/conf.d:/etc/mysql/conf.d \
-p 13306:3306 \
mysql:8.0 \
--innodb_buffer_pool_size=2G \
--max_connections=200
4. 日常运维操作手册
4.1 基础运维命令
bash复制# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止)
docker ps -a
# 启动/停止容器
docker start mysql_dev
docker stop mysql_dev
# 进入容器bash
docker exec -it mysql_dev bash
# 查看日志
docker logs -f mysql_dev
# 删除容器(必须先stop)
docker rm mysql_dev
4.2 数据库备份方案
我常用的三种备份方式:
-
mysqldump直接导出:
bash复制docker exec mysql_dev sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > all-databases.sql -
备份数据卷:
bash复制
tar czvf mysql_backup.tar.gz /opt/mysql_data -
定时任务方案(需先安装cron):
bash复制# 创建备份脚本 echo 'docker exec mysql_dev sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" app_db' > /backups/app_db_$(date +%Y%m%d).sql' > /etc/cron.daily/mysql_backup chmod +x /etc/cron.daily/mysql_backup
4.3 版本升级策略
MySQL小版本升级相对安全,建议流程:
-
停止旧容器并备份数据
bash复制
docker stop mysql_dev tar czvf mysql_data_backup.tar.gz /opt/mysql_data -
启动新版本容器(使用相同volume)
bash复制
docker run -d \ --name mysql_dev_new \ -v /opt/mysql_data:/var/lib/mysql \ mysql:8.0.28 -
验证数据完整性后删除旧容器
bash复制docker rm mysql_dev docker rename mysql_dev_new mysql_dev
注意:跨大版本升级(如5.7→8.0)需要先检查官方升级指南,可能需要特殊迁移步骤。
5. 常见问题排雷指南
5.1 连接问题排查
现象:客户端无法连接容器MySQL
排查步骤:
-
检查容器状态
bash复制
docker ps -a | grep mysql -
查看端口映射
bash复制
docker port mysql_dev -
检查防火墙规则
bash复制sudo ufw status -
容器内测试连接
bash复制docker exec -it mysql_dev mysql -uroot -p
5.2 性能优化实践
通过docker stats发现内存占用过高时:
bash复制docker stats mysql_dev
优化方案:
-
调整MySQL配置
bash复制docker exec -it mysql_dev vi /etc/mysql/my.cnf # 增加:innodb_buffer_pool_size=1G -
限制容器资源
bash复制
docker update --memory 2g --memory-swap 3g mysql_dev -
使用专用监控工具
bash复制docker run -d --name mysql_exporter \ -p 9104:9104 \ -e DATA_SOURCE_NAME="root:password@(mysql_dev:3306)/" \ prom/mysqld-exporter
5.3 数据恢复操作
当误删数据需要从volume恢复时:
-
停止当前容器
bash复制
docker stop mysql_dev -
备份当前数据(防止二次损坏)
bash复制cp -r /opt/mysql_data /opt/mysql_data_bak -
启动临时容器挂载备份数据
bash复制
docker run -d --name mysql_recovery \ -v /opt/mysql_data_bak:/var/lib/mysql \ mysql:8.0 -
通过mysqldump导出需要的数据
6. 进阶:Docker Compose编排
当需要同时管理MySQL和其他服务时,推荐使用docker-compose.yml:
yaml复制version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mysql_app
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: app_db
MYSQL_USER: app_user
MYSQL_PASSWORD: userpass
volumes:
- mysql_data:/var/lib/mysql
- ./conf.d:/etc/mysql/conf.d
ports:
- "3306:3306"
restart: unless-stopped
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 3
volumes:
mysql_data:
启动命令:
bash复制docker-compose up -d
优势:
- 一键启动所有关联服务
- 版本控制友好的配置文件
- 内置健康检查机制
- 统一的网络环境
7. 安全加固建议
-
密码管理:避免在命令行直接暴露密码,改用:
bash复制echo "rootpass" | docker secret create mysql_root_password - docker run --name mysql_secure \ --secret source=mysql_root_password,target=mysql_root_password \ -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \ mysql:8.0 -
网络隔离:创建自定义网络
bash复制
docker network create mysql_net docker run --network mysql_net --name mysql_internal mysql:8.0 -
最小权限原则:MySQL容器应使用非root用户运行
bash复制
docker run --name mysql_safe \ --user 1000:1000 \ -v /opt/mysql_data:/var/lib/mysql \ mysql:8.0 -
定期更新:关注CVE公告并及时更新镜像
bash复制docker pull mysql:8.0 docker stop mysql_dev docker rm mysql_dev docker run ... # 使用新镜像
8. 监控与日志管理
8.1 日志收集方案
查看MySQL慢查询日志:
bash复制docker exec mysql_dev tail -f /var/log/mysql/mysql-slow.log
持久化日志到主机:
bash复制docker run --name mysql_log \
-v /opt/mysql_logs:/var/log/mysql \
mysql:8.0
8.2 性能监控方案
使用cAdvisor+Prometheus+Grafana组合:
bash复制# 启动cAdvisor
docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest
# 配置Prometheus抓取
scrape_configs:
- job_name: cadvisor
static_configs:
- targets: ['cadvisor:8080']
- job_name: mysql
static_configs:
- targets: ['mysql_exporter:9104']
9. 替代方案对比
当Docker方案不适用时,可以考虑:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 原生安装 | 最佳性能 | 环境依赖复杂 | 生产环境高负载 |
| Docker Desktop | 图形化管理 | 资源占用较大 | Windows/Mac开发环境 |
| Podman | 无需守护进程 | 生态工具较少 | 安全敏感环境 |
| Kubernetes Operator | 自动扩缩容 | 学习曲线陡峭 | 云原生环境 |
10. 学习资源推荐
-
官方文档:
-
实用工具:
- Adminer:轻量级数据库管理工具
bash复制docker run -d --link mysql_dev:db -p 8080:8080 adminer - Portainer:Docker可视化管理
bash复制
docker run -d -p 9000:9000 --name portainer \ -v /var/run/docker.sock:/var/run/docker.sock \ portainer/portainer
- Adminer:轻量级数据库管理工具
-
进阶书籍:
- 《Docker实践》
- 《MySQL运维内参》
从个人经验来看,掌握Docker部署MySQL只是起点。真正提升效率的是将这种容器化思维扩展到整个开发流程中,比如结合CI/CD实现自动化测试、用Docker Compose管理微服务等。刚开始可能会觉得有些概念难以理解,但坚持实操两周后,你会发现自己再也回不去传统部署方式了。