
Estoy intentando ejecutar un contenedor Docker basado en:
- PHP 8.1
- Apache 2.4
- MariaDB (última imagen oficial de Docker)
Archivo Docker:
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:
El script src/init.php simplemente se conecta a la base de datos y genera las tablas que la aplicación necesita, si aún no están presentes.
Mi problema ahora es que la ejecución del contenedor Docker siempre termina con la ejecución exitosa de /src/init.php
( php-apache exited with code 0
). Sé que esto es normal con Docker, ya que el contenedor solo persiste mientras se CMD
esté ejecutando, según los documentos. Pero, ¿cómo puedo asegurarme de que el contenedor siga funcionando? ¿Y que el init.php
script simplemente se inicia para garantizar que la aplicación tenga todo lo que necesita al iniciar el contenedor?
ACTUALIZAR
Intenté utilizarlo para configurar esto init.sh
con el siguiente contenido:
#!/bin/sh
php src/init.php
apache2 -D FOREGROUND
Luego reemplacé:
CMD [ "sh", "-c", "php src/init.php" ]
con
CMD ["sh", "-c", "/var/www/html/start.sh"]
Esto ejecuta con éxito el script PHP, pero no puede ejecutar el comando de Apache, diciendo:
[core:warn] [pid 10] AH00111: Config variable ${APACHE_RUN_DIR} is not defined
Entonces, ¿parece que la ejecución del Shell no puede acceder a las variables de Apache?
Respuesta1
Ok, ahora tengo una solución que funciona. En primer lugar, el motivo de:
[core:warn] [pid 10] AH00111: Config variable ${APACHE_RUN_DIR} is not defined
fue que usé la herramienta de comando incorrecta para ejecutar Apache en primer plano. usar apache2ctl
en lugar de apache2
hacer el trabajo (en apache2
, las variables de entorno de Apache parecían no estar disponibles).
A continuación, los contenidos finales de mi start.sh
son:
#!/bin/sh
wait-for-it.sh db:3306 --strict --timeout=30 -- php init.php && apache2ctl -D FOREGROUND
Ahora hay una cosa adicional que he agregado, como puedes ver. docker-compose
inicia contenedores simultáneamente (vereste, sección "No hay conexiones hasta que se complete el inicio de MariaDB"). Cuando inicia el contenedor de la presente aplicación en una máquina en la que mariadb
aún no se ha extraído la imagen, es muy probable que intente ejecutar init.php
, mediante el cual intenta conectarse a su db
, sin que su db
contenedor esté completamente inicializado. Esto nuevamente resulta en el querido SQLSTATE[HY000] [2002] Connection refused
error. Docker en símencionaelespéralosolución como solución alternativa, por eso la he usado. Todo lo que hace en el código que se muestra arriba es:
- compruebe durante un máximo de 30 segundos si la dirección
db:3306
está disponible. - si está disponible dentro de ese tiempo, ejecute todo después
--
. - si no está disponible dentro de ese tiempo, interrumpa la ejecución (que es cuando fallaría la inicialización de su contenedor).
Para un enfoque más estricto a esto, también puede codificar dentro de su init.php
para volver a intentar conectarse a su base de datos por un máximo de x veces después de esperar un intervalo de 5 segundos si la conexión falla; y eso también haría el trabajo.
¡Todo está funcionando completamente ahora!