Lesson 2: The Assembly Line (Writing Dockerfiles)
A Dockerfile is the recipe that tells Docker how to build an image. It's a simple text file with step-by-step instructions — like an assembly line for your application.
Dockerfile Anatomy
# Start from a base image
FROM node:18-alpine
# Set the working directory inside the container
WORKDIR /app
# Copy dependency files first (for caching)
COPY package*.json ./
# Install dependencies
RUN npm install --production
# Copy the rest of the application
COPY . .
# Expose the port the app listens on
EXPOSE 3000
# Define the startup command
CMD ["node", "server.js"]
Dockerfile Instructions
| Instruction | Purpose | Example |
|-------------|---------|---------|
| FROM | Base image to start from | FROM python:3.11-slim |
| WORKDIR | Set the working directory | WORKDIR /app |
| COPY | Copy files from host to image | COPY . . |
| ADD | Like COPY, but handles URLs and archives | ADD archive.tar.gz /opt/ |
| RUN | Execute a command during build | RUN apt-get install -y curl |
| ENV | Set environment variables | ENV NODE_ENV=production |
| EXPOSE | Document which port the app uses | EXPOSE 8080 |
| CMD | Default command when container starts | CMD ["python", "app.py"] |
| ENTRYPOINT | Fixed command (CMD becomes arguments) | ENTRYPOINT ["python"] |
Building an Image
docker build -t my-app:v1 .
-t my-app:v1— Tag (name) the image..— The build context (current directory).
The Order Matters (Layer Caching)
Docker caches each layer. If a layer hasn't changed, Docker skips rebuilding it. This means order your Dockerfile from least-changing to most-changing:
# ✅ GOOD: Dependencies change rarely, code changes often
COPY package.json ./ # Layer 1: Rarely changes
RUN npm install # Layer 2: Cached if package.json unchanged
COPY . . # Layer 3: Changes with every edit
# ❌ BAD: Busts cache on every code change
COPY . . # Layer 1: Changes every time
RUN npm install # Layer 2: Rebuilt every time too!
CMD vs. ENTRYPOINT
| | CMD | ENTRYPOINT |
|---|-----|-----------|
| Can be overridden? | Yes, by docker run args | No (args are appended) |
| Use case | Default command | Fixed executable |
# CMD: Overridable
CMD ["python", "app.py"]
# docker run my-app python test.py ← overrides CMD
# ENTRYPOINT: Fixed
ENTRYPOINT ["python"]
CMD ["app.py"]
# docker run my-app test.py ← runs "python test.py"
Mission Objective
Build your first Docker image:
- Write the recipe: Create a Dockerfile with
touch Dockerfile. - Build it: Run
docker build -t my-app:v1 .to build your image. - Run it: Launch your container with
docker run my-app:v1.