Configure o contêiner Apache Docker para continuar em execução após executar o php shell CMD

Configure o contêiner Apache Docker para continuar em execução após executar o php shell CMD

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 CMDem execução, de acordo com a documentação. Mas como posso ter certeza de que o contêiner continuará funcionando; e que o init.phpscript 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.shcom 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 apache2ctlem vez de apache2fez 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-composeinicia 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 mariadbainda 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 dbcontainer esteja realmente totalmente inicializado. Isto novamente resulta no amado SQLSTATE[HY000] [2002] Connection refusederro. 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:3306está 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.phppara 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!

informação relacionada