Docker Compose集成MySQL启动失败,应用无法连接数据库求助
问题描述
我正在跟随Docker教程搭建一个包含MySQL数据库的简单Hello World级Docker Compose项目,但启动失败。以下是我的docker-compose.yml配置:
services: app: image: node:18-alpine command: sh -c "yarn install && yarn run dev" ports: - 3000:3000 working_dir: /app volumes: - ./:/app environment: MYSQL_HOST: mysql MYSQL_USER: root MYSQL_PASSWORD: secret MYSQL_DB: todos mysql: image: mysql:8.0 volumes: - todo-mysql-data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: todos volumes: todo-mysql-data:
单独启动各服务时应用可正常运行,但执行docker compose up时,MySQL容器看似已就绪,但应用服务无法连接到数据库,日志信息如下:
> sudo docker compose logs -f ... app-mysql-1 | 2023-05-24T09:05:29.562329Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.33' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL. app-app-1 | Waiting for mysql:3306....... app-app-1 | Timeout
我可以通过sudo docker exec -it <mysql-container-id> mysql -u root -p正常连接到数据库,尝试为应用服务添加延迟等待数据库启动后问题仍未解决,请问有什么解决思路?
解决思路
替换简单延迟为数据库就绪检测:简单sleep延迟不可靠,MySQL日志显示"ready for connections"后,可能还需要几秒完成权限初始化、数据库创建等操作。可以在app服务的启动命令中加入基于
mysql-client的检测逻辑:command: sh -c "apk add --no-cache mysql-client && while ! mysql -h mysql -u root -psecret -e 'SELECT 1'; do sleep 1; done && yarn install && yarn run dev"该命令会循环检测,直到成功执行SQL查询后再启动应用。
排查MySQL 8.0认证插件兼容性:MySQL 8.0默认使用
caching_sha2_password认证插件,部分旧版本Node.js MySQL客户端(如mysql包)不支持该插件。可修改MySQL服务配置,强制使用mysql_native_password:mysql: image: mysql:8.0 command: --default-authentication-plugin=mysql_native_password volumes: - todo-mysql-data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: todos同时确保Node.js项目的数据库客户端版本适配,或切换为支持
caching_sha2_password的客户端(如mysql2)。验证容器网络与数据库连通性:进入app容器内部,手动测试网络连通和数据库访问:
sudo docker exec -it app-app-1 sh # 测试DNS解析与网络连通 ping mysql # 尝试连接数据库 mysql -h mysql -u root -psecret todos若ping不通,检查Docker Compose默认网络状态;若ping通但连接失败,重点排查认证插件或权限配置。
配置MySQL健康检查与服务依赖:通过健康检查让Docker Compose等待MySQL真正就绪后再启动app服务:
首先为mysql服务添加健康检查:mysql: image: mysql:8.0 volumes: - todo-mysql-data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: todos healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-psecret"] interval: 2s timeout: 20s retries: 10然后在app服务中配置依赖mysql的健康状态:
app: image: node:18-alpine command: sh -c "yarn install && yarn run dev" ports: - 3000:3000 working_dir: /app volumes: - ./:/app environment: MYSQL_HOST: mysql MYSQL_USER: root MYSQL_PASSWORD: secret MYSQL_DB: todos depends_on: mysql: condition: service_healthy
内容的提问来源于stack exchange,提问作者Felipe Reigosa

