【问题标题】:Docker, PHP PDO and the Single MySQL Container (cannot connect by container name)Docker、PHP PDO 和单个 MySQL 容器(无法通过容器名称连接)
【发布时间】:2019-04-12 11:47:52
【问题描述】:

我遇到了一个有趣的问题,docker run 命令和使用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:(USERPASS 是正确的,是的,我知道我不应该使用 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 failed: Name or service not known

如果我将连接字符串中的 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 容器的方法会产生不同的结果?有没有办法“规范化”这个,所以无论容器如何启动,按名称连接都可以工作?

【问题讨论】:

    标签: php docker docker-compose


    【解决方案1】:

    Docker 撰写automatically sets up a network for you:

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

    Docker 自行创建的默认桥接网络doesn't provide DNS,因此您不能使用它通过容器名称连接到容器。您可能想自己建立一个网络,例如与

    docker network create mynetwork
    

    然后connect your containers 给它,例如与

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

    注意this isn't the only difference 位于 Docker Compose 和手动运行的容器之间。

    【讨论】:

    • 默认桥接网络不应该处理这个吗?
    • @JayBlanchard,从技术上讲,默认网桥提供网络连接,但it doesn't provide DNS 所以你不能通过容器名称连接。我会更新我的答案。
    • 谢谢。这真的有点臭,因为你必须有一个额外的过程(我在我的社区里教其他人关于 Docker),但我完全理解为什么。它肯定比我们之前要做的所有事情都要好。
    • “它肯定比我们之前所做的一切都要好”——听,听!
    猜你喜欢
    • 2020-03-28
    • 2017-08-10
    • 2023-04-07
    • 2020-12-30
    • 2020-07-29
    • 2021-04-04
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多