1Panel-mysql-vVOOmysql:8.4.4/opt/1panel/apps/mysql/mysql/docker-compose.yml/opt/1panel/apps/mysql/mysql/conf/my.cnf/opt/1panel/apps/mysql/mysql/data127.0.0.1:30006不要在此文档或 shell 历史中记录 sudo、MySQL root 等明文密码。以下使用环境变量占位。
bashexport 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'
检查容器:
bashprintf '%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.
检查容器配置和挂载:
bashprintf '%s\n' "$SUDO_PASSWORD" | sudo -S docker inspect "$MYSQL_CONTAINER" --format '{{json .Config}}\n{{json .HostConfig}}\n{{json .Mounts}}\n{{json .State}}'
原 MySQL 配置包含:
iniinnodb_force_recovery=6
该参数表明 InnoDB 已损坏,6 是最高应急恢复等级,只适用于只读导出,不能用于正常生产运行。旧容器可写层另有残留空 socket 锁文件,导致启动中止。
bashprintf '%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 中的数据目录:
bashprintf '%s\n' "$SUDO_PASSWORD" | sudo -S docker compose -f "$MYSQL_APP/docker-compose.yml" up -d --force-recreate
确认 MySQL 仍在应急恢复模式:
bashprintf '%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。
先创建包含权限和属主的物理备份,并备份原配置:
bashprintf '%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"'
在强制恢复模式下导出全部数据库、例程、事件和触发器:
bashprintf '%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 中移除:
iniinnodb_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/
停止旧实例,保留旧数据目录,创建新的空数据目录,写入正常配置并重新启动:
bashprintf '%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 初始化完成:
bashprintf '%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'
正常结果:
textmysqld is alive
bashprintf '%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;"'
导入后应确认:
textinnodb_force_recovery = 0 read_only = 0
执行临时读写测试并检查 Nextcloud 表数量:
bashprintf '%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 张表。
重启后再次验证:
bashprintf '%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 许可协议。转载请注明出处!