How to connect frontend to backend via docker-compose networks

14,554

Solution 1

In fact your traffic is as next:

  1. User browser request page from angular container, then all pages will rendered to user's browser.

  2. The front javascript code using angular HttpClient to fetch the data from express container.

    At that time, although docker-compose setup a customized network for you which afford auto-dns to resolve angular & express, but this dns just works among containers, not effect for host.

    But, your augular HttpClient which call http://express was happened on user's browser which not in container, so the auto-dns defintly not work for you to resolve the name express.

For you, if you just want to open browser from your docker host, you can use localhost, but if you also want the user from other machine to visit your web, you had to use the ip of your dockerhost.

Then, in angular HttpClient you need to use something like http://your_dockerhost_ip:8000 to visit express container.

If interested, you can visit this to see User-defined bridges provide automatic DNS resolution between containers.

Solution 2

A few things:

  1. By using expose, you are making the container's published ports only available to linked/networked services. This is one reason why you are unable to access it locally.
  2. Instead of hitting http://express:8000/ you should try to hit http://localhost:8000. The service is being published to your localhost system and is not being served by anything by default (e.g., IIS, NGINX).
  3. Add a custom defined network in your compose file instead of using links. This is now the main way to network containers together:

    version: '3' # specify docker-compose version
    
    services:
      angular: # name of the first service
        build: ./ # specify the directory of the Dockerfile
        ports:
          - "4200:80" # maps port 4200 on localhost to 80 in container
        network:
          - mynetwork
        depends_on:
          - "express"
    
      express: # name of the second service
        build:  # specify the directory of the Dockerfile
          context: ./
          dockerfile: dockerfile.be
        ports:
          - "8000:8000" # maps port 8000 on localhost to 8000 in container
        networks:
          - mynetwork
    
    networks:
      mynetwork:

    2: https://docs.docker.com/compose/compose-file/#expose

Share:
14,554

Related videos on Youtube

Keanu
Author by

Keanu

Updated on June 04, 2022

Comments

  • Keanu
    Keanu almost 2 years

    I'm trying to dockerize my angular + express application. I have a docker-compose file that creates the two containers, and I am able to hit the containers from my host machine(using my browser), but I'll just get a "ERR_NAME_NOT_RESOLVED" whenever I try to hit the backend from http requests made by my frontend.

    I've looked up the issue, and it seems like most suggest that the service name and container port should be enough to hit the the other container when they're on the same network. I've tried to hit "http://express:8000/user?user=030f0e70-9a8f-11e9-b5d1-f5cb6c0f3616" which I think should work given what I've seen from other places, but regardless, I get the same error.

    My docker-compose file looks like

    version: '3' # specify docker-compose version
    
    # Define the services/containers to be run
    services:
      angular: # name of the first service
        build: ./ # specify the directory of the Dockerfile
        ports:
          - "4200:80" # specify port forewarding
        links:
          - "express"
        depends_on:
          - "express"
    
      express: #name of the second service
        build:  # specify the directory of the Dockerfile
          context: ./
          dockerfile: dockerfile.be
        ports:
          - "8000:8000" #specify ports forewarding
        expose:
          - "8000"
    

    Ideally, I'd like my frontend to be able to hit the other container with a set endpoint, so I could deploy the application with minimal changes. I'd appreciate any advice. I feel like I'm missing something really simple, but after a few hours of tinkering, I still haven't caught it.

    Thanks!

    • atline
      atline almost 5 years
      Describe who send request to which part when you meet ERR_NAME_NOT_RESOLVED, ajax? And the detail url.
    • Keanu
      Keanu almost 5 years
      I just send the request using the angular HttpClient to my express backend. When not using the containers, I can just hit "localhost:8000/user?user=030f0e70-9a8f-11e9-b5d1-f5cb6c0f36‌​16" and get data from the backend to my angular app.
  • Keanu
    Keanu almost 5 years
    For the dockerhost_ip, I figure that's what I get when I run docker-machine ip? I noticed that I can hit that from the frontend (in this case "192.168.99.100:8000"), but I don't know if that would be a viable solution when trying to deploy and run the containers outside of my machine(like if the ip changes when ran somewhere else) or if there's some way of dynamically getting the ip regardless of where it's ran
  • atline
    atline almost 5 years
    You should set env_file in docker-compose.yaml for angular, see this, then, if deploy to other machine, you could customize the ip in it before up. Another way is to wrap a script start.sh, in it use ip a s to get the ip of current machine, e.g. 192.168.99.100, then execute export HOST_IP=192.168.99.100 docker compose up -d, and in compose.yaml, add environment= - ip=${HOST_IP}, refers to docs.docker.com/compose/environment-variables/…
  • atline
    atline almost 5 years
    Then in angular container program you should read the value of ip from envronment & fill in javascript code with this value when render the template.
  • Keanu
    Keanu almost 5 years
    Because the containers ran on the same host, I was able to target all my requests from my angular frontend to "http://" + location.hostname + ":8000", and that's worked for actually hitting the backend. Thanks for the help!