Dockerfile Writing Lab

Lab 1: The Foundation (Basic Web Server)

Goal: Create a simple Nginx server that displays a custom HTML page. This introduces FROM, COPY, and EXPOSE.

Step 1: Create a file named index.html

<h1>Hello from Docker!</h1>

Step 2: Create a file named Dockerfile

# Step 1: Base Image (The OS)
FROM nginx:alpine

# Step 2: Metadata (Good practice)
LABEL maintainer="devsecops-guru"

# Step 3: Copy your web page to the server's default folder
COPY index.html /usr/share/nginx/html/index.html

# Step 4: Documentation (Tell humans this port is needed)
EXPOSE 80

# Note: Nginx has a default CMD, so we don't need to write it!

Step 3: Build and Run

docker build -t my-web-server .
docker run -p 8080:80 my-web-server
  • Test: Open your browser to localhost:8080. You should see “Hello from Docker!”.

Lab 2: The Optimizer (Layer Caching)

Goal: Understand why the order of instructions matters for speed.

Step 1: Create a python file app.py

print("Hello World")

Step 2: Create a requirement file requirements.txt

flask

Step 3: The “Bad” Dockerfile (Write this first)

FROM python:3.9-slim
WORKDIR /app
COPY . . 
# ^ PROBLEM: If you change code, cache breaks here!
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

Step 4: The “Good” Dockerfile (Write this second)

FROM python:3.9-slim
WORKDIR /app

# 1. Copy only files needed for installation first
COPY requirements.txt .

# 2. Install dependencies (This layer is now cached!)
RUN pip install -r requirements.txt

# 3. NOW copy the rest of the source code
COPY . .

CMD ["python", "app.py"]

Activity:

  1. Build the “Good” Dockerfile.
  2. Change one word in app.py.
  3. Build it again.
  4. Notice that RUN pip install says ---> Using cache. It didn’t run again! This saves huge time in big projects.

Lab 3: The Architect (Multi-Stage Build)

Goal: Build a Go application. Go needs a compiler (heavy), but the final app is just a binary (tiny). We will throw away the compiler.

Step 1: Create a Go program main.go

package main
import "fmt"
func main() {
    fmt.Println("I am a tiny container!")
}

Step 2: Create the Multi-Stage Dockerfile

# ----------------------------
# STAGE 1: The Builder (Heavy)
# ----------------------------
FROM golang:1.19-alpine AS builder

WORKDIR /app

# Copy source code
COPY main.go .

# Compile the code to a binary named "my-app"
RUN go build -o my-app main.go

# ----------------------------
# STAGE 2: The Runner (Tiny)
# ----------------------------
FROM alpine:latest

WORKDIR /root/

# Copy ONLY the binary from the "builder" stage
COPY --from=builder /app/my-app .

# Command to run the binary
CMD ["./my-app"]

Step 3: Verify the Size

  1. Build it: docker build -t tiny-go .
  2. Check size: docker images
  3. Result: You will see the image is roughly 10MB. If you didn’t use multi-stage, it would be 800MB+.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top