The Dockerfile
Divio uses dockerised applications. Each Docker image is defined by a Dockerfile
, that describes what is in the image and how containers created from it should be built.
The Dockerfile is simply a text document, containing all the commands that would be issued on the command-line to build an image - in short, the Dockerfile
defines an environment.
The Dockerfile is built automatically, and populated with appropriate commands (see below). However, you can also add any commands you wish to the Dockerfile
, for example to install system packages, or to configure the environment.
The Dockerfile
executes its commands in sequence. This means that commands to install Node (for example) must come before commands to run Node packages.
Example Dockerfile
The following example is taken from our Getting Started with Next.js template:
FROM node:lts-alpine
ENV NODE_PATH=/app/node_modules
WORKDIR /app
COPY package*.json /app/
RUN npm install
COPY . /app
RUN npm run build
EXPOSE 80
CMD ["npm", "start", "--", "-p", "80"]
This Dockerfile is designed to create a Docker container that is ready to run a Node.js application, with all dependencies installed and ports configured to expose the app on port 80. Here's a step-by-step explanation of that Dockerfile:
-
FROM node:20.14
This line specifies the base image to use for the Docker container. It uses a specific version (20.14) of the official Node.js Docker image. We recommend to specifically pin your versions. -
ENV NODE_PATH=/app/node_modules
Sets an environment variable within the container.NODE_PATH
is used by Node.js to determine where to look for modules. Here, it is set to/app/node_modules
, which is where the dependencies will be installed. This helps Node.js find installed modules more efficiently. -
WORKDIR /app
Sets the working directory for any RUN, CMD, ENTRYPOINT, COPY, and ADD commands that follow in the Dockerfile. If the directory does not exist, it will be created. All subsequent actions will be performed within this directory. -
COPY package.json /app/
Copies bothpackage.json
andpackage-lock.json
(if present, due to the wildcard patternpackage\*.json
) from your project folder into the /app directory inside the container. This is added separately to cache the installation of packages. -
RUN npm install
Runs npm install inside your container, which installs all the dependencies defined in package.json andpackage-lock.json
. These dependencies will be placed in the/app/node_modules
directory, aligning with theNODE_PATH
set earlier. -
COPY . /app
Copies the rest of your project's files and directories into the/app
directory inside the container. This step is done after installing dependencies to ensure that changes in your source code don’t invalidate the Docker cache of the npm install step. -
RUN npm run build
Executes the build script specified in yourpackage.json
. This command is typically used to compile or transpile the application, prepare it for production by bundling or minifying it. -
EXPOSE 80
Informs Docker that the container listens on port80
at runtime. This is a way of documenting which ports are intended to be published. It doesn’t actually publish the port; it functions as a type of documentation between the person who builds the image and the person who runs the container. -
CMD ["npm", "start", "--", "-p", "80"]
Specifies the command that will be executed when the Docker container starts. Here, it runsnpm start -- -p 80
, which typically starts your Node.js application and specifies that it should run on port80
.
Docker caching
Docker's caching mechanism is designed to speed up image builds by reusing layers from previous builds when possible. When Docker builds an image, it processes each instruction in the Dockerfile sequentially and checks if an identical instruction has been executed in a previous build. If a match is found, Docker uses the cached layer instead of generating a new one.
This caching is particularly effective up to the point where a file has changed (e.g., a COPY command that adds files from the host). After a change is detected, all subsequent layers will be rebuilt. To make the most efficient use of Docker's cache, you should structure your Dockerfile to handle frequently changing steps (like copying source code) after infrequently changing steps (like installing packages).
For more detailed information on Docker's caching strategies, you can refer to the official Docker documentation.