0

So I want to have a single Nginx web server serving both frontend and backend with Docker. Here is my docker-compose:

version: "3.8"

services:
  db: #mysqldb
    image: mysql:5.7
    container_name: ${DB_SERVICE_NAME}
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_USER: ${DB_USERNAME}
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    ports:
      - $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
    volumes:
      - ./docker-compose/mysql:/docker-entrypoint-initdb.d
    networks:
      - backend

  mrmfrontend:
    build:
      context: ./mrmfrontend
      args:
        - REACT_APP_API_BASE_URL=$CLIENT_API_BASE_URL
        - REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
        - REACT_APP_FRONTEND_ENDPOINT=$REACT_APP_FRONTEND_ENDPOINT
        - REACT_APP_FRONTEND_ENDPOINT_ERROR=$REACT_APP_FRONTEND_ENDPOINT_ERROR
        - REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
        - REACT_APP_NAME=$REACT_APP_NAME
        - REACT_APP_OWNER=""
    ports:
      - $REACT_LOCAL_PORT:$REACT_DOCKER_PORT
    networks:
      - frontend

  nginx:
    image: nginx:alpine
    container_name: backend-nginx
    restart: unless-stopped
    ports:
      - 8000:80
    volumes:
      - ./MRMBackend:/var/www
      - ./docker-compose/nginx/backend:/etc/nginx/conf.d/
    networks:
      - backend
      - frontend

  app:
    build:
      args:
        user: admin
        uid: 1000
      context: ./MRMBackend
      dockerfile: Dockerfile
    image: backend
    container_name: backend-app
    restart: unless-stopped
    working_dir: /var/www/
    volumes:
      - ./MRMBackend:/var/www
    networks:
      - backend

volumes:
  db:

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

And here's the Dockerfile for the frontend:

FROM node:16.13.0 as build-stage

WORKDIR /app

COPY package.json ./
COPY package-lock.json ./
COPY ./ ./
RUN npm i

ARG REACT_APP_API_BASE_URL
ARG REACT_APP_BACKEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT_ERROR
ARG REACT_APP_CUSTOMER
ARG REACT_APP_NAME

ENV REACT_APP_API_BASE_URL=$REACT_APP_API_BASE_URL
ENV REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT = $REACT_APP_FRONTEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT_ERROR = $REACT_APP_FRONTEND_ENDPOINT_ERROR
ENV REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
ENV REACT_APP_NAME=$REACT_APP_NAME

ENV GENERATE_SOURCEMAP=false

RUN npm run build

The problem is that the frontend container can't seem to start. It exit always at startup.

From my understanding I should copy the build content of the build-stage into the nginx folder "/usr/share/nginx/html" but how can I do it from the docker-compose file?

Just using volumes won't work. I need nginx in the docker-compose because it's also serving the backend.

Please note that the backend is working correctly.

UPDATE

My first approach was to use a Dockerfile for the frontend where I copied the content of the build directly into an Nginx image

# Stage 1
FROM node:16.13.0 as build-stage

WORKDIR /app

COPY package.json ./
COPY package-lock.json ./
COPY ./ ./
RUN npm i

ARG REACT_APP_API_BASE_URL
ARG REACT_APP_BACKEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT_ERROR
ARG REACT_APP_CUSTOMER
ARG REACT_APP_NAME

ENV REACT_APP_API_BASE_URL=$REACT_APP_API_BASE_URL
ENV REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT = $REACT_APP_FRONTEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT_ERROR = $REACT_APP_FRONTEND_ENDPOINT_ERROR
ENV REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
ENV REACT_APP_NAME=$REACT_APP_NAME

#avoid javascript out of memory
ENV GENERATE_SOURCEMAP=false

RUN npm run build

# Stage 2
FROM nginx:1.17.0-alpine

COPY --from=build-stage /app/build /usr/share/nginx/html
EXPOSE $REACT_DOCKER_PORT

CMD nginx -g 'daemon off;'

But in this way I think I'm deploying two Nginx. One in the Dockerfile and one in the Docker-compose. Am I right?

Federico Arona
  • 125
  • 1
  • 13
  • Have you tried [share-named-volume-between-multiple-containers ](https://stackoverflow.com/questions/44284484/docker-compose-share-named-volume-between-multiple-containers#44284993) – abestrad Jan 23 '22 at 10:18
  • @a_e So I should create a shared named volumes, copy the content of the build there and then use it as volume for Nginx? – Federico Arona Jan 23 '22 at 16:26
  • that would be one way, another is build the app in the first stage and a second stage to deploy nginx as last step. – abestrad Jan 23 '22 at 17:35
  • The second way you described was my first approach but I have a question on that approach. I updated the question to show the initial Dockerfile. But my question with that approach is: using the second stage "from nginx-alpine" am I deploying two different nginx images? One is in the Dockerfile and one in the docker-compose. – Federico Arona Jan 23 '22 at 17:51
  • Yes, that’s why if you want to have 1 nginx you need to share or copy the files from the container that is building the app. – abestrad Jan 23 '22 at 19:22
  • Thanks @a_e. Using shared named volumes I've been able to copy the content of the build into the "usr/share/nginx/html" folder. The app is still not working but it's probably a nginx configuration issue. If you put your comment as asnwer I'll accept it. – Federico Arona Jan 25 '22 at 00:20
  • Done, added the info with some additional links, @federico-arona – abestrad Jan 25 '22 at 11:01

2 Answers2

1

@federico-arona

As stated in my comment: If you want to have 1 nginx you need to share or copy the files from the container that is building the app.

Based on your requirements and what you wanted to accomplish. The best solution is named volumes, as they can be shared across containers.

They are the preferred mechanism for persisting data generated by and used by Docker containers. Plus you can manage volumes using Docker CLI commands and the Docker API. The Official docs show other benefits and additional information on how to use them.

abestrad
  • 898
  • 2
  • 12
  • 23
0

I mostly use Docker multi-build to configure my FE app. Hope this might help you!

FROM node:16.13.0 as build-stage

WORKDIR /app

COPY package.json ./
COPY package-lock.json ./
COPY ./ ./

RUN npm install
RUN npm run dev



#Build Files
FROM nginx:1.19.10-alpine
COPY nginx-conf /etc/nginx/conf.d/default.conf
COPY --from=build /app /home/ubuntu/app/dist

you can use default nginx configuration.

Abhishek Kumar
  • 417
  • 7
  • 17
  • Thanks for your answer. But in this way am I deploying two Nginx images? One is the one present here in the Dockerfile, and the other is the one deployed with the Docker-compose. Am I right? – Federico Arona Jan 23 '22 at 18:10
  • you do not need another Nginx, because your angular code is hosted by the Nginx that is present in the container itself. and It'll be light wait aslo – Abhishek Kumar Jan 24 '22 at 06:56
  • In this way I would another Nginx to serve the backend app. That's why I tried to move the Nginx image into the docker-compose, in order to have only one Nginx serving both frontend and backend – Federico Arona Jan 24 '22 at 10:23