Search code examples
dockerdocker-composecypressdocker-network

docker-compose can't connect to adjacent service via service name


I have this docker-compose.yml that basically builds my project for e2e test. It's composed of a postgres db, a backend Node app, a frontend Node app, and a spec app which runs the e2e test using cypress. version: '3'

  services:
    database:
      image: 'postgres'
    backend:
      build: ./backend
      command: /bin/bash -c "sleep 3; yarn backpack dev"
      depends_on:
        - database
    frontend:
      build: ./frontend
      command: /bin/bash -c "sleep 15; yarn nuxt"
      depends_on:
        - backend
    spec:
      build:
        context: ./frontend
        dockerfile: Dockerfile.e2e
      command: /bin/bash -c "sleep 30; yarn cypress run"
      depends_on:
        - frontend
        - backend

The Dockerfiles are just simple Dockerfiles that based off node:8 which copies the project files and run yarn install. In the spec Dockerfile, I pass http://frontend:3000 as FRONTEND_URL.

But this setup fails at the spec command when my cypress runner can't connect to frontend with error:

  spec_1      |   > Error: connect ECONNREFUSED 172.20.0.4:3000

As you can see, it resolves the hostname frontend to the IP correctly, but it's not able to connect. I'm scratching my head over why can't I connect to the frontend with the service name. If I switch the command on spec to do sleep 30; ping frontend, it's successfully pinging the container. I've tried deleting and let docker-compose recreate the network, I've tried specifying expose and links to the services respectively. All to no success.

I've set up a sample repo here if you wanna try replicating the issue: https://github.com/afifsohaili/demo-dockercompose-network

Any help is greatly appreciated! Thank you!


Solution

  • Your application is listening on loopback:

    $ docker run --rm --net container:demo-dockercompose-network_frontend_1 nicolaka/netshoot ss -lnt                                                               
    State      Recv-Q Send-Q Local Address:Port               Peer Address:Port
    LISTEN     0      128    127.0.0.11:35233                    *:*
    LISTEN     0      128    127.0.0.1:3000                     *:*
    

    From outside of the container, you cannot connect to ports that are only listening on loopback (127.0.0.1). You need to reconfigure your application to listen on all interfaces (0.0.0.0).

    For your app, in the package.json, you can add (according to the nuxt faq):

      "config": {
        "nuxt": {
          "host": "0.0.0.0",
          "port": "3000"
        }
      },
    

    Then you should see:

    $ docker run --rm --net container:demo-dockercompose-network_frontend_1 nicolaka/netshoot ss -lnt
    State      Recv-Q Send-Q Local Address:Port               Peer Address:Port
    LISTEN     0      128          *:3000                     *:*
    LISTEN     0      128    127.0.0.11:39195                    *:*
    

    And instead of an unreachable error, you'll now get a 500:

    ...
    frontend_1  |   response: undefined,        
    frontend_1  |   statusCode: 500,                                                                 
    frontend_1  |   name: 'NuxtServerError' }
    ...
    spec_1      | The response we received from your web server was:
    spec_1      |                                                                                     
    spec_1      |   > 500: Server Error