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
This commit is contained in:
Maieul BOYER 2025-12-30 17:28:06 +01:00 committed by Maix0
parent af13395f2f
commit 2ed524872b
17 changed files with 93 additions and 128 deletions

View file

@ -6,7 +6,6 @@ DOCKER_SERVICE= \
auth \
chat \
tic-tac-toe \
frontend \
nginx \
user \

View file

@ -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:

View file

@ -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" ]

View file

@ -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/

View file

@ -1,17 +1,9 @@
# **************************************************************************** #
# #
# ::: :::::::: #
# Dockerfile :+: :+: :+: #
# +:+ +:+ +:+ #
# By: maiboyer <maiboyer@student.42.fr> +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# 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 ./conf /etc/nginx/templates
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;

View file

@ -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 / {

View file

@ -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;

View file

@ -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;

View file

@ -1,30 +1,22 @@
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
# lets actually build our stuff
FROM raw_builder AS builder
WORKDIR /build
COPY @shared/ /build/@shared/
COPY ${SERVICE}/ /build/${SERVICE}/
@ -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=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

View file

@ -1,7 +0,0 @@
#!/bin/sh
set -e
# do anything here
# run the CMD [ ... ] from the dockerfile
exec "$@"

View file

@ -1,7 +0,0 @@
#!/bin/sh
set -e
# do anything here
# run the CMD [ ... ] from the dockerfile
exec "$@"

View file

View file

@ -1,7 +0,0 @@
{
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "7.17.0"
}
}

View file

@ -1,7 +0,0 @@
#!/bin/sh
set -e
# do anything here
# run the CMD [ ... ] from the dockerfile
exec "$@"

View file

@ -1,7 +0,0 @@
#!/bin/sh
set -e
# do anything here
# run the CMD [ ... ] from the dockerfile
exec "$@"