Настройте контейнер Apache Docker для продолжения работы после выполнения php shell CMD

Настройте контейнер Apache Docker для продолжения работы после выполнения php shell CMD

Я пытаюсь запустить 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вашего контейнера. Это снова приводит к любимой ошибке. Сам DockerdbSQLSTATE[HY000] [2002] Connection refusedупоминает the ждать егорешение как обходной путь, поэтому я его и использовал. Все, что он делает в коде, показанном выше, это:

  • db:3306проверьте в течение максимум 30 секунд , доступен ли адрес .
  • если он станет доступен в течение этого времени, выполните все, что последует --.
  • если он не станет доступен в течение этого времени, прервите выполнение (в этом случае инициализация вашего контейнера завершится неудачей).

Для более строгого подхода вы также можете закодировать в своем коде init.phpповторную попытку подключения к вашей базе данных максимум x раз после ожидания в течение 5 секунд в случае сбоя соединения; и это тоже сработает.

Теперь все полностью работает!

Связанный контент