Получение SQLSTATE[HY000] [2002] Отказано в подключении в контейнере PHP Apache Docker с использованием mariadb, если подключено через CMD Dockerfile (PHP CLI работает)

Получение SQLSTATE[HY000] [2002] Отказано в подключении в контейнере PHP Apache Docker с использованием mariadb, если подключено через CMD Dockerfile (PHP CLI работает)

Я пытаюсь запустить Docker-контейнер на основе:

  • PHP 8.1
  • Апач 2.4
  • MariaDB (последний официальный образ Docker)

Все запускается без проблем, но я не могу подключиться к базе данных Docker-контейнера через PDO.

Dockerfile:

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:

Согласно большинству сообщений и ответов с разных форумов, я пытался использовать и то, и другое, localhostа также 127.0.0.1значение переменной окружения MARIADB_HOST(и, кроме того, мне интересно узнать, почему это должно работать?). В любом случае, это не решает проблему, следующий php-код (содержимое 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
    ]
);

Всегда приводит к:

SQLSTATE[HY000] [2002] Connection refused.

ОБНОВЛЯТЬ

Я пошел еще дальше, заменив вот эту строку:

MARIADB_HOST: "127.0.0.1"

с именем моей службы базы данных; это:

MARIADB_HOST: db

Я узнал об этом, потому что в то же время узнал, что могу войти в панель администратора, только если использую ее dbкак хост. Поэтому это было скорее предположение, и мне все еще хотелось бы понять, почему это работает сейчас..?

Однако это все еще не полностью работает. Это работает только если я опускаю строку CMDв dockerfile, собираю контейнер, мигрирую в его терминал через docker exec -t -i php-apache /bin/bashи запускаю команду php src/init.phpоттуда. Если я пытаюсь сделать это через CMDформу Dockerfile(как описано выше), я получаю указанную ошибку. Что я еще упускаю? Я бы, конечно, предпочел автоматизировать этот вызов init с помощью запуска контейнера Docker. Копаем дальше...

решение1

Теперь понял по-настоящему. Соединение было отклонено, потому что переменные окружения использовались только если скрипт выполнялся через оболочку, а через Docker's CMD- когда я его использовал - никакой обработки оболочки не происходило. Из документации я также нашелэтот:

В отличие от формы shell, форма exec не вызывает командную оболочку. Это означает, что обычная обработка оболочки не происходит. Например, CMD [ "echo", "$HOME" ] не будет выполнять подстановку переменных в $HOME. Если вам нужна обработка оболочки, то либо используйте форму shell, либо выполните оболочку напрямую, например: CMD [ "sh", "-c", "echo $HOME" ]. При использовании формы exec и запуске оболочки напрямую, как в случае с формой shell, расширением переменных среды занимается оболочка, а не docker.

При использовании в форматах shell или exec инструкция CMD задает команду, которая будет выполнена при запуске образа.

Если вы используете оболочку CMD, то она будет выполнена в /bin/sh -c

С использованием:

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

вместо:

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

Сделал работу!

Связанный контент