首页 > 解决方案 > Docker、PHP PDO 和单个 MySQL 容器(无法通过容器名称连接)

问题描述

docker run我遇到了一个有趣的问题,其中command 和 using之间似乎存在差异docker-compose

我有两个 Docker 容器,一个是带有 PHP 的 Apache 网站,另一个是 MySQL。我使用以下命令来运行容器:

网站:

docker run -p 8080:80 -d website_local

MySQL:

docker run -e MYSQL_ROOT_PASSWORD=RamaLamaDingDong --name=mysql5725 -d mysql:5.7.25

查看 Docker 生态系统,我可以看到它们都在运行:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
849c421e750b        website_local       "/usr/sbin/apache2ct…"   19 minutes ago      Up 19 minutes       0.0.0.0:8080->80/tcp   pedantic_tesla
ccebba95693b        mysql:5.7.25        "docker-entrypoint.s…"   23 minutes ago      Up 23 minutes       3306/tcp, 33060/tcp    mysql5725

我已经使用 MySQL Docker 容器的名称设置了到数据库的 PDO 连接:

PHP:(USERandPASS是正确的,是的,我知道我不应该使用 root 的凭据)

try {
        $dbh = new PDO('mysql:host=mysql5725;dbname=grocery;charset=utf8', USER, PASS);
        $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }
    catch(PDOException $e) {
        echo $e->getMessage();
        $errorCode = $e->getCode();
    }

尝试连接数据库时出现以下错误:

SQLSTATE [HY000] [2002] php_network_getaddresses:getaddrinfo 失败:名称或服务未知

如果我用host容器的 Docker IP 地址 (172.17.0.3) 替换连接字符串,它将正确连接。

现在它变得有趣了。如果我使用 Docker Compose 启动容器:

version: '3'

services:
  db:
    image: mysql:5.7.25
    container_name: mysql5725
    environment:
      MYSQL_ROOT_PASSWORD: RamaLamaDingDong
    ports:
      - "3306:3306"

  web:
    image: website_local:latest
    container_name: website_local
    depends_on:
      - db
    volumes:
      - ./website/www:/var/www/html/
    ports:
      - "8080:80"

PHP 函数使用 Docker 容器的名称(mysql5725)正确连接,但无法使用 Docker 容器的 IP 地址连接。

很多时候在测试环境中我只想停止和重建某些容器,尤其是在处理两个以上的 Docker 镜像时。我应该只在建立连接时使用资源的名称,因为不能保证网络每次都会为容器分配相同的 IP 地址。

为什么这两种启动 Docker 容器的方法会产生不同的结果?有没有办法“规范化”这个,所以无论容器如何启动,按名称连接都会起作用?

标签: phpdockerdocker-compose

解决方案


Docker Compose会自动为您设置网络

默认情况下,Compose 会为您的应用程序设置一个网络。服务的每个容器都加入默认网络,并且可以被该网络上的其他容器访问,并且可以通过与容器名称相同的主机名被它们发现

Docker 自己创建的默认桥接网络不提供 DNS,因此您不能使用它来使用名称连接到容器。您可能想自己建立一个网络,例如

docker network create mynetwork

然后将您的容器连接到它,例如

docker network connect mynetwork mysql5725
docker network connect mynetwork php-container

请注意,这不是Docker Compose 和手动运行容器之间的唯一区别。


推荐阅读