Obteniendo un SQLSTATE[HY000] [2002] Conexión rechazada en el contenedor PHP Apache Docker usando mariadb, si está conectado a través del CMD de Dockerfile (PHP CLI funciona)

Obteniendo un SQLSTATE[HY000] [2002] Conexión rechazada en el contenedor PHP Apache Docker usando mariadb, si está conectado a través del CMD de Dockerfile (PHP CLI funciona)

Estoy intentando ejecutar un contenedor Docker basado en:

  • PHP 8.1
  • Apache 2.4
  • MariaDB (última imagen oficial de Docker)

Todo arranca sin ningún problema; pero no puedo conectarme con la base de datos del contenedor Docker a través de PDO.

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 ["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:

Según la mayoría de las publicaciones y respuestas de diferentes foros, he intentado usar tanto localhostcomo 127.0.0.1el valor de la variable de entorno MARIADB_HOST(y además, me interesa saber por qué debería funcionar). De todos modos no soluciona el problema, el siguiente código php (contenido de src/init.php):

new PDO(
    "mysql:host={$_ENV['MARIADB_HOST']};dbname={$_ENV['MARIADB_DB']}",
    $_ENV['MARIADB_USER'],
    $_ENV['MARIADB_PASSWORD'],
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]
);

Siempre resulta en:

SQLSTATE[HY000] [2002] Connection refused.

ACTUALIZAR

Llegué un paso más allá reemplazando esta línea aquí:

MARIADB_HOST: "127.0.0.1"

con el nombre de mi servicio de base de datos; ser:

MARIADB_HOST: db

Descubrí esto porque descubrí al mismo tiempo que solo puedo iniciar sesión en el panel de administración si lo uso dbcomo anfitrión. Por lo tanto, esto fue más bien una suposición, y todavía me encantaría entender por qué funciona ahora.

Sin embargo, esto todavía no funciona del todo. Solo funciona si omito la CMDlínea en el dockerfile, construyo el contenedor, migro a su terminal a través de docker exec -t -i php-apache /bin/bashy ejecuto el comando php src/init.phpdesde allí. Si intento hacerlo a través CMDdel formulario Dockerfile(como se detalla anteriormente), aparece el error mencionado. ¿Qué me falta todavía? Por supuesto, preferiría automatizar esta llamada de inicio con el inicio del contenedor Docker. Profundizando más...

Respuesta1

Lo tengo de verdad ahora. La conexión fue rechazada porque las variables de entorno solo se usaban si el script se ejecuta a través del shell, y a través de Docker, CMDcomo lo usé, no se produjo ningún procesamiento del shell. De los documentos, también encontréeste:

A diferencia del formulario de shell, el formulario exec no invoca un shell de comandos. Esto significa que no se produce el procesamiento normal del shell. Por ejemplo, CMD [ "echo", "$HOME" ] no sustituirá variables en $HOME. Si desea procesar el shell, utilice el formulario del shell o ejecute un shell directamente, por ejemplo: CMD [ "sh", "-c", "echo $HOME" ]. Cuando se utiliza el formulario exec y se ejecuta un shell directamente, como en el caso del formulario shell, es el shell el que realiza la expansión de la variable de entorno, no la ventana acoplable.

Cuando se usa en los formatos shell o exec, la instrucción CMD establece el comando que se ejecutará al ejecutar la imagen.

Si usa la forma shell del CMD, entonces se ejecutará en /bin/sh -c

Usando:

CMD [ "sh", "-c", "php src/init.php" ]

en lugar de:

CMD [ "php", "src/init.php" ]

¡Hizo el trabajo!

información relacionada