Issue
I am still finding my feet in the docker world. I am trying to dockerize my small pet project. The frontend is a vue-cli app which communicates with backend containing restful APIs made by spring boot.
So my approach was to declare two separate dockerfile for backend and frontend and combine them via one docker compose file. So the folder structure is -
backend/
- Dockerfile
frontend/
- Dockerfile
docker-compose.yml
As frontend needs to be able to call backend services, I created a bridge network and shared the network between them. This is my docker compose file -
version: "2"
services:
backend:
build: backend/.
networks:
- movie-network
ports:
- "8098:8098"
frontend:
build: frontend/.
ports:
- "8812:8080"
networks:
- movie-network
networks:
movie-network:
driver: bridge
I have an endpoint exposed at backend called /api/findAll
. Now if the frontend service calls the API via http://localhost:8098:/api/findAll
(host network), I can view it from my browser (http://localhost:8812), everything works fine.
But If frontend calls the same API using backend:8098/api/findAll
; utilizing bridge network - it gives error in my browser -
If I do a docker exec
in the frontend and ping backend, the ping is successful
So, why is it giving error in my browser (http://localhost:8812)? Am I conceptually doing anything wrong? Seeking suggestions.
Frontend Dockerfile -
FROM node:lts-alpine
# install simple http server for serving static content
RUN npm install -g http-server
# make the 'app' folder the current working directory
WORKDIR /app
# copy both 'package.json' and 'package-lock.json' (if available)
COPY package*.json ./
# install project dependencies
RUN npm install
# copy project files and folders to the current working directory (i.e. 'app' folder)
COPY . .
# build app for production with minification
RUN npm run build
EXPOSE 8080
Backend Dockerfile -
FROM openjdk:11-jre-slim
# Creating app directory
WORKDIR /usr/src/movies
# Copying Jar (didn't use FROM maven to save some time)
COPY target/movies*.jar movies.jar
RUN pwd
RUN ls -la
# Exposing Port
EXPOSE 8098
# Running App
ENTRYPOINT ["java","-jar","/usr/src/movies/movies.jar"]
Solution
The important thing for this setup is that your actual front-end code is not running in Docker, it's running in your browser. That means it has no idea about Docker networking, containers, or anything else; the URL you give it has to be one that reaches a published port on your host. That's why localhost
works here (if the browser and containers are running on the same host) but backend
doesn't.
A typical approach to this is to set up some sort of reverse proxy that can both host the front-end application code and proxy to the back-end application. (For example, set up Nginx where its /api
route proxy_pass http://backend:8098
, and its /
route either try_files
a prebuilt Javascript application or proxy_pass http://frontend:8080
.)
If you do this, then e.g. http://localhost:8900
is the front-end and http://localhost:8900/api
is the back-end, from the browser's point of view. This avoids the CORS issues @coedycode hints at in their answer; but it also means that the front-end code can use a relative URL /api
(with no host name) and dodge this whole problem.
+-------------+ | Docker > / +----------+
+-------------+ | /------> | frontend |
| | localhost:8900 | +-------+ | +----------+
| Browser | ---------------> | -> | nginx | -> +
| | | +-------+ | /api +----------+
| | | \------> | backend |
+-------------+ | +----------+
Answered By - David Maze
Answer Checked By - Clifford M. (JavaFixing Volunteer)