![Получение SQLSTATE[HY000] [2002] Отказано в подключении в контейнере PHP Apache Docker с использованием mariadb, если подключено через CMD Dockerfile (PHP CLI работает)](https://rvso.com/image/781990/%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20SQLSTATE%5BHY000%5D%20%5B2002%5D%20%D0%9E%D1%82%D0%BA%D0%B0%D0%B7%D0%B0%D0%BD%D0%BE%20%D0%B2%20%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B8%20%D0%B2%20%D0%BA%D0%BE%D0%BD%D1%82%D0%B5%D0%B9%D0%BD%D0%B5%D1%80%D0%B5%20PHP%20Apache%20Docker%20%D1%81%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC%20mariadb%2C%20%D0%B5%D1%81%D0%BB%D0%B8%20%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%BE%20%D1%87%D0%B5%D1%80%D0%B5%D0%B7%20CMD%20Dockerfile%20(PHP%20CLI%20%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82).png)
Я пытаюсь запустить 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" ]
Сделал работу!