Search code examples
node.jsdockerubuntunetwork-programmingdocker-container

calling nodejs application running on windows from container running in ubuntu hosted on windows wsl


Using Wsl i am using ubuntu to create containers.

One of my application is running on my base windows machine (nodejs agi on localhost:3000)

The container that is running on ubuntu machine use this localhost:3000

but this shows an error

res_agi.c:2015 handle_connection: Connecting to '172.17.0.1:3000' failed for url 'agi://host.docker.internal:3000': Connection refused

I tried adding in my service in docker-compose

extra_hosts:
   - "host.docker.internal:host-gateway"

Even there is an entry in container's /etc/hosts

172.17.0.1 host.docker.internal

I have not much knowledge on container and stuff, any help will be appreciated.


Solution

  • TLDR: In WSL2, use ip route show default or cat /etc/resolv.conf to get the Windows IP address to access the application running on Windows from a container.

    user@WSL:~# ip ro sh default 
    default via 192.168.96.193 dev eth0 
    user@WSL:~# curl 192.168.96.193:3000
    Hello World!
    user@WSL:~# docker run alpine/curl 192.168.96.193:3000
    Hello World!
    

    Networking Details

    There's a game of virtualisation babuska dolls happening here, but the networking is pretty straight forward if you ignore the Docker port mapping magic.

    • Windows normally has a regular network z.z.z.z
    • Windows HyperV creates a network for the WSL VM x.x.x.x
    • Docker creates a network on the WSL VM for the containers y.y.y.y

    The layout looks like this:

              Windows                            
            ┌─────────────────────────────────────────────────────────────────┐
            │ localhost             UbuntuVM                                  │
            │                     ┌───────────────────────────────────────────┤
            │                     │ localhost             Container           │
            │                     │                     ┌─────────────────────┤
            │ LAN          HyperV │                     │ localhost           │
    GW      │ Adapter     Adapter │ eth0        docker0 │ eth0                │
    z.z.z.1 ┼ z.z.z.8     x.x.x.1 ┼ x.x.x.5     y.y.y.1 ┼ y.y.y.19            │
            └─────────────────────┴─────────────────────┴─────────────────────┘
    

    Think of the address to the left hand side of each box as the "external" interface for each "machine". That address tends to be ephemeral, assigned at the whim of gateway it's connected to.

    localhost in each box, always refers to the box localhost.

    host.docker.internal refers to the UbuntuVM docker0 y.y.y.1 address. This can be used to access services on the Docker host. But this is only in the UbuntuVM box. We need something else to reach into the Windows box.

    To get to Windows (application running on my base windows machine) that needs to be addressed to the z.z.z.z or x.x.x.1 address.

    The z.z.z.z address can change depending on where you are connected.

    The x.x.x.x address will stay consistent on your machine, but will vary on other peoples machines. Microsofts guidance for Accessing Windows networking apps from Linux:

    Accessing Windows networking apps from Linux (host IP)

    If you want to access a networking app running on Windows (for example an app running on a NodeJS or SQL server) from your Linux distribution (ie Ubuntu), then you need to use the IP address of your host machine. While this is not a common scenario, you can follow these steps to make it work.

    1. Obtain the IP address of your host machine by running this command from your Linux distribution: cat /etc/resolv.conf
    2. Copy the IP address following the term: nameserver.
    3. Connect to any Windows server using the copied IP address.

    I'm pretty sure an ip route show default will also give you the same gateway address.