
我正在嘗試運行基於以下內容的 Docker 容器:
- PHP 8.1
- 阿帕契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 init 完成之前沒有連接」部分)。因此,當您在尚未提取映像的電腦上啟動當前應用程式的容器時mariadb
,您很可能會嘗試執行init.php
,透過它嘗試連接到您的db
,而db
容器實際上並未完全初始化。這又導致了人們喜愛的SQLSTATE[HY000] [2002] Connection refused
錯誤。 Docker 本身提及這等待解決方案作為解決方法,這就是我使用它的原因。上面顯示的程式碼中它所做的就是:
- 最多 30 秒內檢查該位址是否
db:3306
可用。 - 如果在該時間內可用,則執行 後的所有內容
--
。 - 如果它在這段時間內不可用,請中斷執行(此時容器初始化將失敗)。
對於更嚴格的方法,您還可以在您的程式碼中編寫程式碼,init.php
如果連接失敗,則在等待 5 秒的間隔後重新嘗試連接到資料庫最多 x 次;這也能完成任務。
現在一切都正常運作了!