如果通过 Dockerfile 的 CMD 连接(PHP CLI 有效),则在使用 mariadb 的 PHP Apache Docker 容器中获取 SQLSTATE[HY000] [2002] 连接被拒绝

如果通过 Dockerfile 的 CMD 连接(PHP CLI 有效),则在使用 mariadb 的 PHP Apache Docker 容器中获取 SQLSTATE[HY000] [2002] 连接被拒绝

我正在尝试运行基于以下内容的 Docker 容器:

  • PHP 8.1
  • Apache 2.4
  • MariaDB(最新官方 Docker 镜像)

一切都启动顺利;但我无法通过 PDO 连接到 Docker 容器的数据库。

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以主机身份使用,我只能登录管理员仪表板。因此,这只是一个猜测,我现在仍然很想知道为什么这样做有效……?

但是,这仍然无法完全发挥作用。只有当我省略CMDdockerfile 中的行、构建容器、通过 迁移到其终端docker exec -t -i php-apache /bin/bash并从其中运行命令时,它才有效php src/init.php。如果我尝试通过CMD表单执行此操作Dockerfile(如上所述),我会收到上述错误。我还缺少什么?我当然更愿意通过 Docker 容器的运行启动来自动化此 init 调用。进一步挖掘...

答案1

现在真的明白了。连接被拒绝,因为环境变量仅在脚本通过 shell 执行时使用,而通过 DockerCMD执行时(我使用它时)没有发生任何 shell 处理。从文档中,我还发现

与 shell 形式不同,exec 形式不会调用命令 shell。这意味着不会发生正常的 shell 处理。例如,CMD [“echo”,“$HOME”] 不会对 $HOME 进行变量替换。如果您想要 shell 处理,则可以使用 shell 形式或直接执行 shell,例如:CMD [“sh”,“-c”,“echo $HOME”]。当使用 exec 形式并直接执行 shell 时(如 shell 形式的情况),是 shell 而不是 docker 进行环境变量扩展。

当在shell或exec格式中使用时,CMD指令设置运行镜像时要执行的命令。

如果你使用CMD的shell形式,那么将在/bin/sh -c中执行

使用:

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

代替:

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

完成工作了!

相关内容