
Estou tentando executar um contêiner Docker baseado em:
- PHP 8.1
- Apache 2.4
- MariaDB (imagem oficial mais recente do docker)
Arquivo 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:
O script src/init.php simplesmente se conecta ao banco de dados e gera as tabelas que a aplicação precisa, caso ainda não estejam presentes.
Meu problema agora é que a execução do contêiner Docker sempre termina com a execução bem-sucedida de /src/init.php
( php-apache exited with code 0
). Eu sei que isso é normal com o Docker, pois o contêiner só persiste enquanto estiver CMD
em execução, de acordo com a documentação. Mas como posso ter certeza de que o contêiner continuará funcionando; e que o init.php
script seja simplesmente lançado para garantir que a aplicação tenha tudo o que precisa, na inicialização do container?
ATUALIZAR
Eu tentei usar para configurar isso init.sh
com o seguinte conteúdo:
#!/bin/sh
php src/init.php
apache2 -D FOREGROUND
Então eu substituí:
CMD [ "sh", "-c", "php src/init.php" ]
com
CMD ["sh", "-c", "/var/www/html/start.sh"]
Isso executa com sucesso o script PHP, mas falha ao executar o comando Apache, dizendo:
[core:warn] [pid 10] AH00111: Config variable ${APACHE_RUN_DIR} is not defined
Então parece que as variáveis do Apache não são acessíveis pela execução do shell?
Responder1
Ok, tenho uma solução funcional agora. Em primeiro lugar, o motivo:
[core:warn] [pid 10] AH00111: Config variable ${APACHE_RUN_DIR} is not defined
foi que usei a ferramenta de comando errada para executar o Apache em primeiro plano. using apache2ctl
em vez de apache2
fez o trabalho (no apache2
, as variáveis de ambiente do Apache pareciam estar indisponíveis).
A seguir, o conteúdo final do meu start.sh
é:
#!/bin/sh
wait-for-it.sh db:3306 --strict --timeout=30 -- php init.php && apache2ctl -D FOREGROUND
Agora, há uma coisa adicional que adicionei, como você pode ver. docker-compose
inicia contêineres simultaneamente (vejaesse, seção "Sem conexões até que a inicialização do MariaDB seja concluída"). Ao iniciar assim o container da presente aplicação em uma máquina que mariadb
ainda não teve a imagem extraída, é muito provável que você tente executar o init.php
, pelo qual você tenta se conectar ao seu db
, sem que o seu db
container esteja realmente totalmente inicializado. Isto novamente resulta no amado SQLSTATE[HY000] [2002] Connection refused
erro. O próprio Dockermencionaoespere por issosolução como solução alternativa, e é por isso que a usei. Tudo o que faz no código mostrado acima é:
- verifique durante no máximo 30 segundos se o endereço
db:3306
está disponível. - se estiver disponível dentro desse prazo, execute tudo depois
--
. - se não estiver disponível nesse período, interrompa a execução (que é quando a inicialização do contêiner falharia).
Para uma abordagem mais rigorosa para isso, você também pode codificar dentro de seu init.php
para tentar novamente se conectar ao seu banco de dados por no máximo x vezes depois de esperar por um intervalo de 5s se a conexão falhar; e isso também faria o trabalho.
Tudo está funcionando perfeitamente agora!