我正在尝试运行基于以下内容的 Docker 容器:
- PHP 8.1
- Apache 2.4
- MariaDB(最新官方 Docker 镜像)
Dockerfile:
FROM php:8.1-apache
WORKDIR /var/www/html/
RUN pecl install xdebug \
&& apt update \
&& apt install libzip-dev -y \
&& docker-php-ext-enable xdebug \
&& a2enmod rewrite \
&& docker-php-ext-install zip \
&& rm -rf /var/lib/apt/lists/* \
&& docker-php-ext-install pdo pdo_mysql
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY composer.json .
RUN groupadd -r user && useradd -r -g user user
USER user
RUN composer install --no-dev
COPY . .
EXPOSE 80
CMD [ "sh", "-c", "php src/init.php" ]
docker-compose.yml:
services:
php:
build: ./php
depends_on:
- db
- adminer
container_name: php-apache
ports:
- 80:80
volumes:
# setup xdebug to be able to use PHP step debugger, if needed
- ./php/conf.d/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
- ./php/conf.d/error_reporting.ini:/usr/local/etc/php/conf.d/error_reporting.ini
# apache config (server name)
- ./apache/apache2.conf:/etc/apache2/apache2.conf
# apache config (rewrite rule to reroute all requests to unknown resources through to REST controller)
- ./apache/000-default.conf:/etc/apache2/sites-enabled/000-default.conf
# Source code
- ./php/src:/var/www/html/src
# unbind local composer components
- /php/vendor
- /php/composer.lock
- /php/composer.phar
environment:
MARIADB_HOST: "127.0.0.1"
MARIADB_USER: root
MARIADB_PASSWORD: top_very_secret
MARIADB_DB: apidb
adminer:
image: adminer
depends_on:
- db
restart: always
ports:
- 8080:8080
db:
image: mariadb
container_name: db
volumes:
- maria-db-storage:/var/lib/mysql
environment:
MARIADB_ROOT_PASSWORD: top_very_secret
MARIADB_DATABASE: apidb
ports:
- 3306:3306
volumes:
maria-db-storage:
脚本 src/init.php 只是连接到数据库并生成应用程序所需的表(如果尚不存在)。
我现在的问题是 Docker 容器的执行总是在/src/init.php
( php-apache exited with code 0
) 成功执行后终止。我知道这对于 Docker 来说是正常的,因为根据文档,容器只有在运行时才会持续存在CMD
。但我如何确保容器继续运行;并且只需init.php
启动脚本即可确保应用程序在启动容器时拥有所需的一切?
更新
init.sh
我尝试使用以下内容进行设置:
#!/bin/sh
php src/init.php
apache2 -D FOREGROUND
然后我替换了:
CMD [ "sh", "-c", "php src/init.php" ]
和
CMD ["sh", "-c", "/var/www/html/start.sh"]
这成功执行了 PHP 脚本,但无法执行 apache 命令,并显示:
[core:warn] [pid 10] AH00111: Config variable ${APACHE_RUN_DIR} is not defined
所以看起来 apache 的变量不能被 shell 执行访问??
答案1
好的,现在有一个可行的解决方案。首先,原因是:
[core:warn] [pid 10] AH00111: Config variable ${APACHE_RUN_DIR} is not defined
是我使用了错误的命令工具在前台运行 apache。使用apache2ctl
而不是apache2
完成了工作(在 中apache2
,apache 的环境变量似乎不可用)。
接下来我的最终内容start.sh
是:
#!/bin/sh
wait-for-it.sh db:3306 --strict --timeout=30 -- php init.php && apache2ctl -D FOREGROUND
现在我又添加了一个新东西,如你所见。docker-compose
同时启动容器(参见这,部分“在 MariaDB 初始化完成之前无连接”)。因此,当您在尚未提取映像的机器上启动当前应用程序的容器时mariadb
,您很可能会尝试执行init.php
,通过该操作尝试连接到您的db
,而您的db
容器实际上尚未完全初始化。这再次导致心爱的SQLSTATE[HY000] [2002] Connection refused
错误。Docker 本身提及这等待解决方案作为一种解决方法,这就是我使用它的原因。上面显示的代码中它所做的只是:
- 检查最多 30 秒内该地址是否
db:3306
可用。 - 如果它在该时间内可用,则执行之后的所有操作
--
。 - 如果它在该时间内没有可用,则中断执行(此时容器初始化将失败)。
为了采取更严格的方法,init.php
如果连接失败,您还可以在内部编写代码,在等待 5 秒的间隔后重新尝试连接数据库最多 x 次;这样也可以完成工作。
现在一切都正常运转了!