必须挂载/var/lib/mysql,否则升级即丢数据;需先用docker inspect确认旧容器是否挂载该路径,推荐用命名卷(如mysql_data_84)复用数据,停旧启新后mysql自动执行mysql_upgrade,再验证数据、字符集及客户端连接参数。

必须挂载 /var/lib/mysql,否则升级即丢数据
不挂载就升级,等于把数据库文件放在容器可写层——容器一删,/var/lib/mysql 目录直接清空,连初始化都得重来。这不是 MySQL 的 bug,是 Docker 默认行为:可写层随容器销毁而消失。
哪怕只是 docker stop && docker rm && docker run 一次,没挂载就全没了。所以第一步不是拉新镜像,而是确认旧容器是否已挂载该路径:
• 运行 docker inspect <container_name> | grep -A 5 Mounts</container_name>,看是否有 /var/lib/mysql 映射到宿主机目录或命名卷
• 如果输出为空,或 Source 是空字符串、Destination 是 /var/lib/mysql 但没 Mode 或 RW 为 true 却无实际挂载点,说明没挂载
用命名卷(docker volume)比绑定挂载(-v /host/path:/var/lib/mysql)更稳妥
命名卷由 Docker 管理路径和权限,避免因宿主机目录权限错乱导致 MySQL 启动失败(常见错误:mysqld: Can't create test file 或 Table 'mysql.plugin' doesn't exist)。绑定挂载需手动 chown -R 999:999 /host/path,且路径硬编码不利于迁移。
• 创建命名卷:docker volume create mysql_data_84
• 启动旧容器时已用命名卷,升级时直接复用该卷名即可
• 若旧容器用的是绑定挂载,升级前建议先用 docker run --rm -v mysql_data_84:/target -v /old/host/path:/source alpine cp -r /source/. /target/ 迁移数据,再改用命名卷启动新容器
使用 Python 脚本下载 Docker 镜像并打包为 tar 文件。用户说“下载镜像”“拉取镜像”“pull xxx”“帮我下载 nginx 镜像”等时触发。支持 SOCKS5 代理直连(推荐)和国内镜像站加速两种模式。
升级过程必须停旧启新,不能热替换镜像
Docker 不支持运行中替换容器镜像,所谓“热升级”本质仍是停旧启新。关键在于控制停机窗口和兼容性:
• 先停旧容器:docker stop mysql_80(MySQL 8.0 容器名)
• 拉取目标镜像:docker pull mysql:8.4.8(LTS 版本更稳)
• 启动新容器,**复用原卷**:docker run -d --name mysql_84 -e MYSQL_ROOT_PASSWORD=xxx -v mysql_data_84:/var/lib/mysql -p 3306:3306 mysql:8.4.8
• 注意:MySQL 8.0 → 8.4 属于大版本内升级,官方支持原地升级,但首次启动时会自动执行 mysql_upgrade(日志里能看到 Upgrading MySQL data directory),此过程可能耗时数秒至几分钟,取决于数据量
升级后立即验证数据可读性和字符集兼容性
MySQL 8.4 默认字符集是 utf8mb4,排序规则是 utf8mb4_0900_ai_ci。若旧库用的是 utf8mb4_unicode_ci 或更老的 utf8,表结构不会自动改,但查询可能因排序规则差异返回不同结果。
• 登录验证:docker exec -it mysql_84 mysql -uroot -p -e "SHOW DATABASES;"
• 检查关键表数据:SELECT COUNT(*) FROM your_db.your_table;
• 查看字符集:SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'your_db';
• 容易被忽略的是:某些客户端(如旧版 Navicat、PHP mysqli)未显式设置 charset=utf8mb4,会导致插入 emoji 失败或乱码,必须同步调整连接参数










