Search code examples
reactjsdockerdocker-composemicroservicesdevops

Calling API in a docker-compose React container to django container using service name


I have a docker compose that containss a react app and other django container. They are in the same network so when I try to make curl request from the react container to one of the django services using the service name it works but in the web app it doesn't work and it said :

POST http://backend-account:8000/api/auth/login/ net::ERR_NAME_NOT_RESOLVED

this is my docker compose :

version: "3.9"
services:
  db-account:
    restart: always
    container_name: ctr-db-account-service
    image: mysql:8
    environment:
      - MYSQL_DATABASE=dtp_db
      - MYSQL_USER=admin
      - MYSQL_PASSWORD=ictf
      - MYSQL_HOST=db
      - MYSQL_PORT=3306
      - MYSQL_ROOT_HOST=%
      - MYSQL_ROOT_PASSWORD=root
    volumes:
      - account-data:/var/lib/mysql
    networks:
      - dtp-network

  db-stream:
    restart: always
    container_name: ctr-db-stream-service
    image: mysql:8
    environment:
      - MYSQL_DATABASE=dtp_db
      - MYSQL_USER=admin
      - MYSQL_PASSWORD=ictf
      - MYSQL_HOST=db
      - MYSQL_PORT=3306
      - MYSQL_ROOT_HOST=%
      - MYSQL_ROOT_PASSWORD=root
    volumes:
      - stream-data:/var/lib/mysql
    networks:
      - dtp-network

  backend-account:
    restart: always
    container_name: ctr-account-service
    command:
      # bash -c "python check_db.py --service-name db --ip db --port 3306 &&
      bash -c "sleep 20 &&
      python manage.py migrate &&
      python manage.py runserver 0.0.0.0:8000"
    env_file:
      - ./dtp-account-management-app/account_management/.env
    build:
      context: ./dtp-account-management-app/account_management/
      dockerfile: Dockerfile
    expose: 
      - 8000
    ports:
      - "8080:8000"
    depends_on:
      - db-account
    links:
      - db-account
    networks:
      - dtp-network

  backend-stream:
    restart: always
    container_name: ctr-stream-service
    command:
      # bash -c "python check_db.py --service-name db --ip db --port 3306 &&
      bash -c "sleep 20 &&
      python manage.py migrate &&
      python manage.py runserver 0.0.0.0:7000"
    env_file:
      - ./dtp-stream-management-app/stream_management/.env
    build:
      context: ./dtp-stream-management-app/stream_management/
      dockerfile: Dockerfile
    expose: 
      - 7000
    ports:
      - "7000:7000"
    depends_on:
      - db-stream
    links:
      - db-stream
    networks:
      - dtp-network

  frontend:
    restart: always
    command: npm start
    container_name: ctr-frontend-service
    build:
      context: ./dtp-frontend-app/
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    stdin_open: true
    depends_on:
      - backend-account
      - backend-stream
    links:
      - backend-stream
      - backend-account
    networks:
      - dtp-network

networks:
  dtp-network:
    driver: bridge

volumes:
  account-data:
    driver: local
  stream-data:
    driver: local

Additionally when the error occurred I get nothing in the terminal, more like there is no communication, but trying by running the curl request in the react container i got this response:

/react # curl -i -X GET --url http://backend-account:8000/api/auth/login/
HTTP/1.1 200 OK
Date: Mon, 13 Sep 2021 11:25:06 GMT
Server: WSGIServer/0.2 CPython/3.9.6
Content-Type: application/json
Vary: Accept, Origin
Allow: POST, OPTIONS
X-Frame-Options: DENY
Content-Length: 40
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin

Solution

  • Your web app (react) is ultimately run in the user's browser and not in the container. At that moment they are not in the same docker network and using the service name won't work like it does when you use curl from within the container.

    So you need to expose your service on your server so that the users from its own machine at home using their browser can make the network request.

    Then you need to use the server IP address or domain name you have set up, in your frontend code to hit the Django backend.

    Since you have already published the ports of your backends, 8080:8000 and 7000:7000, you can hit that service on your server IP if your firewall permits.

    For example, use one of those in your frontend code.

    http://<your-server-ip>:8080
    # or
    http://<your-server-ip>:7000
    

    That said, I would advise to purchase a domain and set a DNS record pointing to your server. Then you could also serve a proper SSL certificate, encrypting the traffic.

    On a side note, if you wanted only internal communication between services with docker, then you don't need to publish the ports like you did. This may or may not lead to security issues. Your database, for example, doesn't have the ports published, and the backend can still connect. But as I said, this is more of a random side fact than being part of the actual answer. To solve your problem, you need to do what I have described above.