自定义CMD导致Docker MySQL容器无法启动,无法等待服务就绪
问题分析与解决方案
这个问题的核心是你误解了官方mysql:5 Docker镜像的启动流程——你的自定义CMD覆盖了镜像默认的启动命令,导致MySQL服务根本没启动起来,自然你的等待脚本永远连不上!
为什么会出现这个问题?
官方mysql:5镜像的启动逻辑是这样的:
- 镜像的
ENTRYPOINT是docker-entrypoint.sh,这个脚本负责处理MySQL的初始化(比如设置root密码、创建默认数据库等),最后会启动mysqld进程。 - 镜像默认的
CMD是["mysqld"],这个参数会传递给ENTRYPOINT脚本,作为最终启动服务的命令。
而你的自定义CMD:
CMD ["./setup/setup.sh", "mysql", "-u", "root", "<", "./setup/schema.sql"]
直接替换了官方的CMD,导致ENTRYPOINT脚本接收到的参数是你的setup.sh命令,而不是启动mysqld的指令。这意味着容器启动后,只运行了你的setup.sh,但MySQL服务从来没被启动过,所以脚本里的mysql -uroot -c '\q'永远会连接失败,进入循环等待。
正确的解决方案(推荐利用官方镜像的初始化机制)
官方MySQL镜像提供了自动初始化的功能:容器第一次启动时,会自动执行/docker-entrypoint-initdb.d/目录下的.sh、.sql、.sql.gz文件。你完全不需要自己写等待脚本,直接利用这个机制即可。
1. 修改你的Dockerfile
FROM mysql:5 # 添加数据目录(如果需要的话) RUN mkdir /server_data WORKDIR /server_data ADD --chown="root:root" ./db.data . # 复制配置文件 COPY ./config /etc/mysql/conf.d # 将初始化脚本和SQL文件复制到官方指定的初始化目录 COPY ./setup/setup.sh /docker-entrypoint-initdb.d/ COPY ./setup/schema.sql /docker-entrypoint-initdb.d/ # 给脚本添加可执行权限 RUN chmod +x /docker-entrypoint-initdb.d/setup.sh
2. 简化你的setup.sh(不需要等待逻辑)
因为官方docker-entrypoint.sh会确保MySQL服务启动完成后,才会执行/docker-entrypoint-initdb.d/下的脚本,所以你可以直接写初始化逻辑:
#!/bin/bash # 执行SQL脚本(这里可以用mysql命令直接执行,因为此时MySQL已经可用) mysql -uroot -p"$MYSQL_ROOT_PASSWORD" < /docker-entrypoint-initdb.d/schema.sql # 如果你还有其他初始化命令,继续在这里添加
3. 保持docker-compose.yml不变
你的docker-compose.yml配置没问题,环境变量MYSQL_ROOT_PASSWORD会被官方初始化脚本读取,用于设置root密码。
如果你一定要用自定义的等待脚本(不推荐)
如果坚持要用自己的setup.sh来控制流程,你需要修改ENTRYPOINT和CMD,确保先启动MySQL服务,再执行初始化:
修改后的Dockerfile
FROM mysql:5 # ... 其他不变的步骤 ... # 覆盖ENTRYPOINT,先启动MySQL,再执行初始化 ENTRYPOINT ["./setup/setup.sh"] CMD ["mysqld"]
修改setup.sh
#!/bin/bash set -e # 先保存原始的CMD命令(即启动mysqld的命令) cmd="$@" # 启动MySQL服务(后台运行) mysqld & pid="$!" # 等待MySQL启动 until mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -c '\q'; do >&2 echo "mysql is unavailable - sleeping" sleep 1 done >&2 echo "mysql is up - executing initialization" # 执行SQL脚本 mysql -uroot -p"$MYSQL_ROOT_PASSWORD" < ./setup/schema.sql # 等待MySQL进程,保持容器运行 wait "$pid"
这种方式需要自己管理MySQL进程的生命周期,不如官方的初始化机制可靠,所以更推荐第一种方案。
内容的提问来源于stack exchange,提问作者Stephen
相关产品推荐
相关产品推荐

