
Ich versuche, einen Docker-Container auszuführen, basierend auf:
- PHP 8.1
- Apache 2.4
- MariaDB (neuestes offizielles Docker-Image)
Docker-Datei:
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:
Das Skript src/init.php stellt einfach eine Verbindung zur Datenbank her und generiert die Tabellen, die die Anwendung benötigt, sofern sie nicht bereits vorhanden sind.
Mein Problem ist nun, dass die Ausführung des Docker-Containers immer mit der erfolgreichen Ausführung von /src/init.php
( php-apache exited with code 0
) beendet wird. Ich weiß, dass das bei Docker normal ist, da der Container CMD
laut Dokumentation nur so lange besteht, wie der ausgeführt wird. Aber wie kann ich sicherstellen, dass der Container weiter ausgeführt wird und dass das init.php
Skript einfach gestartet wird, um sicherzustellen, dass die Anwendung beim Start des Containers über alles verfügt, was sie benötigt?
AKTUALISIEREN
init.sh
Ich habe versucht, dies mit dem folgenden Inhalt einzurichten :
#!/bin/sh
php src/init.php
apache2 -D FOREGROUND
Dann habe ich ersetzt:
CMD [ "sh", "-c", "php src/init.php" ]
mit
CMD ["sh", "-c", "/var/www/html/start.sh"]
Dadurch wird das PHP-Skript erfolgreich ausgeführt, der Apache-Befehl schlägt jedoch fehl, und es wird folgende Meldung angezeigt:
[core:warn] [pid 10] AH00111: Config variable ${APACHE_RUN_DIR} is not defined
Es scheint also, dass auf die Variablen von Apache durch die Shell-Ausführung nicht zugegriffen werden kann??
Antwort1
Ok, ich habe jetzt eine funktionierende Lösung. Zunächst einmal der Grund dafür:
[core:warn] [pid 10] AH00111: Config variable ${APACHE_RUN_DIR} is not defined
lag daran, dass ich das falsche Befehlstool verwendet habe, um Apache im Vordergrund auszuführen. Die Verwendung apache2ctl
von anstelle von apache2
hat funktioniert (in apache2
schienen die Umgebungsvariablen von Apache nicht verfügbar zu sein).
Als nächstes sind die endgültigen Inhalte von mir start.sh
:
#!/bin/sh
wait-for-it.sh db:3306 --strict --timeout=30 -- php init.php && apache2ctl -D FOREGROUND
Wie Sie sehen, habe ich noch eine weitere Funktion hinzugefügt. docker-compose
startet Container gleichzeitig (sieheDas, Abschnitt „Keine Verbindungen, bis MariaDB-Init abgeschlossen ist“). Wenn Sie also den Container der vorliegenden Anwendung auf einer Maschine starten, auf der das mariadb
Image noch nicht heruntergeladen wurde, ist es sehr wahrscheinlich, dass Sie versuchen, auszuführen init.php
, wodurch Sie versuchen, eine Verbindung zu Ihrem herzustellen db
, ohne dass Ihr db
Container tatsächlich vollständig initialisiert ist. Dies führt erneut zu dem beliebten SQLSTATE[HY000] [2002] Connection refused
Fehler. Docker selbstErwähnungenDiewarte daraufLösung als Workaround, weshalb ich sie verwendet habe. Im oben gezeigten Code macht sie nur Folgendes:
- Prüfen Sie maximal 30 Sekunden lang, ob die Adresse
db:3306
verfügbar ist. - Wenn es innerhalb dieser Zeit verfügbar wird, führen Sie alles danach aus
--
. - wenn es innerhalb dieser Zeit nicht verfügbar ist, unterbrechen Sie die Ausführung (in diesem Fall würde die Initialisierung Ihres Containers fehlschlagen).
Für einen strengeren Ansatz könnten Sie in Ihrem Code auch festlegen, dass init.php
bei einem Verbindungsfehler nach einer Wartezeit von 5 Sekunden maximal x-mal erneut versucht wird, eine Verbindung zu Ihrer Datenbank herzustellen. Auch das würde funktionieren.
Jetzt funktioniert alles voll!