From 71d4a63a17506809571daae5ab7ae62232b2fad5 Mon Sep 17 00:00:00 2001 From: Mohamed Messaad Date: Mon, 13 Nov 2023 10:13:56 +0100 Subject: [PATCH] feat(docker): use multi-stage Docker builds for smaller images (#1614) # Description Currently, the production Docker images are very large, sitting at 4.17 GB for the frontend image, and 3.49 GB for backend images. This change adds multi-stage builds, to optimize the image sizes, which results in the following improvements: - frontend image size: 4.17 GB -> 1.64 GB - backend image size: 3.49 GB -> 1.71 GB I hope this is appropriate as there is no open issue for this that I know of. I implemented this change and tested it locally, and would be glad to discuss this and open an issue if necessary. ## Checklist before requesting a review Please delete options that are not relevant. - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented hard-to-understand areas - [x] New and existing unit tests pass locally with my changes ## Screenshots (if appropriate): Image sizes before: image Image sizes after: image --- backend/Dockerfile | 40 ++++++++++++++++++++++++++++++++-------- frontend/Dockerfile | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 1f2c7e18c..de9122487 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,10 +1,10 @@ -# Using a slim version for a smaller base image -FROM python:3.11-slim-bullseye +# First stage: Build environment +FROM python:3.11-slim-bullseye as builder ARG DEV_MODE ENV DEV_MODE=$DEV_MODE -# Install GEOS library, Rust, and other dependencies, then clean up +# Install GEOS library, Rust, and other build-time dependencies RUN apt-get update && apt-get install -y \ libgeos-dev \ libcurl4-openssl-dev \ @@ -20,19 +20,43 @@ RUN apt-get update && apt-get install -y \ # Add Rust binaries to the PATH ENV PATH="/root/.cargo/bin:${PATH}" +# Create a virtual environment and activate it +RUN python -m venv /venv +ENV PATH="/venv/bin:$PATH" + WORKDIR /code # Copy just the requirements first COPY ./requirements.txt . -# Upgrade pip -RUN pip install --upgrade pip - -# Increase timeout to wait for the new installation -RUN pip install --no-cache-dir -r requirements.txt --timeout 200 +# Upgrade pip and install requirements +RUN pip install --upgrade pip && \ + pip install --no-cache-dir -r requirements.txt --timeout 200 +# Install development tools if in DEV_MODE RUN if [ "$DEV_MODE" = "true" ]; then pip install --no-cache debugpy --timeout 200; fi + + +FROM python:3.11-slim-bullseye as runtime + +ARG DEV_MODE +ENV DEV_MODE=$DEV_MODE + +# Create and activate the virtual environment +ENV PATH="/venv/bin:$PATH" + +# Install runtime dependencies +RUN apt-get update && apt-get install -y \ + pandoc \ + binutils && \ + rm -rf /var/lib/apt/lists/* && apt-get clean + +WORKDIR /code + +# Copy the virtual environment from the builder stage +COPY --from=builder /venv /venv + # Copy the rest of the application COPY . . diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 02c681bd1..475e15e7d 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,31 +1,49 @@ -FROM node:18.13.0-alpine +# First stage: Build environment +FROM node:18.13.0-alpine as builder + # Install Python and essential build tools RUN apk add --update --no-cache python3 make g++ && ln -sf python3 /usr/bin/python RUN python3 -m ensurepip RUN pip3 install --no-cache --upgrade pip setuptools -# Create the directory on the node image -# where our Next.js app will live -RUN mkdir -p /app +# Create a Python virtual environment +RUN python3 -m venv /venv +ENV PATH="/venv/bin:$PATH" -# Set /app as the working directory +# Create the directory where our app will live +RUN mkdir -p /app WORKDIR /app -# Copy package.json and yarn.lock -# to the /app working directory +# Copy package.json and yarn.lock to the working directory COPY package*.json yarn.lock ./ -# Install dependencies in /app +# Install Node.js dependencies RUN yarn install --network-timeout 1000000 -# Copy the rest of our Next.js folder into /app +# Copy the rest of the Next.js folder into /app COPY . . # Build the Next.js application RUN yarn build +# Second stage: Runtime environment +FROM node:18.13.0-alpine + +# Copy the virtual environment from the builder stage +COPY --from=builder /venv /venv +ENV PATH="/venv/bin:$PATH" + +# Set the working directory +WORKDIR /app + +# Copy built assets from the builder stage +COPY --from=builder /app/.next ./.next +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/public ./public + # Ensure port 3000 is accessible to our system EXPOSE 3000 -# Run yarn start, as we would via the command line +# Run yarn start, as we would via the command line CMD ["yarn", "start"]