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: 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 | |
| ARG | Sets build-time variables that are not available at runtime | |
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
EXPOSEis a hint to Docker and users about port exposure- Does not publish or bind ports in the container
- Use
-pflag duringdocker runto publish ports - Can specify multiple ports in one
EXPOSEinstruction
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 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: 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 | |
| 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.