如何在Dockerfile中正确启动并同时运行MySQL与Apache服务
问题根因
- Docker容器的核心运行逻辑是必须有一个持续运行的前台进程作为PID 1,如果前台所有进程都退出,容器就会直接停止。
- 你在Dockerfile的
RUN指令中启动MySQL、执行建库操作,仅会在镜像构建的临时构建层生效,镜像构建完成后,所有临时启动的进程都会被销毁,不会随容器启动保留运行状态。 - 你之前尝试把
/usr/sbin/mysqld -u mysql写入CMD,本质是用MySQL替换了基础镜像原本的Apache前台启动命令,因此Apache不会被自动拉起。
单容器同时运行Apache与MySQL的落地方法
如果不希望拆分容器,可以通过自定义启动脚本统一调度两个服务,核心逻辑是把非主服务放到后台运行,把其中一个服务留作前台主进程保证容器不退出,具体修改步骤如下:
1. 调整Dockerfile的不合理部分
删除你原来写在RUN阶段的MySQL启动、建库、设置密码的逻辑——这类初始化操作不应该在构建阶段执行,否则会把数据库初始状态固化在镜像层里,后续无法更新,还会导致镜像体积变大,且容器删除重建后所有数据库数据都会丢失。
2. 编写统一启动脚本
在项目目录下新建start.sh脚本,实现服务拉起+初始化的逻辑:
#!/bin/bash # 后台启动MySQL服务 /etc/init.d/mysql start # 等待MySQL完全就绪 sleep 5 # 仅在容器首次启动时执行数据库初始化,避免重复执行报错 if [ ! -f /var/lib/mysql/.init_flag ]; then mysql -u root -e "CREATE DATABASE IF NOT EXISTS eccube;" mysqladmin -u root password 'secret' # 打标记避免重复初始化 touch /var/lib/mysql/.init_flag fi # 以前台模式启动Apache,作为容器的主进程保证容器持续运行 apache2-foreground
3. 在Dockerfile中集成启动脚本
在你原有Dockerfile的末尾追加以下内容:
# 复制启动脚本到容器内部 COPY ./start.sh /start.sh # 给脚本添加可执行权限 RUN chmod +x /start.sh # 替换默认启动命令,用自定义脚本接管容器启动流程 CMD ["/start.sh"]
注意:脚本的执行顺序不能乱——必须把Apache作为最后一个以前台运行的进程。如果把Apache也放到后台,两个进程都在后台运行,前台没有持续存活的进程,容器启动后几秒就会自动退出。
更推荐的优化方向
长期来看更符合Docker设计原则的方案是拆分两个独立容器:
- 用基于
php:7.4-apache构建的镜像运行Web服务 - 用官方MySQL镜像单独运行数据库服务
两个容器通过Docker自定义网络连通,Web应用可以直接通过MySQL容器的服务名访问数据库。这种模式下两个服务可以独立重启、独立升级,还能方便地通过数据卷挂载实现数据库持久化,不会出现进程调度冲突的问题。
内容的提问来源于stack exchange,提问作者Camilo Urán
相关产品推荐
相关产品推荐

