【问题标题】:ReactPHP and docker: could not resolve hosts from php to nginx containerReactPHP 和 docker:无法将主机从 php 解析到 nginx 容器
【发布时间】:2018-02-13 16:30:56
【问题描述】:

我使用 docker 和微服务。假设我们有 3 个服务:

          user API
        /
gateway API
        \
          hotel API

请求通过网关到达服务。我有phpnginx 的容器,其中的容量是相同的。接下来我给出配置列表:

server {
    server_name gateway.api.loc;

    root /var/www/der-ibe/ibe-gateway-api/web;
    client_max_body_size 32m;

    location / {
        try_files $uri @rewriteapp;
    }

    location @rewriteapp {
        rewrite ^(.*)$ /app.php/$1 last;
    }

    location ~ ^/(app|app_dev|config)\.php(/|$) {
       ...
    }
}
server {
    server_name hotel.api.loc;
    root /var/www/der-ibe/ibe-hotel-api/web;
    client_max_body_size 32m;

    location / {
        try_files $uri @rewriteapp;
    }

    location @rewriteapp {
        rewrite ^(.*)$ /app.php/$1 last;
    }

    location ~ ^/(app|app_dev|config)\.php(/|$) {
        ...
    }
}

...

docker-compose.yml

version: "3.1" 
services:

    tphp:
        build: docker/php
        restart: always
        container_name: my_tphp
        extra_hosts:
            - gateway.api.loc:172.14.10.10
            - user.api.loc:172.14.10.10
            - hotel.api.loc:172.14.10.10
        networks:
            - test
        volumes:
            - ../user-api:/var/www/user-api
            - ../hotel-api:/var/www/hotel-api
            - ./:/var/www/gateway-api

    tnginx:
        build: docker/nginx
        restart: always
        container_name: my_tnginx
        ports:
            - 80:80
        networks:
            test:
                 ipv4_address: 172.14.10.10
        volumes:
            - ../user-api:/var/www/user-api
            - ../hotel-api:/var/www/hotel-api
            - ./:/var/www/gateway-api

networks:
    ibe:
      driver: bridge
      ipam:
        driver: default
        config:
          - subnet: 172.14.10.0/24

如果我使用简单的 cURL,我可以访问酒店和用户 api,我可以从他们那里得到响应,但是如果我尝试使用 reactPHP 来做 - 我做不到!我的代码和平:

 public function asyncGetRequest(Route $route, $params, $token)
{
    $url = $this->buildURL($route, $params);

    $loop = React\EventLoop\Factory::create();

    $dns = '172.14.10.10';
    $sender = Clue\React\Buzz\Io\Sender::createFromLoopDns($loop, $dns);

    //$url = 'http://172.14.10.10:3000/api/quota/list';

    $client = new Clue\React\Buzz\Browser($loop, $sender);
    //$client = new Clue\React\Buzz\Browser($loop);

    $promise = $client->get($url,
        [
            'Authorization' => $token,
        ]
    );

    /** @var Response $response */
    $response = new Response();

    try {
        $response = Clue\React\Block\await($promise, $loop);
    } catch (ResponseException $e) {
        $this->logger->error($e->getMessage());
    }

    dump($response->getBody()->getContents()); // I work on symfony 3.2
    die;
}

线索库只是react 的包装器。所以我得到的错误是: DNS query for hotel.api.loc timed out 和最后一个错误An error occurred in the underlying stream

所以我有一个问题:我做错了什么?为什么我可以通过 curl 访问 nginx 容器,但无法通过 reactPHP 访问?就算点dns!

但是,如果我使用带有端口的裸 ip,我可以访问它。我不是 dns 专业人士,只是基础知识。

更新

我使用 Linux Debian(在容器中)。在 Mac 上工作。

关于逻辑:当请求 URI 是 gateway.api.loc/api/hotel/list 在网关内部时,我们将请求发送到 hotel.api.loc 到相同的 URL(/api/hotel/list),接受响应并返回它。

我再说一遍,我可以通过 cURL 访问域,但无法使用 reactPHP 访问,并且不明白为什么...

【问题讨论】:

  • 您使用的是什么操作系统?请在您的问题中更新
  • 我找到了不使用任何 dns 的解决方案,直接请求即可。我请求带有标题'Host' => 'user.api.loc'http://172.14.10.10/api/doc 并且它有效。但如果你告诉我为什么我不能在gateway 内直接请求user.api.loc/api/doc,我将非常感谢
  • 太好了,谢谢分享

标签: php docker nginx dns reactphp


【解决方案1】:

您的问题是 gateway.api.lochotel.api.loc 没有 DNS 解析,它们在您的 Nginx 配置中定义用于路由,但在其他任何地方都没有用于 DNS 解析。您需要将您的撰写更改为以下内容,以便它们也可以在 docker DNS 解析中得到解决

version: "3.1" 
services:

    tphp:
        build: docker/php
        restart: always
        container_name: my_tphp
        extra_hosts:
            - gateway.api.ibe.lazy-ants.loc:172.14.10.10
            - user.api.ibe.lazy-ants.loc:172.14.10.10
            - hotel.api.ibe.lazy-ants.loc:172.14.10.10
        networks:
            - test
        volumes:
            - ../user-api:/var/www/user-api
            - ../hotel-api:/var/www/hotel-api
            - ./:/var/www/gateway-api

    tnginx:
        build: docker/nginx
        restart: always
        container_name: my_tnginx
        ports:
            - 80:80
        networks:
            test:
                 ipv4_address: 172.14.10.10
                 aliases:
                     - hotel.api.loc
                     - gateway.api.loc
        volumes:
            - ../user-api:/var/www/user-api
            - ../hotel-api:/var/www/hotel-api
            - ./:/var/www/gateway-api

networks:
    ibe:
      driver: bridge
      ipam:
        driver: default
        config:
          - subnet: 172.14.10.0/24

此 DNS 解析仅适用于撰写内部而不是外部。因此,如果您在外面使用它,那么您将不得不进行主机条目

Edit-1

看来您的问题可能只是代码。当网关 IP 不是 DNS 服务器时,您正尝试使用网关 IP 作为 DNS。

改变

$loop = React\EventLoop\Factory::create();

$dns = '172.14.10.10';
$sender = Clue\React\Buzz\Io\Sender::createFromLoopDns($loop, $dns);

//$url = 'http://172.14.10.10:3000/api/quota/list';

$client = new Clue\React\Buzz\Browser($loop, $sender);

$loop = React\EventLoop\Factory::create();

$dns = '172.14.10.10';
//$sender = Clue\React\Buzz\Io\Sender::createFromLoopDns($loop, $dns);
//$url = 'http://172.14.10.10:3000/api/quota/list';

$client = new Clue\React\Buzz\Browser($loop);

看看有没有帮助

【讨论】:

  • 坏消息:不要为我工作,而且我认为不仅对我有用。 Aliases 只是容器名称的别名,而不是主机名的别名。
  • 别名用于使用 DNS 而不是主机名的 IP 解析。请让我明白为什么它不起作用?你在哪里运行 PHP 代码,你得到了什么确切的错误?
  • 正如我在示例中展示的那样。该方法在控件上,来自服务的方法并从中调用。错误是:[1/4] TimeoutException: Timed out after 5 seconds +, [2/4] TimeoutException: DNS query for user.api.ibe.lazy-ants.net timed out [3/4] RuntimeException: DNS query for user.api.ibe.lazy-ants.net failed: too many retries [4/4] RuntimeException: An error occurred in the underlying stream(我编辑 docker-compose.yml,请你也修复它;谢谢)
  • 我忘了说当我请求gateway.api.loc/api/user/list网关转换它并且请求变成user.api.loc/api/user/list并且它由用户api请求gateway项目中的reactPHP。
  • 现在有问题的 docker-compose 是正确的。请修正你的答案。我非常想要答案! :)
【解决方案2】:

您看到的问题是 ReactPHP 的 DNS 实现不完整。它不尊重/etc/resolv.conf,最近只增加了对/etc/hosts 的支持。如果您没有使用react/dns v0.4.11 or later,那么这可能是问题所在,您应该尝试升级。

我不确定最近 Docker 如何为链接容器解析 DNS。多年前,它使用了一个钩子 /etc/hosts,它提供了主机名和相应的 IP。但我认为这些天 Docker 正在使用内部 DNS 服务器。由于 ReactPHP 不会自动获取它,因此您必须在创建 DNS 解析器时显式设置它。

尝试将127.0.0.11设置为nameserver,也就是Docker的内部DNS。

【讨论】:

  • 我认为问题出在 PHP 本身的想法相同,因为将条目添加到 hosts 文件可以解决问题。虽然我找不到任何关于此的官方声明。
猜你喜欢
  • 1970-01-01
  • 2019-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-29
  • 1970-01-01
  • 2017-04-12
  • 2020-06-18
相关资源
最近更新 更多