编辑
2026-07-14
小白笔记
0

目录

Docker MySQL 容器故障修复记录
环境
故障表现与根因
检查存储与配置
第一次容器重建
创建备份
重建干净的数据库实例
导入备份
功能与重启验证

Docker MySQL 容器故障修复记录

环境

  • 容器:1Panel-mysql-vVOO
  • 镜像:mysql:8.4.4
  • Compose:/opt/1panel/apps/mysql/mysql/docker-compose.yml
  • 配置:/opt/1panel/apps/mysql/mysql/conf/my.cnf
  • 数据目录:/opt/1panel/apps/mysql/mysql/data
  • MySQL 地址:127.0.0.1:30006
  • 修复日期:2026-07-14

不要在此文档或 shell 历史中记录 sudo、MySQL root 等明文密码。以下使用环境变量占位。

bash
export SUDO_PASSWORD='<sudo-password>' export MYSQL_ROOT_PASSWORD='<mysql-root-password>' export MYSQL_CONTAINER='1Panel-mysql-vVOO' export MYSQL_APP='/opt/1panel/apps/mysql/mysql'

故障表现与根因

检查容器:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S docker ps -a printf '%s\n' "$SUDO_PASSWORD" | sudo -S docker logs --tail 300 "$MYSQL_CONTAINER"

容器以退出码 1 停止。日志包含 InnoDB 断言失败和以下 socket 锁错误:

text
[ERROR] [MY-013183] [InnoDB] Assertion failure [ERROR] [MY-010276] [Server] Unix socket lock file is empty /var/run/mysqld/mysqld.sock.lock [ERROR] [MY-010268] [Server] Unable to setup unix socket lock file.

检查容器配置和挂载:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S docker inspect "$MYSQL_CONTAINER" --format '{{json .Config}}\n{{json .HostConfig}}\n{{json .Mounts}}\n{{json .State}}'

原 MySQL 配置包含:

ini
innodb_force_recovery=6

该参数表明 InnoDB 已损坏,6 是最高应急恢复等级,只适用于只读导出,不能用于正常生产运行。旧容器可写层另有残留空 socket 锁文件,导致启动中止。

检查存储与配置

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S df -h / /opt /var/lib/docker printf '%s\n' "$SUDO_PASSWORD" | sudo -S sh -c 'df -i / /opt /var/lib/docker'

修复时数据目录为约 4.7 GiB,磁盘余量约 283 GiB。

第一次容器重建

为清除旧容器运行层内残留的 socket 锁文件,先强制重建容器。此命令不删除 bind mount 中的数据目录:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S docker compose -f "$MYSQL_APP/docker-compose.yml" up -d --force-recreate

确认 MySQL 仍在应急恢复模式:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S docker exec "$MYSQL_CONTAINER" mysql --protocol=socket -uroot -p"$MYSQL_ROOT_PASSWORD" -e 'SELECT VERSION() AS version, @@innodb_force_recovery AS innodb_force_recovery;'

结果为 innodb_force_recovery = 6

创建备份

先创建包含权限和属主的物理备份,并备份原配置:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S sh -c 'backup=/opt/1panel/apps/mysql/mysql/data-backup-20260714-0309; test -d /opt/1panel/apps/mysql/mysql && test ! -e "$backup" && cp -a /opt/1panel/apps/mysql/mysql/data "$backup" && cp -a /opt/1panel/apps/mysql/mysql/conf/my.cnf /opt/1panel/apps/mysql/mysql/conf/my.cnf.backup-20260714-0309 && du -sh "$backup"'

在强制恢复模式下导出全部数据库、例程、事件和触发器:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S sh -c 'test -d /opt/1panel/apps/mysql/mysql && test ! -e /opt/1panel/apps/mysql/mysql/recovery-export-20260714-0616.sql && docker exec 1Panel-mysql-vVOO mysqldump --protocol=socket -uroot -p"$MYSQL_ROOT_PASSWORD" --all-databases --routines --events --triggers --hex-blob --single-transaction > /opt/1panel/apps/mysql/mysql/recovery-export-20260714-0616.sql && ls -lh /opt/1panel/apps/mysql/mysql/recovery-export-20260714-0616.sql'

逻辑导出文件为 recovery-export-20260714-0616.sql,大小约 61 MiB。

重建干净的数据库实例

my.cnf 中移除:

ini
innodb_force_recovery=6

其余配置保持:

ini
[mysqld] host-cache-size=0 skip-name-resolve datadir=/var/lib/mysql socket=/var/run/mysqld/mysqld.sock secure-file-priv=/var/lib/mysql-files user=mysql pid-file=/var/run/mysqld/mysqld.pid [client] socket=/var/run/mysqld/mysqld.sock !includedir /etc/mysql/conf.d/

停止旧实例,保留旧数据目录,创建新的空数据目录,写入正常配置并重新启动:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S sh -c 'set -e; app=/opt/1panel/apps/mysql/mysql; test -d "$app"; test -f "$app/recovery-export-20260714-0616.sql"; docker compose -f "$app/docker-compose.yml" down; mv "$app/data" "$app/data-before-rebuild-20260714-0619"; mkdir "$app/data"; chown 999:999 "$app/data"; install -o root -g root -m 0644 /tmp/mysql-my.cnf-normal "$app/conf/my.cnf"; docker compose -f "$app/docker-compose.yml" up -d'

等待 MySQL 初始化完成:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S sh -c 'for i in $(seq 1 30); do if docker exec 1Panel-mysql-vVOO mysqladmin --protocol=socket -uroot -p"$MYSQL_ROOT_PASSWORD" ping >/dev/null 2>&1; then exit 0; fi; sleep 10; done; docker logs --tail 120 1Panel-mysql-vVOO; exit 1'

正常结果:

text
mysqld is alive

导入备份

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S sh -c 'set -e; docker exec -i 1Panel-mysql-vVOO mysql --protocol=socket -uroot -p"$MYSQL_ROOT_PASSWORD" < /opt/1panel/apps/mysql/mysql/recovery-export-20260714-0616.sql; docker exec 1Panel-mysql-vVOO mysql --protocol=socket -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SELECT VERSION() AS version, @@innodb_force_recovery AS innodb_force_recovery, @@read_only AS read_only; SHOW DATABASES;"'

导入后应确认:

text
innodb_force_recovery = 0 read_only = 0

功能与重启验证

执行临时读写测试并检查 Nextcloud 表数量:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S docker exec "$MYSQL_CONTAINER" mysql --protocol=socket -uroot -p"$MYSQL_ROOT_PASSWORD" -e "CREATE DATABASE mysql_recovery_verify; CREATE TABLE mysql_recovery_verify.t (id INT PRIMARY KEY); INSERT INTO mysql_recovery_verify.t VALUES (1); SELECT COUNT(*) AS persisted_write_count FROM mysql_recovery_verify.t; DROP DATABASE mysql_recovery_verify; SELECT COUNT(*) AS nextcloud_table_count FROM information_schema.tables WHERE table_schema = 'nextcloud';"

修复时结果:临时写入成功,nextcloud 有 167 张表。

重启后再次验证:

bash
printf '%s\n' "$SUDO_PASSWORD" | sudo -S docker restart "$MYSQL_CONTAINER" 最终验证结果:容器为 `running`,退出码为 `0`,`innodb_force_recovery=0` 且 `read_only=0`。 ## 保留的恢复文件 在确认 Nextcloud 长期正常前,不要删除: ```text /opt/1panel/apps/mysql/mysql/data-backup-20260714-0309 /opt/1panel/apps/mysql/mysql/data-before-rebuild-20260714-0619 /opt/1panel/apps/mysql/mysql/recovery-export-20260714-0616.sql /opt/1panel/apps/mysql/mysql/conf/my.cnf.backup-20260714-0309

建议至少保留 7 至 30 天,并把逻辑 SQL 备份复制至其他磁盘或远程存储。

本文作者:墨洺的文档

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!