From 2ed524872b6b934a1acd86d8583e11442e925f6e Mon Sep 17 00:00:00 2001 From: Maieul BOYER Date: Tue, 30 Dec 2025 17:28:06 +0100 Subject: [PATCH] feat(docker): Multi stage docker now fetch deps once Split dockerfile into three different dockerfiles such that dependencies are only downloaded once This allows the build to be a bit faster, since all deps are downloaded once at the start. This also makes it so the frontend container no longer needs to be ran, as its files are directly embedded into the nginx container This also remove the extra files, since bind mounts do work it also remove the entrypoint.sh file, as you should prefer to not use it --- Docker.mk | 1 - docker-compose.yml | 57 +++++++++++++++++++++++--------- frontend/Dockerfile | 14 +------- frontend/run.sh | 9 ----- nginx/Dockerfile | 28 ++++++---------- nginx/conf/locations/app.conf | 4 +-- src/@dockerfiles/deps.Dockerfile | 14 ++++++++ src/@dockerfiles/pnpm.Dockerfile | 3 ++ src/Dockerfile | 56 +++++++++++-------------------- src/auth/entrypoint.sh | 7 ---- src/chat/entrypoint.sh | 7 ---- src/chat/extra/.gitkeep | 0 src/empty/.gitkeep | 0 src/openapitools.json | 7 ---- src/tic-tac-toe/entrypoint.sh | 7 ---- src/user/entrypoint.sh | 7 ---- src/user/extra/.gitkeep | 0 17 files changed, 93 insertions(+), 128 deletions(-) delete mode 100644 frontend/run.sh create mode 100644 src/@dockerfiles/deps.Dockerfile create mode 100644 src/@dockerfiles/pnpm.Dockerfile delete mode 100644 src/auth/entrypoint.sh delete mode 100644 src/chat/entrypoint.sh delete mode 100644 src/chat/extra/.gitkeep delete mode 100644 src/empty/.gitkeep delete mode 100644 src/openapitools.json delete mode 100644 src/tic-tac-toe/entrypoint.sh delete mode 100644 src/user/entrypoint.sh delete mode 100644 src/user/extra/.gitkeep diff --git a/Docker.mk b/Docker.mk index 1db9b77..e529f22 100644 --- a/Docker.mk +++ b/Docker.mk @@ -6,7 +6,6 @@ DOCKER_SERVICE= \ auth \ chat \ tic-tac-toe \ - frontend \ nginx \ user \ diff --git a/docker-compose.yml b/docker-compose.yml index 4bd2c1c..febf81b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,22 +5,41 @@ networks: driver: bridge services: + ########## + # DEPS # + ########## + + pnpm_base: + build: + context: ./src + dockerfile: '@dockerfiles/pnpm.Dockerfile' + restart: on-failure:3 + + pnpm_deps: + build: + context: ./src + dockerfile: '@dockerfiles/deps.Dockerfile' + additional_contexts: + pnpm_base: "service:pnpm_base" + restart: on-failure:3 + frontend: - build: ./frontend + build: + context: ./frontend + additional_contexts: + pnpm_base: "service:pnpm_base" container_name: app-frontend restart: on-failure:3 - networks: - - app - volumes: - - static-volume:/volumes/static - logging: - driver: gelf - options: - gelf-address: "udp://127.0.0.1:12201" - tag: "{{.Name}}" + + ############ + # SERVICES # + ############ nginx: - build: ./nginx + build: + context: ./nginx + additional_contexts: + frontend: "service:frontend" container_name: app-nginx restart: always networks: @@ -41,15 +60,14 @@ services: gelf-address: "udp://127.0.0.1:12201" tag: "{{.Name}}" - ############### - # SERVICE # - ############### - auth: build: context: ./src/ args: - SERVICE=auth + additional_contexts: + pnpm_base: "service:pnpm_base" + pnpm_deps: "service:pnpm_deps" container_name: app-auth restart: always networks: @@ -74,6 +92,9 @@ services: context: ./src/ args: - SERVICE=tic-tac-toe + additional_contexts: + pnpm_base: "service:pnpm_base" + pnpm_deps: "service:pnpm_deps" container_name: app-tic-tac-toe restart: always networks: @@ -97,6 +118,9 @@ services: context: ./src/ args: - SERVICE=chat + additional_contexts: + pnpm_base: "service:pnpm_base" + pnpm_deps: "service:pnpm_deps" container_name: app-chat restart: always networks: @@ -119,6 +143,9 @@ services: context: ./src/ args: - SERVICE=user + additional_contexts: + pnpm_base: "service:pnpm_base" + pnpm_deps: "service:pnpm_deps" container_name: app-user restart: always networks: diff --git a/frontend/Dockerfile b/frontend/Dockerfile index f44fde2..c1de397 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,11 +1,8 @@ -FROM node:22-alpine AS pnpm_base -RUN npm install --global pnpm@10; - FROM pnpm_base AS deps COPY ./package.json ./pnpm-lock.yaml ./pnpm-workspace.yaml /src/ WORKDIR /src -RUN pnpm install --frozen-lockfile; +RUN pnpm install -q --frozen-lockfile; FROM pnpm_base AS builder @@ -14,12 +11,3 @@ COPY --from=deps /src/node_modules /src/node_modules COPY . /src RUN pnpm run build; - -FROM pnpm_base - -COPY --from=builder /src/dist /dist -COPY ./run.sh /bin/run.sh - -RUN chmod +x /bin/run.sh - -CMD [ "/bin/run.sh" ] diff --git a/frontend/run.sh b/frontend/run.sh deleted file mode 100644 index 4f2594d..0000000 --- a/frontend/run.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -set -x -set -e - -rm -rf /volumes/static/app -mkdir -p /volumes/static/app - -cp -r /dist/* /volumes/static/app/ diff --git a/nginx/Dockerfile b/nginx/Dockerfile index b152c1c..fbb4136 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -1,17 +1,9 @@ -# **************************************************************************** # -# # -# ::: :::::::: # -# Dockerfile :+: :+: :+: # -# +:+ +:+ +:+ # -# By: maiboyer +#+ +:+ +#+ # -# +#+#+#+#+#+ +#+ # -# Created: 2025/06/12 16:42:38 by maiboyer #+# #+# # -# Updated: 2025/07/29 13:58:39 by maiboyer ### ########.fr # -# # -# **************************************************************************** # +FROM frontend AS frontend-files FROM nginx:stable-alpine +ENV NGINX_DOMAIN "local.maix.me" + RUN \ mkdir -p /volumes/ && \ mkdir -p /etc/nginx/ && \ @@ -21,15 +13,17 @@ RUN \ openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/ssl/private/nginx-selfsigned.key \ -out /etc/ssl/certs/nginx-selfsigned.crt \ - -subj "/C=FR/OU=student/CN=${NGINX_DOMAIN}" + -subj "/C=FR/OU=student/CN=${NGINX_DOMAIN}"; -COPY ./15-local-resolvers.envsh /docker-entrypoint.d/ -COPY ./17-add-template-prefix.sh /docker-entrypoint.d/ +COPY ./15-local-resolvers.envsh /docker-entrypoint.d/ +COPY ./17-add-template-prefix.sh /docker-entrypoint.d/ +COPY ./conf /etc/nginx/templates -COPY ./conf /etc/nginx/templates -COPY ./monitoring.index.html /var/share/www/monitoring/ +COPY ./monitoring.index.html /var/share/www/monitoring/ +COPY --from=frontend-files /src/dist /var/share/www/static/ RUN chmod -R +r /var/share/www/monitoring/; +RUN chmod -R +r /var/share/www/static/; HEALTHCHECK --interval=30s --timeout=3s \ - CMD curl -f -s http://localhost:8080/ok?docker || exit 1; \ No newline at end of file + CMD curl -f -s http://localhost:8080/ok?docker || exit 1; diff --git a/nginx/conf/locations/app.conf b/nginx/conf/locations/app.conf index 75bca27..252fa89 100644 --- a/nginx/conf/locations/app.conf +++ b/nginx/conf/locations/app.conf @@ -1,10 +1,10 @@ location /app { - root /volumes/static/app/; + root /var/share/www/static/; try_files /index.html =404; } location /assets { - root /volumes/static/app/; + root /var/share/www/static/; } location / { diff --git a/src/@dockerfiles/deps.Dockerfile b/src/@dockerfiles/deps.Dockerfile new file mode 100644 index 0000000..df81482 --- /dev/null +++ b/src/@dockerfiles/deps.Dockerfile @@ -0,0 +1,14 @@ +FROM pnpm_base AS deps +WORKDIR /build + +COPY package.json pnpm-workspace.yaml pnpm-lock.yaml /build/ + + +# You need to list all services here... +COPY @shared/package.json /build/@shared/package.json +COPY auth/package.json /build/auth/package.json +COPY chat/package.json /build/chat/package.json +COPY tic-tac-toe/package.json /build/tic-tac-toe/package.json +COPY user/package.json /build/user/package.json + +RUN pnpm install -q --frozen-lockfile; diff --git a/src/@dockerfiles/pnpm.Dockerfile b/src/@dockerfiles/pnpm.Dockerfile new file mode 100644 index 0000000..630ff98 --- /dev/null +++ b/src/@dockerfiles/pnpm.Dockerfile @@ -0,0 +1,3 @@ +FROM node:22-alpine AS pnpm_base +RUN npm install --global pnpm@10 --no-fund -q; +RUN apk add make python3 gcc clang build-base musl-dev curl; diff --git a/src/Dockerfile b/src/Dockerfile index 6b7d366..6141b32 100644 --- a/src/Dockerfile +++ b/src/Dockerfile @@ -1,33 +1,25 @@ -FROM node:22-alpine AS pnpm_base -RUN npm install --global pnpm@10 --no-fund -q; -RUN apk add make python3 gcc clang build-base musl-dev; -RUN apk add --no-cache curl +# lets include the pnpm_deps as an named image (raw_deps) +FROM pnpm_deps AS raw_deps -FROM pnpm_base AS deps -WORKDIR /build -ARG SERVICE - -COPY package.json pnpm-workspace.yaml pnpm-lock.yaml /build/ -COPY @shared/package.json /build/@shared/ -COPY ${SERVICE}/package.json /build/${SERVICE}/ - -RUN pnpm install --frozen-lockfile; - -FROM pnpm_base AS builder - -ARG SERVICE +# lets make a `raw_builder` as an image -> this only include the deps and the metadata files +FROM pnpm_base AS raw_builder WORKDIR /build + +COPY --from=raw_deps /build/node_modules /build/node_modules +ARG SERVICE COPY package.json /build/ COPY @shared/package.json /build/@shared/ -COPY ${SERVICE}/ /build/${SERVICE} +COPY ${SERVICE}/package.json /build/${SERVICE}/ COPY tsconfig.base.json pnpm-workspace.yaml pnpm-lock.yaml /build/ -COPY ${SERVICE}/entrypoint.sh /build/ -COPY --from=deps /build/node_modules /build/node_modules -COPY @shared/ /build/@shared/ -COPY ${SERVICE}/ /build/${SERVICE}/ +# lets actually build our stuff +FROM raw_builder AS builder +WORKDIR /build + +COPY @shared/ /build/@shared/ +COPY ${SERVICE}/ /build/${SERVICE}/ RUN cd /build/${SERVICE} && \ pnpm run build:prod && \ @@ -35,24 +27,16 @@ RUN cd /build/${SERVICE} && \ cp /build/pnpm-workspace.yaml /dist/pnpm-workspace.yaml && \ cp /build/pnpm-lock.yaml /dist/pnpm-lock.yaml && \ cp /build/@shared/package.json /dist/@shared/ && \ - cp /build/${SERVICE}/package.json /dist/${SERVICE}/ && \ - cp /build/entrypoint.sh /dist/ && \ - chmod +x /dist/entrypoint.sh; - + cp /build/${SERVICE}/package.json /dist/${SERVICE}/; +# this is our actual running container :D FROM pnpm_base - WORKDIR /src -ARG EXTRA_FILES=empty -COPY --from=builder /dist /src -COPY --from=deps /build/node_modules /src/node_modules - -COPY ${EXTRA_FILES} /extra -ENTRYPOINT [ "/src/entrypoint.sh" ] - -HEALTHCHECK --interval=30s --timeout=3s \ - CMD curl -f -s http://localhost/monitoring?docker || exit 1 +COPY --from=builder /dist /src +COPY --from=raw_builder /build/node_modules /src/node_modules CMD ["node", "/src/run.cjs"] +HEALTHCHECK --interval=30s --timeout=3s \ + CMD curl -f -s http://localhost/monitoring?docker || exit 1 diff --git a/src/auth/entrypoint.sh b/src/auth/entrypoint.sh deleted file mode 100644 index f1735d5..0000000 --- a/src/auth/entrypoint.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e -# do anything here - -# run the CMD [ ... ] from the dockerfile -exec "$@" diff --git a/src/chat/entrypoint.sh b/src/chat/entrypoint.sh deleted file mode 100644 index f1735d5..0000000 --- a/src/chat/entrypoint.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e -# do anything here - -# run the CMD [ ... ] from the dockerfile -exec "$@" diff --git a/src/chat/extra/.gitkeep b/src/chat/extra/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/empty/.gitkeep b/src/empty/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/openapitools.json b/src/openapitools.json deleted file mode 100644 index f052220..0000000 --- a/src/openapitools.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", - "spaces": 2, - "generator-cli": { - "version": "7.17.0" - } -} diff --git a/src/tic-tac-toe/entrypoint.sh b/src/tic-tac-toe/entrypoint.sh deleted file mode 100644 index f1735d5..0000000 --- a/src/tic-tac-toe/entrypoint.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e -# do anything here - -# run the CMD [ ... ] from the dockerfile -exec "$@" diff --git a/src/user/entrypoint.sh b/src/user/entrypoint.sh deleted file mode 100644 index f1735d5..0000000 --- a/src/user/entrypoint.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -set -e -# do anything here - -# run the CMD [ ... ] from the dockerfile -exec "$@" diff --git a/src/user/extra/.gitkeep b/src/user/extra/.gitkeep deleted file mode 100644 index e69de29..0000000