1

I work with docker and microservices. Imagine we have 3 services:

          user API
        /
gateway API
        \
          hotel API

Requests go through the gateway to services. I have container with php and nginx, where volumes is the same. Next I give list of configs:

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

If I use simple cURL I can reach to hotel and user api, and I can get response from them, but if I try to do it with reactPHP - I can't! My peace of code:

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

Clue library is just wrapper for react. So the error which I get is: DNS query for hotel.api.loc timed out and the last error An error occurred in the underlying stream.

So I have a question: what I do wrong? Why I have access to nginx container by curl, but can't access by reactPHP? Even If point dns!

But if I use bare ip with port I can reach it. I'm not pro in dns, just basic knowledge.

UPDATE

I use Linux Debian (in container). Work on Mac.

A little about logic: when request URI is gateway.api.loc/api/hotel/list inside gateway we send request to hotel.api.loc to the same URL(/api/hotel/list), accept response and return it.

I repeat that I have access to domains by cURL from, but can't do it with reactPHP and don't understand why...

3
  • What OS are you using? Please update that in your question Commented Sep 6, 2017 at 7:32
  • I found solution without using any dns, just direct request. I request to http://172.14.10.10/api/doc with header 'Host' => 'user.api.loc' and it works. But if you tell me why I can't request direct user.api.loc/api/doc inside gateway I will be very thanksfull Commented Sep 6, 2017 at 20:47
  • Great, thanks for sharing Commented Sep 6, 2017 at 20:56

2 Answers 2

2

The issue you're seeing is ReactPHP's incomplete DNS implementation. It doesn't respect /etc/resolv.conf and only added support for /etc/hosts recently. If you're not using react/dns v0.4.11 or later then that's probably the issue and you should try upgrading.

I'm not sure how Docker resolves DNS these days for linked containers. Years ago that worked with a hooked /etc/hosts that provides the hostnames and corresponding IPs. But I think these days Docker is using an internal DNS server. As ReactPHP doesn't pick that up automatically, you have to explicitly set it when creating a DNS resolver.

Try setting 127.0.0.11 as nameserver, which is Docker's internal DNS.

Sign up to request clarification or add additional context in comments.

1 Comment

I have the same thoughts that the issue is located in PHP itself, because adding the entry to the hosts file resolves the issue. Though I could not find any official statement about this.
1

Your issue is that there is no DNS resolution for gateway.api.loc or hotel.api.loc, they are defined in your Nginx config for routing but no anywhere else for DNS resolution. You need to change your compose to below so they also get resolved in docker DNS resolution

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

This DNS resolution will only work inside the compose and not outside. So if you use it outside then you will have to make host entries

Edit-1

It seems your issue may be code only. You are trying to use gateway IP as DNS when it is not a DNS server.

Change

$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);

to

$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);

And see if it helps

7 Comments

Bad news: dont work for me, and I think not only for me. Aliases is just alias for container name, not for hostname.
Aliases is for IP resolution using DNS and not hostname. Please make me understand why it doesn't work? Where are you running the PHP code from and what exact error do you get?
All as I showed in example. This method is on the controlle, method from service and called from it. Error is: [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 (I edit docker-compose.yml, please you fix it too; thanks)
I forgot to say that when I request gateway.api.loc/api/user/list gateway transform it and request becomes user.api.loc/api/user/list and it request by user api with reactPHP inside gateway project.
Now the docker-compose in question is right. Please fix your answer. And I want the answer so much! :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.