3

I am building an application using docker-compose (file 1) and I was wondering how I could communicate the host IP address to the docker-compose file. The application is composed of a db, a frontend and a backend. The aim of it is that I want to access my application from other computers on the local network. It works fine for the front but when I want to communicate with the backend, it does not work anymore. I suspect it's due to the fact that the front is trying to send data to localhost (which is not the correct one for another computer on the local network). Thus, I would like to communicate to the front application the IP address of the host directly in the docker-compose file, so it can communicate with the backend ! Any idea ?

File 1

    version: "3.7"

    services:
      db:
        build: 
          context: ./database
        command: --default-authentication-plugin=mysql_native_password  --sql_mode=""
        restart: always
        cap_add:
          - SYS_NICE  # CAP_SYS_NICE
        volumes:
          - db_data:/var/lib/mysql
        ports:
          - ${MYSQL_PORT}:${MYSQL_PORT}
        environment:
          MYSQL_DATABASE: ${MYSQL_DATABASE}
          MYSQL_PASSWORD: ${MYSQL_PASSWORD}
          MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
          MYSQL_TCP_PORT: ${MYSQL_PORT}
        env_file: ./.env

      back:
        depends_on:
          - db
        build: 
          context: ./backend
          target: development
        volumes: 
          - ./backend:/app
          - /app/node_modules
        restart: "no"
        ports:
          - ${BACKEND_PORT}:${BACKEND_PORT}
        env_file: ./.env

      front:
        depends_on:
          - back
          - db
        build:
          context: ./frontend
          target: development
        stdin_open: true
        volumes:
          - ./frontend:/app
          - /app/node_modules
        restart: "no"
        ports:
          - ${FRONTEND_PORT}:${FRONTEND_PORT}
        env_file: ./.env

    volumes:
      db_data: {}

Here is the api url I am using on the frontend env to communicate with the backend, which I would to be replaced with the host IP dynamically.

File 2

const dev = {
    ...env,
    apiUrl: "http://localhost:3000/api",
};

Thank you so much for you help! Best

Bastien L.
  • 119
  • 1
  • 2
  • 9

4 Answers4

1

Environment variables are an easy way to pass small bits of configuration like this in.

For this particular case I'd probably configure a URL and not the host's IP address. You could very reasonably want to deploy this application behind a load balancer; that load balancer might do TLS termination, so you can advertise an https: URL; your local IP address might not be directly reachable from your clients; you'd prefer to advertise a DNS name than an IP address if you have one.

In the Node code you can find environment variables in process.env:

const dev = {
  ...env,
  apiUrl: process.env.API_URL || 'http://localhost:3000/api'
};

Then in your docker-compose.yml you can directly set that URL:

services:
  front:
    environment:
      API_URL: http://10.20.30.40/api
      # API_URL: https://example.com/myapp/api
David Maze
  • 130,717
  • 29
  • 175
  • 215
  • 1
    Thank you for your answer David; that's exactly what I want to do but I also would like to add the ip address http://10.20.30.40/api dynamically, without having to specify the ip manually each time I am on a new network..not sure if it's possible though – Bastien L. Jan 29 '21 at 09:49
1

What you want is called shell command substitution.
Something like: MYVAR=$(ip route get 1 | awk '{print $NF;exit}')

Unfortunately, command substitution is NOT supported in compose.
Compose supports only "static" shell variables aka shell variable expansion.
Your best bet would be to declare mandatory variable with an appropriate error message.

# requires for the var to be pre-declared in shell
environment:
  API_URL: ${API_URL:?"Variable API_URL must present in shell."}

# alternatively you could provide some default value
environment:
  API_URL: ${API_URL:-192.0.2.2}

Another solution may be to play with envsubst to edit your compose file in-place.
Check this answer for examples.


Also note that there is no such thing as "host's ip address" :)
It's kinda conventional and a pretty vague term.

"Primary IP" is an alias for "whatever your system uses when it originates traffic to the default route". In the absence of source phrases on that route, that's the first address of the interface used (more or less).

Thus, you need to be careful when writing your command to define "host's IP".
In simple network configurations this one is likely to work more or less fine.
ip route get 1 | awk '{print $NF;exit}'
But better check this discussion and make sure your eventual command returns what you expect.

Olesya Bolobova
  • 1,573
  • 1
  • 10
  • 21
0

By adding HOST_IP=http://host.docker.internal:PORT in environment variable of particular services like this

environment:
  - HOST_IP=http://host.docker.internal:4001/

You can access the host ip inside the docker by accessing the environment variable in node js code like

var host_url=process.env.HOST_IP

NOTE: As you can access host ip only you need to add port manually at the end of url and it only works for the development server NOT for production.

Ankit
  • 1,094
  • 11
  • 23
0

You should add an environment variable to your frontend configuration which specifies the URL to the api endpoint and use the hostname of the backend container in the URL. The documentation for Networking in Compose details default hostname and networks used for containers.

Modify your docker compose file as follows:

services:
  front:
    environment:
      API_URL: http://back:${BACKEND_PORT}/api

Modify your javascript file as follows:

const dev = {
  ...env,
  apiUrl: process.env.API_URL || 'http://localhost:3000/api'
};
deAtog
  • 61
  • 3