![取得 SQLSTATE[HY000] [2002] 如果透過 Dockerfile 的 CMD 連線(PHP CLI 有效),則使用 mariadb 在 PHP Apache Docker 容器中連線被拒絕](https://rvso.com/image/781990/%E5%8F%96%E5%BE%97%20SQLSTATE%5BHY000%5D%20%5B2002%5D%20%E5%A6%82%E6%9E%9C%E9%80%8F%E9%81%8E%20Dockerfile%20%E7%9A%84%20CMD%20%E9%80%A3%E7%B7%9A%EF%BC%88PHP%20CLI%20%E6%9C%89%E6%95%88%EF%BC%89%EF%BC%8C%E5%89%87%E4%BD%BF%E7%94%A8%20mariadb%20%E5%9C%A8%20PHP%20Apache%20Docker%20%E5%AE%B9%E5%99%A8%E4%B8%AD%E9%80%A3%E7%B7%9A%E8%A2%AB%E6%8B%92%E7%B5%95.png)
我正在嘗試運行基於以下內容的 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
作為主機使用,我只能登入管理員儀表板。因此,這只是一個猜測,我仍然很想了解為什麼現在會起作用......?
然而,這仍然沒有完全發揮作用。只有當我省略CMD
dockerfile 中的行、建置容器、通過 遷移到其終端並從那裡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" ]
完成任務了!