侧边栏壁纸
  • 累计撰写 20 篇文章
  • 累计创建 5 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Docker-Compose部署MySQL-001

Docker Compose 部署 MySQL 数据库指南

版本: 1.0
更新时间: 2025-06-06
维护者: guobin


前言

什么是 Docker Compose?

想象一下:你要开一家餐厅(部署服务),需要同时安排厨师(MySQL)、服务员(Nginx)、收银员(Redis)各司其职。如果一个个招聘、培训、安排工位,太麻烦了。

Docker Compose 就像一个"团队经理",你只需要写一份"排班表"(docker-compose.yml),它就能一次性把所有员工(容器)安排好,让它们互相配合,同时开工。

用 Docker Compose 部署 MySQL,你不需要手动安装数据库、配置环境变量、创建数据目录——一条命令 docker-compose up -d,一切就绪。

本文档会告诉你:

  • 部署前的环境准备要求
  • Docker 及 Docker Compose 的安装步骤
  • 完整的 docker-compose.yml 配置示例
  • 部署、验证、排查的完整流程
  • 安全最佳实践和数据持久化方案
  • 服务停止与卸载步骤

目录

  1. 环境准备要求
  2. 安装 Docker 和 Docker Compose
  3. 编写 docker-compose.yml 配置文件
  4. 部署流程
  5. 安全最佳实践
  6. 数据持久化方案
  7. 常见问题排查
  8. 服务停止与卸载
  9. 总结

一、环境准备要求

1.1 硬件要求

资源 最低要求 推荐配置 说明
CPU 2 核 4 核+ MySQL 是 CPU 密集型应用
内存 2 GB 4 GB+ MySQL 至少需要 1GB 运行内存
磁盘 10 GB 50 GB+ 取决于数据量,建议 SSD
网络 100 Mbps 1 Gbps 数据库读写频繁时需要高速网络

通俗解释:如果 CPU 是厨师,内存是厨房操作台,磁盘是仓库。厨房太小(内存不足),厨师就施展不开;仓库太小(磁盘不足),食材(数据)就没地方放。

1.2 软件要求

软件 版本要求 说明
操作系统 Linux (CentOS 7+ / Ubuntu 18.04+ / Debian 10+) 推荐使用 Linux 生产环境
Docker 20.10+ 容器运行环境
Docker Compose 2.0+ 多容器编排工具

1.3 端口要求

端口 用途 说明
3306 MySQL 默认端口 数据库连接端口,确保未被占用
# 检查 3306 端口是否被占用
netstat -tuln | grep 3306
# 或
ss -tuln | grep 3306

# 参数解释:
# -tuln:
#   -t:TCP 连接
#   -u:UDP 连接
#   -l:只显示监听的端口
#   -n:以数字形式显示(不解析域名,加快速度)
# | grep 3306:过滤包含 3306 的行

# 输出示例(端口空闲):
# (无输出)→ 说明 3306 端口空闲,可以使用 ✅

# 输出示例(端口被占用):
# tcp6  0  0 :::3306  :::*  LISTEN
# 说明已有程序占用了 3306 端口,需要先关闭该程序或修改 MySQL 端口

二、安装 Docker 和 Docker Compose

2.1 安装 Docker

Ubuntu / Debian

# 🚀 一键安装 Docker(官方脚本)
curl -fsSL https://get.docker.com | sh

# 参数解释:
# curl:下载文件
# -f:失败时不显示错误页面
# -s:静默模式(不显示进度条)
# -S:出错时显示错误信息
# -L:跟随重定向
# | sh:将下载的内容交给 shell 执行

# 启动 Docker 服务
sudo systemctl start docker

# 设置开机自启
sudo systemctl enable docker

# 验证安装
docker --version

# 输出示例:
# Docker version 24.0.7, build afdf5e4
# 解读:看到版本号 = 安装成功 ✅

CentOS / RHEL

# 🚀 安装 Docker(yum 方式)
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io

# 启动并设置自启
sudo systemctl start docker
sudo systemctl enable docker

# 验证
docker --version

2.2 安装 Docker Compose

什么是 Docker Compose?

Docker 是单个集装箱(容器),Docker Compose 是指挥多个集装箱协同工作的"船长"。
你只需要写一份"航海计划"(docker-compose.yml),它就能同时启动多个集装箱,让它们互相配合。

# 🚀 下载 Docker Compose 二进制文件(推荐方式)
sudo curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 参数解释:
# -L:跟随重定向(GitHub 的下载链接会重定向)
# $(uname -s):获取操作系统名称(Linux)
# $(uname -m):获取 CPU 架构(x86_64)
# -o:输出到指定路径

# 添加执行权限
sudo chmod +x /usr/local/bin/docker-compose

# 验证安装
docker-compose --version

# 输出示例:
# Docker Compose version v2.23.0
# 解读:看到版本号 = 安装成功 ✅

2.3 配置 Docker 用户权限(可选)

# 将当前用户加入 docker 组(这样就不用每次都 sudo 了)
sudo usermod -aG docker $USER

# 参数解释:
# usermod:修改用户属性
# -aG:追加到组(a=append, G=group)
# docker:组名
# $USER:当前用户名

# ⚠️ 注意:需要重新登录才能生效
# 重新登录后验证:
docker ps

# 如果不报错,说明配置成功 ✅

三、编写 docker-compose.yml 配置文件

3.1 创建项目目录

# 创建 MySQL 部署目录(幂等操作)
mkdir -p /opt/mysql-docker

# 参数解释:
# -p:父目录不存在时自动创建(幂等,不会报错)

# 进入目录
cd /opt/mysql-docker

# 创建配置文件
touch docker-compose.yml

3.2 完整的 docker-compose.yml 配置

version: '3.8'

services:
  mysql:
    # 是什么:使用的 Docker 镜像及其版本
    # 为什么:8.0 是 MySQL 的长期支持版本,稳定且功能完善
    # 怎么用:可以改成其他版本,如 mysql:5.7 或 mysql:8.0
    image: mysql:8.0

    # 是什么:容器的名称
    # 为什么:方便在 docker 命令中引用,如 docker logs mysql-db
    # 怎么用:改成你想要的容器名
    container_name: mysql-db

    # 是什么:容器重启策略
    # 为什么:除非手动停止,否则总是重启(保证服务高可用)
    # 怎么用:可选值:no(不重启)/ always(总是重启)/ on-failure(失败时重启)/ unless-stopped(除非手动停止)
    restart: unless-stopped

    # 是什么:端口映射(宿主机端口:容器端口)
    # 为什么:让外部能通过 3306 端口访问 MySQL
    # 怎么用:如果 3306 被占用,可以改成其他端口,如 13306:3306
    ports:
      - "3306:3306"

    # 是什么:环境变量配置
    # 为什么:MySQL 容器启动时读取这些变量进行初始化配置
    # 怎么用:修改为你自己的密码和数据库名
    environment:
      # 是什么:MySQL root 用户的密码(必须设置)
      # 为什么:root 是数据库管理员,没有密码容器不会启动
      # ⚠️ 生产环境建议使用 .env 文件或 Docker Secret
      MYSQL_ROOT_PASSWORD: "MyRootPassword@123"

      # 是什么:创建一个普通数据库用户
      # 为什么:应用不应该用 root 连接数据库,应该用普通用户
      # 怎么用:改成你想要的用户名
      MYSQL_USER: "appuser"

      # 是什么:普通用户的密码
      # 怎么用:改成你想要的密码
      MYSQL_PASSWORD: "AppPassword@456"

      # 是什么:创建一个初始数据库
      # 为什么:MySQL 容器启动时会自动创建这个数据库,并授权给 MYSQL_USER
      # 怎么用:改成你想要的数据库名
      MYSQL_DATABASE: "myapp_db"

      # 是什么:MySQL 服务器的字符集配置
      # 为什么:支持中文、emoji 等特殊字符(utf8mb4 是 utf8 的超集)
      # 怎么用:一般不需要改
      MYSQL_CHARSET: "utf8mb4"

    # 是什么:数据卷挂载(宿主机目录:容器内目录)
    # 为什么:容器删除后数据不会丢失(数据持久化)
    # 怎么用:冒号左边是宿主机路径,右边是容器内路径
    volumes:
      # 是什么:MySQL 数据目录
      # 为什么:存放数据库文件、表数据、索引等(最重要的数据)
      # 怎么用:./data 表示当前目录下的 data 文件夹
      - ./data:/var/lib/mysql

      # 是什么:MySQL 配置文件挂载
      # 为什么:自定义 MySQL 配置(如最大连接数、日志格式等)
      # 怎么用:先创建 ./conf/my.cnf,然后挂载
      - ./conf/my.cnf:/etc/mysql/conf.d/my.cnf

      # 是什么:MySQL 初始化脚本目录
      # 为什么:容器首次启动时会自动执行 /docker-entrypoint-initdb.d/ 下的 .sql/.sh 脚本
      # 怎么用:把你的初始化脚本放在 ./init/ 目录下
      - ./init:/docker-entrypoint-initdb.d

    # 是什么:资源限制
    # 为什么:防止 MySQL 占用过多资源影响其他服务
    # 怎么用:根据你的服务器配置调整
    deploy:
      resources:
        limits:
          # 是什么:容器最多使用 512MB 内存
          # 为什么:防止内存泄漏导致系统崩溃
          memory: 512M
          # 是什么:容器最多使用 1.5 个 CPU 核心
          # 为什么:防止 CPU 占用过高
          cpus: '1.5'
        reservations:
          # 是什么:容器至少保证 256MB 内存
          # 为什么:保证 MySQL 有足够内存运行
          memory: 256M

    # 是什么:健康检查
    # 为什么:让 Docker 知道 MySQL 什么时候才算真正启动成功
    # 怎么用:一般不需要改
    healthcheck:
      # 是什么:检查命令
      # 为什么:用 mysqladmin ping 检查 MySQL 是否存活
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$MYSQL_ROOT_PASSWORD"]
      # 是什么:容器启动后等多久再开始检查
      # 为什么:MySQL 启动需要时间,太早检查会误报
      start_period: 30s
      # 是什么:每隔多久检查一次
      interval: 10s
      # 是什么:超时时间
      timeout: 5s
      # 是什么:连续失败 3 次才认为不健康
      retries: 3

    # 是什么:容器日志配置
    # 为什么:防止日志文件无限增长占满磁盘
    # 怎么用:根据你的需求调整大小和数量
    logging:
      driver: "json-file"
      options:
        # 是什么:每个日志文件最大 10MB
        max-size: "10m"
        # 是什么:最多保留 3 个日志文件
        max-file: "3"

    # 是什么:网络配置
    # 为什么:让 MySQL 和其他服务(如应用服务器)在同一个内网中通信
    # 怎么用:一般不需要改
    networks:
      - mysql-network

# 是什么:自定义网络
# 为什么:让容器之间能互相访问,同时和外部隔离
# 怎么用:其他服务也加入这个网络,就能用容器名互相访问
networks:
  mysql-network:
    # 是什么:网络驱动
    # 为什么:bridge 是 Docker 默认的网络驱动(桥接模式)
    # 怎么用:一般用 bridge 就够了
    driver: bridge

3.3 MySQL 配置文件(可选)

创建 ./conf/my.cnf 文件:

[mysqld]
# 是什么:默认字符集
# 为什么:支持中文和 emoji
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

# 是什么:最大连接数
# 为什么:限制同时连接数据库的客户端数量,防止资源耗尽
# 怎么用:根据你的应用并发量调整
max_connections = 200

# 是什么:慢查询日志
# 为什么:记录执行超过指定时间的 SQL,帮助优化性能
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2  # 超过 2 秒的查询记录

# 是什么:InnoDB 缓冲池大小
# 为什么:MySQL 最重要的性能参数,建议设置为内存的 50%-70%
# 怎么用:根据你的服务器内存调整
innodb_buffer_pool_size = 256M

# 是什么:SQL 模式
# 为什么:严格模式可以避免数据 truncation 等问题
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

[client]
default-character-set = utf8mb4

3.4 初始化 SQL 脚本(可选)

创建 ./init/01-init.sql 文件:

-- 创建示例表(容器首次启动时自动执行)

-- 使用指定的数据库
USE myapp_db;

-- 创建用户表
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID(自动增长)',
    username VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名(唯一)',
    email VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱(唯一)',
    password_hash VARCHAR(255) NOT NULL COMMENT '密码哈希值',
    status TINYINT DEFAULT 1 COMMENT '状态:1=启用,0=禁用',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';

-- 插入测试数据
INSERT INTO users (username, email, password_hash) VALUES
('admin', 'admin@example.com', '$2b$12$example_hash'),
('testuser', 'test@example.com', '$2b$12$example_hash');

四、部署流程

4.1 启动服务

# 🚀 启动 MySQL 服务(后台运行)
docker-compose up -d

# 参数解释:
# up:启动服务
# -d:detached 模式(后台运行,不阻塞终端)

# 输出示例:
# [+] Running 2/0
#  ✔ Network mysql-docker_mysql-network  Created    0.0s
#  ✔ Container mysql-db                  Started    0.5s

# 解读:
# - Network ... Created:网络创建成功
# - Container ... Started:容器启动成功

4.2 检查服务状态

# 👀 查看容器运行状态
docker-compose ps

# 输出示例:
# NAME      IMAGE       COMMAND                  SERVICE   CREATED         STATUS                   PORTS
# mysql-db  mysql:8.0   "docker-entrypoint.s…"   mysql     2 minutes ago   Up 2 minutes (healthy)   0.0.0.0:3306->3306/tcp

# 解读:
# - STATUS:Up 2 minutes (healthy) = 容器运行中且健康检查通过 ✅
# - STATUS:Up 2 minutes (starting) = 容器运行中但健康检查还没通过(MySQL 启动中)
# - STATUS:Exited = 容器已停止(需要排查)
# - PORTS:0.0.0.0:3306->3306/tcp = 宿主机 3306 端口映射到容器 3306 端口
# 👀 查看更详细的容器信息
docker ps -a

# 参数解释:
# -a:包括已停止的容器

# 输出示例:
# CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS                   PORTS     NAMES
# a1b2c3d4e5f6   mysql:8.0   "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes (healthy)   3306/tcp  mysql-db

# 解读:
# - CONTAINER ID:容器的唯一标识
# - CREATED:容器创建时间
# - STATUS:运行状态
# - NAMES:容器名称

4.3 查看日志

# 📋 查看实时日志
docker-compose logs -f mysql

# 参数解释:
# -f:follow 模式(实时滚动,类似 tail -f)
# mysql:指定服务名

# 按 Ctrl+C 退出日志查看
# 📋 查看最近 50 行日志
docker-compose logs --tail=50 mysql

# 参数解释:
# --tail=50:只显示最后 50 行
# 📋 查看完整的启动日志(判断是否启动成功)
docker-compose logs mysql | grep -i "ready for connections"

# 参数解释:
# grep -i:不区分大小写搜索
# "ready for connections":MySQL 启动成功的标志

# 输出示例(启动成功):
# mysql-db  | 2025-06-06T10:00:00.000000Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.35'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.

# 解读:
# - ready for connections = MySQL 启动成功 ✅
# - port: 3306 = 监听 3306 端口

4.4 连接 MySQL 验证

# 🔌 通过 Docker exec 进入容器内连接 MySQL
docker exec -it mysql-db mysql -uroot -pMyRootPassword@123

# 参数解释:
# exec:在容器内执行命令
# -it:
#   -i:交互式(interactive)
#   -t:分配伪终端(tty)
# mysql-db:容器名称
# mysql:MySQL 客户端命令
# -uroot:以 root 用户登录
# -pMyRootPassword@123:密码(-p 和密码之间没有空格)

# 进入 MySQL 命令行后:

# 查看数据库列表
SHOW DATABASES;

# 输出:
# +--------------------+
# | Database           |
# +--------------------+
# | information_schema |
# | myapp_db           |  ← 这是我们创建的数据库
# | mysql              |
# | performance_schema |
# | sys                |
# +--------------------+
# 解读:能看到 myapp_db = 数据库创建成功 ✅

# 使用应用数据库
USE myapp_db;

# 查看表
SHOW TABLES;

# 输出(如果有初始化脚本):
# +--------------------+
# | Tables_in_myapp_db |
# +--------------------+
# | users              |
# +--------------------+

# 查询数据
SELECT * FROM users;

# 退出 MySQL
EXIT;

4.5 外部连接测试

# 🔌 从宿主机或其他机器连接 MySQL
mysql -h 127.0.0.1 -P 3306 -u root -pMyRootPassword@123

# 参数解释:
# -h 127.0.0.1:主机地址(本机)
# -P 3306:端口号(大写的 P)

# 如果提示 "command not found",说明宿主机没装 MySQL 客户端
# 可以改用:
docker exec -it mysql-db mysql -uroot -pMyRootPassword@123

五、安全最佳实践

5.1 密码管理

❌ 不推荐:明文写在 docker-compose.yml 中

# 不推荐:密码直接写在文件中,容易被 git 提交
environment:
  MYSQL_ROOT_PASSWORD: "MyRootPassword@123"

✅ 推荐方案一:使用 .env 文件

创建 .env 文件:

# .env 文件(不要提交到 git)
MYSQL_ROOT_PASSWORD=MyRootPassword@123
MYSQL_USER=appuser
MYSQL_PASSWORD=AppPassword@456
MYSQL_DATABASE=myapp_db

修改 docker-compose.yml

environment:
  MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
  MYSQL_USER: ${MYSQL_USER}
  MYSQL_PASSWORD: ${MYSQL_PASSWORD}
  MYSQL_DATABASE: ${MYSQL_DATABASE}
# ⚠️ 重要:将 .env 加入 .gitignore,防止密码泄露
echo ".env" >> .gitignore

✅ 推荐方案二:使用 Docker Secret(生产环境推荐)

version: '3.8'

services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
    secrets:
      - mysql_root_password

secrets:
  mysql_root_password:
    file: ./secrets/mysql_root_password.txt
# 创建密码文件
mkdir -p ./secrets
echo "MyRootPassword@123" > ./secrets/mysql_root_password.txt

# ⚠️ 设置严格的文件权限(只有 owner 可读)
chmod 600 ./secrets/mysql_root_password.txt

5.2 网络隔离

# 限制只有特定网络才能访问 MySQL
networks:
  mysql-network:
    driver: bridge
    # 是什么:IP 地址管理
    # 为什么:限制网络范围,提高安全性
    ipam:
      config:
        - subnet: 172.20.0.0/16  # 只允许这个子网访问

5.3 不要用 root 运行应用

-- 创建应用专用用户(最小权限原则)
CREATE USER 'app_user'@'%' IDENTIFIED BY 'AppPassword@456';

-- 只授予必要的权限(而不是 ALL)
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'app_user'@'%';

-- 刷新权限
FLUSH PRIVILEGES;

-- 解读:
# SELECT, INSERT, UPDATE, DELETE:只允许增删改查
# 不允许 CREATE, DROP, ALTER 等危险操作
# ON myapp_db.*:只能访问 myapp_db 数据库

5.4 定期备份

# 📋 创建备份脚本
cat > /opt/mysql-docker/backup.sh << 'EOF'
#!/bin/bash

# 备份目录
BACKUP_DIR="/opt/mysql-docker/backups"
mkdir -p "$BACKUP_DIR"

# 备份文件名(带时间戳)
BACKUP_FILE="$BACKUP_DIR/mysql_backup_$(date +%Y%m%d_%H%M%S).sql"

# 执行备份
docker exec mysql-db mysqldump -uroot -pMyRootPassword@123 --all-databases > "$BACKUP_FILE"

# 压缩备份文件
gzip "$BACKUP_FILE"

# 删除 7 天前的旧备份
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -delete

echo "✅ 备份完成:${BACKUP_FILE}.gz"
EOF

chmod +x /opt/mysql-docker/backup.sh

# 设置定时任务(每天凌晨 2 点备份)
(crontab -l 2>/dev/null; echo "0 2 * * * /opt/mysql-docker/backup.sh") | crontab -

六、数据持久化方案

6.1 数据卷挂载方式对比

方式 语法 优点 缺点
Bind Mount ./data:/var/lib/mysql 文件直接在宿主机可见 依赖宿主机路径
Named Volume mysql_data:/var/lib/mysql Docker 管理,跨平台 不方便直接访问文件
tmpfs tmpfs:/tmp 速度快 容器停止后数据丢失

6.2 推荐方案:Bind Mount

volumes:
  # 数据目录(最重要)
  - ./data:/var/lib/mysql

  # 配置文件
  - ./conf/my.cnf:/etc/mysql/conf.d/my.cnf

  # 初始化脚本(只在首次启动时执行)
  - ./init:/docker-entrypoint-initdb.d

  # 日志目录(可选)
  - ./logs:/var/log/mysql

6.3 数据备份与恢复

备份

# 📋 备份整个数据目录(冷备份,需要先停止容器)
docker-compose down
tar -czf mysql_data_backup_$(date +%Y%m%d).tar.gz ./data/
docker-compose up -d

# 参数解释:
# tar:打包压缩
# -c:创建新档案
# -z:用 gzip 压缩
# -f:指定文件名
# 📋 使用 mysqldump 备份(热备份,不需要停止容器)
docker exec mysql-db mysqldump -uroot -pMyRootPassword@123 --all-databases > backup_$(date +%Y%m%d).sql

# 参数解释:
# mysqldump:MySQL 逻辑备份工具
# --all-databases:备份所有数据库
# >:重定向输出到文件

恢复

# 📋 从 mysqldump 恢复
cat backup_20250606.sql | docker exec -i mysql-db mysql -uroot -pMyRootPassword@123

# 参数解释:
# cat:读取文件
# |:管道,把内容传给下一个命令
# -i:interactive 模式(从标准输入读取数据)
# 📋 从数据目录恢复(冷恢复)
docker-compose down
rm -rf ./data/
tar -xzf mysql_data_backup_20250606.tar.gz
docker-compose up -d

# ⚠️ 危险操作:rm -rf 会删除数据目录
# 操作前请确保备份文件完整可用

七、常见问题排查

问题 1:容器启动后立即退出

现象

docker-compose ps
# 输出:STATUS = Exited (1)

通俗解释:就像一个厨师(MySQL)还没开始炒菜就辞职了,通常是环境配置有问题。

排查步骤

# 📋 第一步:查看日志(最重要)
docker-compose logs mysql

# 常见错误及解决方案:

# 错误 1:[ERROR] [MY-010457] --initialize specified but the data directory has files in it
# 原因:数据目录不为空
# 解决:
rm -rf ./data/*
docker-compose up -d

# 错误 2:[ERROR] [MY-013276] Failed to initialize authentication
# 原因:密码不符合复杂度要求(MySQL 8.0)
# 解决:使用更复杂的密码(包含大小写、数字、特殊字符)

# 错误 3:Port 3306 is already in use
# 原因:端口被占用
# 解决:见问题 2

问题 2:端口被占用

现象

Error: Port 3306 is already in use

通俗解释:就像你要开一家新店,但门牌号已经被别人用了。

排查步骤

# 👀 查看哪个程序占用了 3306 端口
netstat -tuln | grep 3306
# 或
ss -tuln | grep 3306

# 输出示例:
# tcp6  0  0 :::3306  :::*  LISTEN

# 👀 查看是哪个进程
sudo lsof -i :3306

# 输出:
# COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
# mysqld  1234 mysql  34u  IPv6  12345      0t0  TCP *:3306 (LISTEN)

# 解读:
# - COMMAND:mysqld(另一个 MySQL 实例)
# - PID:1234

解决方案

  1. 方案一:关闭占用端口的程序
sudo kill 1234
# 或
sudo systemctl stop mysql  # 如果是系统 MySQL 服务
  1. 方案二:修改映射端口
# 修改 docker-compose.yml 中的 ports 部分
ports:
  - "13306:3306"  # 用 13306 映射到容器的 3306

问题 3:无法从外部连接 MySQL

现象

ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.1.100:3306' (111)

通俗解释:就像你给餐厅打电话,但电话线被切断了。

排查步骤

# 1. 检查 MySQL 是否在运行
docker-compose ps
# 确认 STATUS = Up (healthy)

# 2. 检查端口是否在监听
netstat -tuln | grep 3306
# 应该能看到 0.0.0.0:3306 或 :::3306

# 3. 检查防火墙
# Ubuntu/Debian
sudo ufw status
sudo ufw allow 3306/tcp

# CentOS/RHEL
sudo firewall-cmd --list-ports
sudo firewall-cmd --permanent --add-port=3306/tcp
sudo firewall-cmd --reload

# 4. 检查 MySQL 是否允许远程连接
docker exec -it mysql-db mysql -uroot -pMyRootPassword@123 -e "SELECT host, user FROM mysql.user;"

# 输出:
# +-----------+------------------+
# | host      | user             |
# +-----------+------------------+
# | %         | root             |  ← % 表示允许所有主机
# | localhost | root             |
# +-----------+------------------+
# 如果 root 的 host 只有 localhost,说明不允许远程连接

解决方案

-- 允许 root 从任何主机连接(⚠️ 生产环境不推荐)
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'MyRootPassword@123';
FLUSH PRIVILEGES;

-- 或者创建专门的远程用户(推荐)
CREATE USER 'remote_user'@'%' IDENTIFIED BY 'RemotePassword@789';
GRANT ALL PRIVILEGES ON myapp_db.* TO 'remote_user'@'%';
FLUSH PRIVILEGES;

问题 4:数据丢失

现象:重启容器后数据不见了。

通俗解释:就像你把东西放在临时宿舍里,退房后东西被清理了。

原因:没有配置数据卷挂载,数据存在容器内部,容器删除就没了。

解决方案

# 确保 docker-compose.yml 中有 volumes 配置
volumes:
  - ./data:/var/lib/mysql  # 这行必须有!
# 验证数据是否在宿主机
ls -la ./data/
# 应该能看到 mysql 的数据文件

问题 5:内存不足导致 MySQL 被杀

现象

Killed
# 或
docker-compose ps 显示 Exited (137)

通俗解释:就像餐厅雇不起厨师了(内存不够),只能把人辞退。

排查步骤

# 检查系统内存
free -h

# 检查是否有 OOM Killer 记录
dmesg | grep -i "killed process"

# 输出示例:
# [12345.678] Out of memory: Killed process 1234 (mysqld) total-vm:1234567kB, anon-rss:567890kB

# 解读:
# - mysqld 进程被 OOM Killer 杀掉了
# - 说明系统内存不足

解决方案

  1. 增加服务器内存
  2. 减少 MySQL 的内存配置:
# my.cnf
[mysqld]
innodb_buffer_pool_size = 128M  # 减少缓冲池
max_connections = 100           # 减少最大连接数

八、服务停止与卸载

8.1 停止服务

# ⏹️ 停止服务(容器和数据卷保留)
docker-compose stop

# 参数解释:
# stop:停止容器(类似关机,数据还在)

# 验证:
docker-compose ps
# STATUS 应该显示为 Exited

8.2 停止并删除容器

# ⏹️ 停止并删除容器、网络(数据卷保留)
docker-compose down

# 参数解释:
# down:停止容器并删除容器和网络(数据还在)

# 验证:
docker-compose ps
# 应该看不到容器了

# 验证数据还在:
ls -la ./data/

8.3 彻底清理(⚠️ 危险操作)

⚠️ 危险操作:以下操作会删除所有数据,操作前务必备份!

# 🗑️ 停止容器并删除数据卷(数据会丢失!)
docker-compose down -v

# 参数解释:
# -v:删除数据卷(包括所有数据)
# ⚠️ 操作前请确保已备份重要数据!
# 🗑️ 删除项目目录(彻底清理)
docker-compose down -v
cd ..
rm -rf mysql-docker/

# ⚠️ 再次提醒:这会删除所有 MySQL 数据!
# 操作前请执行备份:
# ./backup.sh  或
# docker exec mysql-db mysqldump -uroot -p --all-databases > backup.sql

8.4 卸载 Docker(可选)

# Ubuntu/Debian
sudo apt-get purge docker-ce docker-ce-cli containerd.io
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

# CentOS/RHEL
sudo yum remove docker-ce docker-ce-cli containerd.io
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

九、总结

核心操作速查表

操作 命令 说明
启动服务 docker-compose up -d 后台启动
查看状态 docker-compose ps 检查运行状态
查看日志 docker-compose logs -f mysql 实时日志
进入容器 docker exec -it mysql-db bash 进入容器终端
连接数据库 docker exec -it mysql-db mysql -uroot -p MySQL 客户端
停止服务 docker-compose stop 停止容器
删除容器 docker-compose down 删除容器(保留数据)
彻底清理 docker-compose down -v 删除所有数据(⚠️ 危险)

黄金法则

  1. 先备份,后操作 - 任何涉及数据的操作前先备份
  2. 数据卷必须挂载 - 没有 volumes 配置,重启就丢数据
  3. 不要用 root 跑应用 - 创建专用用户,最小权限原则
  4. 日志要限制大小 - 防止日志占满磁盘
  5. 密码不要硬编码 - 使用 .env 文件或 Docker Secret

文件结构

mysql-docker/
├── docker-compose.yml    # 核心配置文件
├── .env                  # 环境变量(不要提交 git)
├── data/                 # MySQL 数据目录(自动创建)
├── conf/
│   └── my.cnf           # MySQL 自定义配置
├── init/
│   └── 01-init.sql      # 初始化脚本(首次启动执行)
├── logs/                # 日志目录(可选)
└── backup.sh            # 备份脚本

文档版本:1.0
最后更新:2025-06-06
维护者:guobin

1
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区