Skip to main content

Building Images with Dockerfile

1. Creating Dockerfile

Directive Description Example
FROM Sets the base image for subsequent instructions FROM ubuntu:20.04
RUN Executes commands in a new layer on top of the current image RUN apt-get update && apt-get install -y nodejs
COPY Copies files from <src> to the container filesystem COPY . /app
ADD Similar to COPY but also supports remote URLs and auto-extraction ADD https://example.com/file.tar.gz /app/
WORKDIR Sets the working directory for subsequent instructions WORKDIR /app
EXPOSE Documents which ports the application listens on at runtime EXPOSE 8080
CMD Provides the default command to run when a container starts CMD ["npm", "start"]
ENTRYPOINT Sets the command that runs when a container starts (without arguments) ENTRYPOINT ["/bin/sh", "-c"]

Example: Basic Dockerfile

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

2. Setting Working Directory

Directive Description Usage Notes
WORKDIR Sets the working directory for subsequent RUN, CMD, ENTRYPOINT, COPY, and ADD instructions. WORKDIR /app Can be used multiple times in a Dockerfile. Paths are absolute.

Example: Setting Working Directory

FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Note: The working directory is set to /app and all subsequent commands will run relative to this path.

3. Using COPY vs ADD Instructions

Feature COPY ADD
Source Local files or directories Local files, directories, or remote URLs
Destination Container filesystem path Container filesystem path
Compression Handling No automatic decompression Automatically decompresses .tar.gz and .tgz files
URL Support No Yes, supports HTTP/HTTPS URLs
Symlink Preservation No Preserves symlinks from source
Security More secure, no automatic extraction Less secure due to potential auto-extraction

Example: COPY usage

COPY ./app.js /usr/src/app/
COPY ./config.json /usr/src/app/config.json

Example: ADD usage with URL

ADD https://example.com/file.tar.gz /app/
RUN tar -xzf /app/file.tar.gz -C /app/
Note: Use COPY for local files and directories, and ADD only when you need to extract compressed archives or fetch from remote URLs.

4. Defining Environment Variables

Directive Description Example
ENV Sets environment variables for the container
ENV NODE_ENV=production
ENV PORT=3000
ARG Sets build-time variables that are not available at runtime
ARG BUILD_VERSION=1.0
ENV VERSION=$BUILD_VERSION

Example: Setting Environment Variables

FROM node:18
ENV NODE_ENV=production
ENV PORT=3000
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE $PORT
CMD ["node", "server.js"]
Note: Environment variables set with ENV are available at runtime, while ARG variables are only available during the build process.
Warning: Avoid hardcoding sensitive information like passwords in ENV directives. Use secrets or external configuration instead.

5. Defining Build Arguments

Directive Description Example
ARG Defines a build-time variable that can be passed during the build process. ARG VERSION=latest
ARG Can be overridden at build time using --build-arg. ARG NODE_VERSION=18

Example: Using ARG in Dockerfile

FROM node:${NODE_VERSION}
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Note: Build arguments are not persisted in the final image and are only available during the build process.

6. Exposing Ports

Directive Format Description Notes
EXPOSE EXPOSE <port> [<port> ...] Documents which ports the application listens on Does not actually publish the port, only informs Docker about intended exposure

Example: EXPOSE directive usage

FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Note: The EXPOSE instruction does not actually publish the port. It's a documentation hint to users of the image and tools like Docker Compose.
Warning: To actually publish a port when running the container, use the -p or --publish flag with docker run.

Key Points

  • EXPOSE is a hint to Docker and users about port exposure
  • Does not publish or bind ports in the container
  • Use -p flag during docker run to publish ports
  • Can specify multiple ports in one EXPOSE instruction

7. Setting User Context

Directive Description Usage
USER Sets the user for subsequent RUN, CMD, ENTRYPOINT, and EXEC instructions. USER <user>[:<group>]
USER Can also accept a UID/GID instead of user/group names. USER <UID>[:<GID>]

Example: Setting User Context

FROM alpine:latest
RUN adduser -D -s /bin/sh appuser
USER appuser
WORKDIR /home/appuser
CMD ["sh"]
Note: Setting the user context to a non-root user improves security by reducing the privileges of the container process.

8. Adding Labels

Label Key Value Description
org.opencontainers.image.title "MyApp" Human-readable title of the image
org.opencontainers.image.version "v1.2.3" Version of the image
org.opencontainers.image.description "A sample application" Short description of the image
org.opencontainers.image.authors "John Doe <john@example.com>" Image authors
org.opencontainers.image.licenses "MIT" License for the image content

Example: Adding Labels in Dockerfile

FROM ubuntu:20.04
LABEL org.opencontainers.image.title="MyApp"
LABEL org.opencontainers.image.version="v1.2.3"
LABEL org.opencontainers.image.description="A sample application"
LABEL org.opencontainers.image.authors="John Doe <john@example.com>"
LABEL org.opencontainers.image.licenses="MIT"
CMD ["echo", "Hello World"]
Note: Labels are stored as key-value pairs and can be used for metadata, version tracking, or compliance purposes.

9. Using ENTRYPOINT vs CMD

Directive Behavior Usage Notes
ENTRYPOINT Configures the container's main command. It cannot be overridden by command-line arguments. Use for setting a fixed command that should always run. Can be overridden with --entrypoint in docker run.
CMD Provides a default command to run when the container starts. It can be overridden by command-line arguments. Use for flexible default commands that can be customized at runtime. If multiple CMDs are specified, only the last one is used.

Example: ENTRYPOINT and CMD together

FROM ubuntu:20.04
ENTRYPOINT ["/bin/bash"]
CMD ["-c", "echo \"Hello from bash\""]

Example: Override CMD with arguments

docker run my-image "echo \"Custom command\""

Example: Override ENTRYPOINT with --entrypoint

docker run --entrypoint /bin/sh my-image -c "echo \"Overridden entrypoint\""

Key Differences Summary

  • ENTRYPOINT: Fixed command, cannot be overridden by arguments.
  • CMD: Default command, can be overridden at runtime.
  • Both can be used together, with CMD providing default arguments to ENTRYPOINT.

10. Configuring Healthchecks

Directive Description Example
HEALTHCHECK Defines how to test if the container is healthy HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD curl -f http://localhost:8080/health || exit 1

Example: Basic Healthcheck

HEALTHCHECK CMD curl -f http://localhost:8080/health || exit 1

Example: Healthcheck with Options

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 CMD curl -f http://localhost:8080/health || exit 1
Note: The healthcheck command must return an exit code of 0 for success, or non-zero for failure.

Healthcheck Configuration Options

  • --interval=<duration>: Time between health checks (default: 30s)
  • --timeout=<duration>: Maximum time to wait for a check (default: 30s)
  • --start-period=<duration>: Grace period before starting checks (default: 0s)
  • --retries=<number>: Number of consecutive failures to mark container as unhealthy (default: 3)

11. Handling .dockerignore Files

Rule Description Example
.dockerignore File that specifies files and folders to exclude from the build context
node_modules
*.log
.git
.DS_Store
Build context Directory containing the Dockerfile and files to be sent to Docker daemon Only files not matching .dockerignore patterns are included

Example: .dockerignore usage

# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.DS_Store
Note: .dockerignore works similarly to .gitignore but is used during Docker build, not version control.

12. Building Images

Instruction Description Example
FROM Sets the base image for subsequent instructions FROM ubuntu:20.04
RUN Executes commands in a new layer on top of the current image RUN apt-get update && apt-get install -y nginx
COPY Copies files from <src> to the container filesystem COPY . /app
ADD Similar to COPY but supports remote URLs and auto-extraction ADD https://example.com/file.tar.gz /app/
WORKDIR Sets the working directory for subsequent instructions WORKDIR /app
EXPOSE Documents which ports the application listens on at runtime EXPOSE 8080
ENV Sets environment variables in the container ENV NODE_ENV=production
CMD Provides the default command to run when starting a container CMD ["npm", "start"]
ENTRYPOINT Sets the command that runs when a container starts ENTRYPOINT ["/usr/bin/python3"]
VOLUME Creates a mount point and marks it as holding externally mounted volumes VOLUME ["/data"]

Example: Basic Dockerfile

FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Note: Each instruction creates a new layer in the image. Minimize layers by combining RUN commands where possible.

Was this article helpful?