Dockerfile
Table of Contents
- What is a Dockerfile?
- Core Dockerfile Instructions
- Putting It Together: Example Dockerfile
- Building and Running a Custom Image
A Dockerfile is the foundational building block for creating custom Docker images. In this section, we'll break down what a Dockerfile is, explore essential instructions, contrast similar commands (like COPY vs ADD and CMD vs ENTRYPOINT), and demonstrate how to build and run custom images.
1. What is a Dockerfile?
A Dockerfile is a text document containing a sequential list of instructions that Docker executes to assemble a custom image. It automates the entire image creation process, ensuring builds are reproducible and version-controlled.
2. Core Dockerfile Instructions
-
FROMSets the base image for subsequent instructions. Every valid Dockerfile must start with aFROMinstruction.FROM node:20-alpine -
WORKDIRSets the working directory inside the container for any subsequentRUN,CMD,ENTRYPOINT,COPY, orADDinstructions. If the directory doesn't exist, Docker creates it automatically.WORKDIR /app -
COPYvsADDBoth instructions transfer files from thehost machineinto thecontainer image, but they have distinct differences:-
COPY: Copies local files and directories from thebuild contextinto the image. (Recommended for almost all use cases). -
ADD: Includes extra features like auto-extracting local tar archives (.tar.gz) and fetching files directly from remote URLs.
# Standard file copy (Best Practice) COPY package.json package-lock.json ./ # Auto-extracting a local tar archive ADD archive.tar.gz /extracted-files/ -
-
RUNExecutes commands during the build phase to install packages, create files, or set up dependencies. EachRUNinstruction creates a new read-only image layer.# Chain commands with && to reduce image layer count RUN apt-get update && apt-get install -y \ curl \ git \ && rm -rf /var/lib/apt/lists/* -
ENVvsARGBoth define variables during the image lifecycle, but they operate at different stages:Instruction Scope Persistence Example Use Case ARGBuild time only Not available in running Passing version tags, build flags ENVBuild time & Persists inside running Database host, application environment # Available only during 'docker build' ARG BUILD_VERSION=1.0.0 # Persists in the container at runtime ENV NODE_ENV=production ENV PORT=3000 -
EXPOSEInforms Docker that the container listens on specific network ports at runtime. Note:EXPOSEacts as documentation between the image creator and user—it does not actually publish the port on the host.EXPOSE 3000 -
CMDvsENTRYPOINTBoth specify the command executed when a container starts, but they behave differently when overridden:CMD: Sets default arguments or commands that can be easily overridden from the command line.ENTRYPOINT: Configures a container to run as an executable. Command-line arguments passed todocker runare appended toENTRYPOINTrather than replacing it.
# CMD example: easily overridden by passing a command to 'docker run' CMD ["node", "server.js"] # ENTRYPOINT + CMD pattern: ENTRYPOINT sets fixed executable, CMD sets default argument ENTRYPOINT ["node"] CMD ["server.js"]
3. Putting It Together: Example Dockerfile
Here is a complete, production-ready Dockerfile for a Node.js application:
# 1. Base image
FROM node:20-alpine
# 2. Build-time argument and runtime environment
ARG BUILD_DATE
LABEL org.opencontainers.image.created=$BUILD_DATE
ENV NODE_ENV=production
# 3. Set working directory
WORKDIR /app
# 4. Copy dependency definitions first (for layer caching)
COPY package*.json ./
# 5. Install dependencies
RUN npm ci --only=production
# 6. Copy application code
COPY . .
# 7. Document exposed port
EXPOSE 3000
# 8. Set default runtime command
CMD ["npm", "start"]
4. Building and Running a Custom Image
Build the Image (docker build)
Use docker build with the -t (tag) flag to name your image, pointing to the build context directory (usually .):
# Build image tagged 'my-app:v1' using current directory context
docker build -t my-app:v1 .
# Build passing a build argument
docker build --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') -t my-app:v1 .
Run the Custom Container (docker run)
Instantiate a container from your newly built custom image:
# Run detached, map host port 8080 to container port 3000
docker run -d --name my-running-app -p 8080:3000 my-app:v1
Buy Me a Coffee
Found this tutorial helpful? Consider buying me a coffee to support more free content!