我正在尝试运行基于以下内容的 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
以主机身份使用,我只能登录管理员仪表板。因此,这只是一个猜测,我现在仍然很想知道为什么这样做有效……?
但是,这仍然无法完全发挥作用。只有当我省略CMD
dockerfile 中的行、构建容器、通过 迁移到其终端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" ]
完成工作了!