Writing a Dockerfile

Explanation

A Dockerfile is a text-based document that's used to create a container image. It provides instructions to the image builder on the commands to run, files to copy, startup command, and more.

As an example, the following Dockerfile would produce a ready-to-run Python application:

FROM python:3.12
WORKDIR /usr/local/app

# Install the application dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# Copy in the source code
COPY src ./src
EXPOSE 5000

# Setup an app user so the container doesn't run as the root user
RUN useradd app
USER app

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]

Common instructions

Some of the most common instructions in a Dockerfile include:

  • FROM <image> - this specifies the base image that the build will extend.
  • WORKDIR <path> - this instruction specifies the "working directory" or the path in the image where files will be copied and commands will be executed.
  • COPY <host-path> <image-path> - this instruction tells the builder to copy files from the host and put them into the container image.
  • RUN <command> - this instruction tells the builder to run the specified command.
  • ENV <name> <value> - this instruction sets an environment variable that a running container will use.
  • EXPOSE <port-number> - this instruction sets configuration on the image that indicates a port the image would like to expose.
  • USER <user-or-uid> - this instruction sets the default user for all subsequent instructions.
  • CMD ["<command>", "<arg1>"] - this instruction sets the default command a container using this image will run.

To read through all of the instructions or go into greater detail, check out the Dockerfile reference.

Try it out

Just as you saw with the previous example, a Dockerfile typically follows these steps:

  1. Determine your base image
  2. Install application dependencies
  3. Copy in any relevant source code and/or binaries
  4. Configure the final image

In this quick hands-on guide, you'll write a Dockerfile that builds a simple Node.js application. If you're not familiar with JavaScript-based applications, don't worry. It isn't necessary for following along with this guide.

Set up

Download this ZIP file and extract the contents into a directory on your machine.

Creating the Dockerfile

Now that you have the project, you’re ready to create the Dockerfile.

  1. Download and install Docker Desktop.

  2. Create a file named Dockerfile in the same folder as the file package.json.

    Dockerfile file extensions

    It's important to note that the Dockerfile has no file extension. Some editors will automatically add an extension to the file (or complain it doesn't have one).

  3. In the Dockerfile, define your base image by adding the following line:

    FROM node:20-alpine
  4. Now, define the working directory by using the WORKDIR instruction. This will specify where future commands will run and the directory files will be copied inside the container image.

    WORKDIR /app
  5. Copy all of the files from your project on your machine into the container image by using the COPY instruction:

    COPY . .
  6. Install the app's dependencies by using the yarn CLI and package manager. To do so, run a command using the RUN instruction:

    RUN yarn install --production
  7. Finally, specify the default command to run by using the CMD instruction:

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

    And with that, you should have the following Dockerfile:

    FROM node:20-alpine
    WORKDIR /app
    COPY . .
    RUN yarn install --production
    CMD ["node", "./src/index.js"]

This Dockerfile isn't production-ready yet

It's important to note that this Dockerfile is not following all of the best practices yet (by design). It will build the app, but the builds won't be as fast, or the images as secure, as they could be.

Keep reading to learn more about how to make the image maximize the build cache, run as a non-root user, and multi-stage builds.

Containerize new projects quickly with docker init

The docker init command will analyze your project and quickly create a Dockerfile, a compose.yaml, and a .dockerignore, helping you get up and going. Since you're learning about Dockerfiles specifically here, you won't use it now. But, learn more about it here.

Additional resources

To learn more about writing a Dockerfile, visit the following resources:

Next steps

Now that you have created a Dockerfile and learned the basics, it's time to learn about building, tagging, and pushing the images.