Fastify + Distroless + Multi-Stage Builds = 🤯

David
3 min readFeb 28, 2023

--

In the previous blog posts here and here, we described how to run a simple “hello world” HTTP server using Fastify inside a Docker container in Node.js and then how to update the Dockerfile to use a distroless Node.js base image. In this third part, we will explain the benefits of using a multi-stage distroless Dockerfile and how to update the basic Dockerfile to a multi-stage distroless Dockerfile.

Docker multi-stage builds allow you to use multiple FROM statements in a single Dockerfile to create multiple stages for building your container image. Each stage can have its own dependencies, environment variables, and build instructions. Using a multi-stage build can help you reduce the size of your container images by eliminating unused dependencies and files.

Prerequisites

Create a new Dockerfile

First, create a new file called Dockerfile.multistage in the root of your project directory. This file will contain the instructions for building your Docker image using a multi-stage distroless base image.

# Stage 1: Build the application
FROM node:16-alpine as builder

WORKDIR /app

COPY package*.json ./

RUN npm install --production

# Stage 2: Create the production image
FROM gcr.io/distroless/nodejs:16

ENV ADDRESS=0.0.0.0 PORT=3000

WORKDIR /app

COPY package*.json ./

COPY --from=builder /app/node_modules .

COPY . .

CMD ["node", "index.js"]

This Dockerfile contains two stages:

  • Stage 1: Build the application
  • Stage 2: Create the production image

In stage 1, we use the official Node.js 16-alpine image as our base image, set the working directory to /app, copy the package*.json files to the working directory, install dependencies using npm, copy the rest of the files to the working directory, and run the npm run build command. This stage is responsible for building our application.

In stage 2, we use the distroless Node.js 16 image as our base image, set the working directory to /app, copy the node_modules from the previous stage to the working directory and set the default command to run the node index.js command. This stage is responsible for creating the production image.

Note that we’re using the --from=builder flag in the COPY command to copy the dist directory from the previous stage to the current stage.

Build the Docker image

Now that you have created the Dockerfile.multistage, you can use it to build a Docker image. Run the following command in your terminal:

docker build -f Dockerfile.multistage -t fastify-multistage .

This command tells Docker to build an image using the instructions in the Dockerfile.multistage and tag it with the name fastify-multistage.

Run the Docker container

Finally, you can run the Docker container using the multi-stage distroless-based image you just built. Run the following command in your terminal:

docker run -p 3000:3000 fastify-multistage

This command tells Docker to run a container using the fastify-multistage image and map port 3000 inside the container to port 3000 on your local machine.

Congratulations! Similarly to our other blog posts, you can now open http://localhost:3000 in your browser to see a response from the server.

--

--

David

Coding is both my hobby and my job. I love writing about things I'm working on ❤️