Docker部署JHipster应用MySQL异常重启后数据丢失排查
排查与解决步骤
首先从日志特征可以锁定核心判断依据:MySQL重启后完整走了entrypoint初始化流程,说明启动时/var/lib/mysql路径下不存在已有的InnoDB系统表和用户数据文件,基本可以排除Liquibase主动删库的可能——Liquibase仅操作业务库表,不会删除MySQL本身的系统库。
第一步:先排除最常见的持久化配置错误
90%以上的这类问题都是数据卷挂载失效导致的,逐一核对:
- 确认挂载路径精确对应MySQL的数据目录
/var/lib/mysql,不要挂载到/var/lib/mysql/xxx子目录或者/var/lib上层目录,不要使用匿名临时卷。优先选择Docker命名卷做持久化,避免宿主机目录权限、自动清理带来的问题,配置参考:
volumes: mysql_data: {} services: mysql: image: mysql:8.0.29 volumes: - mysql_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: 你的数据库密码 restart: unless-stopped
- 如果必须用宿主机目录绑定挂载,先给目录赋权,MySQL 8.0官方镜像内运行用户的UID/GID为999,没有对应权限会无法写入数据文件,导致每次启动都重新初始化,执行命令修正权限:
chown -R 999:999 /path/to/your/host/mysql/dir - 验证持久化是否生效:手动进MySQL创建测试库、写入测试数据,执行
docker restart <mysql容器ID/名称>,重启后如果测试数据存在,说明持久化配置正常,否则继续排查挂载问题。
第二步:定位SHUTDOWN指令的来源
日志里的Received SHUTDOWN from user root不代表真的有用户手动执行了关库命令,mysqld收到Docker发送的SIGTERM优雅终止信号时,也会打印一模一样的日志,按以下方法定位触发源:
- 查看容器退出码:执行
docker inspect <mysql容器名> --format='{{.State.ExitCode}}',退出码为0说明是被正常发送终止信号关闭,退出码137是宿主机OOM Killer杀掉进程(调大容器内存限制即可解决),退出码139是进程崩溃(一般是版本bug或文件损坏)。 - 抓容器事件:执行
docker events --filter "container=<mysql容器名>"保持运行,等下一次MySQL自动关闭时,看事件日志里的触发主体,常见触发源包括:Docker daemon配置了自动清理策略、宿主机定时运维脚本、compose服务联动重启(比如依赖的应用容器重启时错误触发了数据库容器重启)。
第三步:修正应用侧配置与启动顺序
排除以上问题后,再核对JHipster的配置:
- 检查所有环境的配置文件,确保
spring.liquibase.drop-first配置为false,生产环境不要设置spring.jpa.hibernate.ddl-auto: create或create-drop,用validate即可,避免JPA自动删表建表。 - 给MySQL容器加健康检查,配置JHipster等数据库完全就绪后再启动,避免应用启动时连不上初始空库触发异常逻辑,健康检查与依赖配置参考:
# mysql服务段新增配置 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"] interval: 10s timeout: 5s retries: 10 # jhipster应用服务段修改depends_on配置 depends_on: mysql: condition: service_healthy
验证方法
按以上步骤修正配置后,手动写入测试数据,连续运行24小时观察,如果没有再出现数据丢失、数据库自动初始化的问题,说明故障已解决。
内容的提问来源于stack exchange,提问作者srcapezz
相关产品推荐
相关产品推荐

