取得 SQLSTATE[HY000] [2002] 如果透過 Dockerfile 的 CMD 連線(PHP CLI 有效),則使用 mariadb 在 PHP Apache Docker 容器中連線被拒絕

取得 SQLSTATE[HY000] [2002] 如果透過 Dockerfile 的 CMD 連線(PHP CLI 有效),則使用 mariadb 在 PHP Apache Docker 容器中連線被拒絕

我正在嘗試運行基於以下內容的 Docker 容器:

  • PHP 8.1
  • 阿帕契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 執行時才使用環境變量,並且透過 Docker 執行CMD(正如我使用的那樣),不會發生 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" ]

完成任務了!

相關內容