
Я пытаюсь запустить 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 недоступны при выполнении оболочки?
решение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
вашего контейнера. Это снова приводит к любимой ошибке. Сам Dockerdb
SQLSTATE[HY000] [2002] Connection refused
упоминает the ждать егорешение как обходной путь, поэтому я его и использовал. Все, что он делает в коде, показанном выше, это:
db:3306
проверьте в течение максимум 30 секунд , доступен ли адрес .- если он станет доступен в течение этого времени, выполните все, что последует
--
. - если он не станет доступен в течение этого времени, прервите выполнение (в этом случае инициализация вашего контейнера завершится неудачей).
Для более строгого подхода вы также можете закодировать в своем коде init.php
повторную попытку подключения к вашей базе данных максимум x раз после ожидания в течение 5 секунд в случае сбоя соединения; и это тоже сработает.
Теперь все полностью работает!