Docker compose, dev and prod multi stage with volume bind

Viewed 47

I am currently trying to build a complete website using docker compose, with a frontend (Vue), a backend (Nest), and a db (Postgresql). I would like to keep the same code for dev and prod purposes by using Docker's multi-stage builds, but still bind volumes to make dev easier.

My problem is for Vue. I need the volume to be bound for dev purpose, thus I need to use CMD [...] instruction to get the files "synced" on dev stage, thus not letting me add a second stage for serving using nginx or stuff like that when I'm running a build. Here is an example of what I would like to be able to make work.

# Dev / Build stage
FROM bitnami/node:18 as first-stage

RUN echo "{ <all my env vars> }" > .env.json && \
              mkdir -p /secrets && \
              openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /secrets/key.pem -out /secrets/cert.pem -subj "<subject>" && \
              chown 1000:1000 /secrets/key.pem && \
              chown 1000:1000 /secrets/cert.pem && \
              yarn install --ignore-engines

# Here is the problem, I get my volume mounted in /app from docker-compose, but I can't
#  access it from the container using `RUN` because when mounting the volume,
#  the container's volume content is wiped out and replaced by host's volume content (am I right ?)
# Using `CMD` to get the volume mounted and synced prevents me from having a
#  second stage in my Dockerfile, so this option is unsuccessful too

# VUE_PHASE can be "serve" for dev purpose or "build" for prod, depends on env variable provided by compose
RUN yarn run ${VUE_PHASE}
# This phase should be synced with host's volume, and should "never end" in dev
#  environment (vue-cli serve has supposedly no end) (I am aware that if serving ends
#  unexpectedly, nginx will start building, but I do not know how to shutdown
#  the container here if in serving stage)

# Serving stage
FROM bitnami/nginx:1.23 as serving-stage

COPY --from=first-stage /app/dist /app

# [ ... ] Other nginx related stuff

I tried to use a second container for nginx, but it seems odd to me as multi-stage build are a good option. By the way when I add my nginx container and make it depend on vue container, my compose logs in console are not shown until nginx container starts, seems a bit weird (and problematic when in dev phase because no log is shown)

Here is a part of my docker compose file

version: '3'

networks:
  n_backend:
    driver: bridge
    name: n_backend
  n_frontend:
    driver: bridge
    name: n_frontend

services:

  # [ ... ] nest and postgresql containers

  s_vuejs:
    build:
      context: ./website/frontend/vuejs/
    image: 's_vuejs'
    networks:
      - n_backend
      - n_frontend
    ports:
      - "${FRONTEND_EXPOSED_HTTP}:${FRONTEND_PORT_HTTP}"
      - "${FRONTEND_EXPOSED_HTTPS}:${FRONTEND_PORT_HTTPS}"
    volumes:
      - ./website/frontend/vuejs/bind:/app
    restart: "no"
    environment:
      # [ ... ]

  # Below is the "second container option"

  s_nginx_frontend:
    build:
      context: ./website/frontend/nginx/
    image: 's_nginx'
    networks:
      - n_frontend
    ports:
      - "${FRONTEND_EXPOSED_HTTP}:${NGINX_PORT_HTTP}"
      - "${FRONTEND_EXPOSED_HTTPS}:${NGINX_PORT_HTTPS}"
    volumes:
      - ./website/frontend/vuejs/bind/dist:/app
      - ./website/frontend/nginx/my_server_block.conf:/opt/bitnami/nginx/conf/server_blocks/my_server_block.conf:ro
    restart: unless-stopped
    # If I do not add the `depends_on` directive, logs are ok, if I do, they wait until nginx starts
    depends_on:
      s_vuejs:
        condition: service_completed_successfully

Thank y'all !

EDIT: I have been able to make the "second container option" work using docker compose profiles, enabling nginx's container with a prod profile, but I think this is still not optimal...

0 Answers
Related