简体   繁体   English

Docker,PHP PDO和单个MySQL容器(无法通过容器名称连接)

[英]Docker, PHP PDO and the Single MySQL Container (cannot connect by container name)

I've run into an interesting issue where there seems to be a difference between the docker run command and using docker-compose . 我遇到了一个有趣的问题,其中docker run命令和使用docker-compose之间似乎有所不同。

I have two Docker containers, one is an Apache website with PHP, the other a MySQL. 我有两个Docker容器,一个是带有PHP的Apache网站,另一个是MySQL。 I use the following commands to run the containers: 我使用以下命令来运行容器:

Website: 网站:

docker run -p 8080:80 -d website_local

MySQL: MySQL的:

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

Looking at the Docker ecosystem I can see them both running: 查看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

I have setup a PDO connection to the database, using the name for the MySQL Docker container: 我已经使用MySQL Docker容器的名称建立了到数据库的PDO连接:

PHP: (the USER and PASS are correct and yes, I know I shouldn't use the root's credentials) PHP:( USERPASS是正确的,是的,我知道我不应该使用根的凭据)

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();
    }

When attempting to connect to the database I get the following error: 尝试连接到数据库时,出现以下错误:

SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known SQLSTATE [HY000] [2002] php_network_getaddresses:getaddrinfo失败:名称或服务未知

If I replace host in the connections string with the Docker IP address (172.17.0.3) of the container it connects properly. 如果将连接字符串中的host替换为容器的Docker IP地址(172.17.0.3),它将正确连接。

Now it gets interesting. 现在变得有趣了。 If I bring up the containers using Docker Compose: 如果我使用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"

The PHP function connects correctly using the name of the Docker container ( mysql5725 ), but cannot connect using the IP address of the Docker container. PHP函数使用Docker容器的名称( mysql5725 )正确连接,但无法使用Docker容器的IP地址连接。

Many times in a testing environment I only want to stop and rebuild certain containers, especially when dealing with more than two Docker images. 在测试环境中,很多时候我只想停止并重建某些容器,尤其是在处理两个以上的Docker映像时。 I should only have to use the resource's name when making a connection because there is no guarantee the network will assign the same IP addresses to containers every time. 建立连接时,我只需要使用资源的名称,因为不能保证网络每次都会为容器分配相同的IP地址。

Why should these two methods of launching Docker containers produce different results? 为什么这两种启动Docker容器的方法会产生不同的结果? Is there a way to 'normalize' this, so connecting by name will work no matter how the container is launched? 有没有一种方法可以对此进行“规范化”,因此无论容器如何启动,通过名称进行连接都将有效?

Docker Compose automatically sets up a network for you : Docker Compose会自动为您建立一个网络

By default Compose sets up a single network for your app. 默认情况下,Compose为您的应用设置单个网络 Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name. 为服务每个容器加入默认网络既是由网络上的其他集装箱到达 ,并在相同的容器名称主机名被他们发现

The default bridge network that Docker creates on its own doesn't provide DNS so you can't use it to connect to containers using their names. Docker自己创建的默认网桥网络不提供DNS,因此您不能使用它来使用其名称连接到容器。 You'll probably want to set up a network yourself, eg with 您可能需要自己建立一个网络,例如

docker network create mynetwork

and then connect your containers to it, eg with 然后将您的容器连接到它,例如

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

Note that this isn't the only difference between Docker Compose and manually running containers. 请注意, 这并不是 Docker Compose与手动运行容器之间的唯一区别

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM