Skip to content

Latest commit

 

History

History
193 lines (118 loc) · 5.89 KB

005-dockerfile.md

File metadata and controls

193 lines (118 loc) · 5.89 KB

Chapter 5: What is a Dockerfile

A Dockerfile is a text document that contains a series of instructions and arguments. These instructions are used to create a Docker image automatically. It's essentially a script of successive commands Docker will run to assemble an image, automating the image creation process.

Anatomy of a Dockerfile

A Dockerfile typically consists of the following components:

  1. Base image declaration
  2. Metadata and label information
  3. Environment setup
  4. File and directory operations
  5. Dependency installation
  6. Application code copying
  7. Execution command specification

Let's dive deep into each of these components and the instructions used to implement them.

Dockerfile Instructions

FROM

The FROM instruction initializes a new build stage and sets the base image for subsequent instructions.

FROM ubuntu:20.04

This instruction is typically the first one in a Dockerfile. It's possible to have multiple FROM instructions in a single Dockerfile for multi-stage builds.

LABEL

LABEL adds metadata to an image in key-value pair format.

LABEL version="1.0" maintainer="[email protected]" description="This is a sample Docker image"

Labels are useful for image organization, licensing information, annotations, and other metadata.

ENV

ENV sets environment variables in the image.

ENV APP_HOME=/app NODE_ENV=production

These variables persist when a container is run from the resulting image.

WORKDIR

WORKDIR sets the working directory for any subsequent RUN, CMD, ENTRYPOINT, COPY, and ADD instructions.

WORKDIR /app

If the directory doesn't exist, it will be created.

COPY and ADD

Both COPY and ADD instructions copy files from the host into the image.

COPY package.json .
ADD https://example.com/big.tar.xz /usr/src/things/

COPY is generally preferred for its simplicity. ADD has some extra features like tar extraction and remote URL support, but these can make build behavior less predictable.

RUN

RUN executes commands in a new layer on top of the current image and commits the results.

RUN apt-get update && apt-get install -y nodejs

It's a best practice to chain commands with && and clean up in the same RUN instruction to keep layers small.

CMD

CMD provides defaults for an executing container. There can only be one CMD instruction in a Dockerfile.

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

CMD can be overridden at runtime.

ENTRYPOINT

ENTRYPOINT configures a container that will run as an executable.

ENTRYPOINT ["nginx", "-g", "daemon off;"]

ENTRYPOINT is often used in combination with CMD, where ENTRYPOINT defines the executable and CMD supplies default arguments.

EXPOSE

EXPOSE informs Docker that the container listens on specified network ports at runtime.

EXPOSE 80 443

This doesn't actually publish the port; it functions as documentation between the person who builds the image and the person who runs the container.

VOLUME

VOLUME creates a mount point and marks it as holding externally mounted volumes from native host or other containers.

VOLUME /data

This is useful for any mutable and/or user-serviceable parts of your image.

ARG

ARG defines a variable that users can pass at build-time to the builder with the docker build command.

ARG VERSION=latest

This allows for more flexible image builds.

Best Practices for Writing Dockerfiles

  1. Use multi-stage builds: This helps create smaller final images by separating build-time dependencies from runtime dependencies.
FROM node:14 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
  1. Minimize the number of layers: Combine commands where possible to reduce the number of layers and image size.

  2. Leverage build cache: Order instructions from least to most frequently changing to maximize build cache usage.

  3. Use .dockerignore: Exclude files not relevant to the build, similar to .gitignore.

  4. Don't install unnecessary packages: Keep the image lean and secure by only installing what's needed.

  5. Use specific tags: Avoid latest tag for base images to ensure reproducible builds.

  6. Set the WORKDIR: Always use WORKDIR instead of proliferating instructions like RUN cd … && do-something.

  7. Use COPY instead of ADD: Unless you explicitly need the extra functionality of ADD, use COPY for transparency.

  8. Use environment variables: Especially for version numbers and paths, making the Dockerfile more flexible.

Advanced Dockerfile Concepts

Health Checks

You can use the HEALTHCHECK instruction to tell Docker how to test a container to check that it's still working.

HEALTHCHECK --interval=30s --timeout=10s CMD curl -f http://localhost/ || exit 1

Shell and Exec Forms

Many Dockerfile instructions can be specified in shell form or exec form:

  • Shell form: RUN apt-get install python3
  • Exec form: RUN ["apt-get", "install", "python3"]

The exec form is preferred as it's more explicit and avoids issues with shell string munging.

BuildKit

BuildKit is a new backend for Docker builds that offers better performance, storage management, and features. You can enable it by setting an environment variable:

export DOCKER_BUILDKIT=1

Conclusion

Dockerfiles are a powerful tool for creating reproducible, version-controlled Docker images. By mastering Dockerfile instructions and best practices, you can create efficient, secure, and portable applications. Remember that writing good Dockerfiles is an iterative process – continually refine your Dockerfiles as you learn more about your application's needs and Docker's capabilities.