Dockerize a Project

A practical guide to packaging real-world applications into Docker containers — the hands-on bridge between Docker Fundamentals and Kubernetes orchestration.

What is Dockerization?

Dockerization is the process of packaging an application and all its dependencies into a Docker image so it can run consistently anywhere. It eliminates the “works on my machine” problem by ensuring the runtime environment is identical across development, staging, and production.

The Dockerfile Anatomy

A Dockerfile is a text document containing instructions to build a Docker image. Each instruction creates a cached layer.

# ─── Stage 1: Builder ───
FROM node:18-alpine AS builder
 
WORKDIR /app
 
# Copy dependency files first (for layer caching)
COPY package*.json ./
RUN npm ci --only=production
 
# Copy source and build
COPY . .
RUN npm run build
 
# ─── Stage 2: Runtime ───
FROM node:18-alpine
 
WORKDIR /app
 
# Create non-root user for security
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nextjs -u 1001
 
# Copy only built artifacts from builder stage
COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json
 
USER nextjs
 
EXPOSE 3000
 
ENV NODE_ENV=production
 
CMD ["node", "dist/main.js"]

Key Instructions

InstructionPurposeExample
FROMBase image to start fromFROM node:18-alpine
WORKDIRSet working directory inside containerWORKDIR /app
COPYCopy files from host to containerCOPY package*.json ./
RUNExecute commands during buildRUN npm install
EXPOSEDocument which port the container listens onEXPOSE 3000
ENVSet environment variablesENV NODE_ENV=production
USERRun as non-root userUSER nextjs
CMDDefault command when container startsCMD ["node", "server.js"]
ENTRYPOINTConfigure container as executableENTRYPOINT ["python", "app.py"]

The Dockerize Workflow

  1. Create a .dockerignore — exclude node_modules, .git, build artifacts, large data files.
  2. Write the Dockerfile — choose a slim base image, set WORKDIR, order instructions for cache efficiency.
  3. Build the imagedocker build -t myapp:1.0 .
  4. Test locallydocker run -d -p 8080:3000 myapp:1.0
  5. Push to registrydocker push registry.example.com/myapp:1.0

Layer Caching & Optimization

  • Docker builds images in layers — each instruction creates a cached layer.
  • If a layer changes, all subsequent layers must be rebuilt.
  • Golden Rule: Copy dependency files (package.json, requirements.txt, pom.xml) before the full source code so dependency installation is cached and only rebuilds when dependencies change.
# ✅ Good — dependencies cached unless package.json changes
COPY package*.json ./
RUN npm ci
COPY . .
 
# ❌ Bad — any source change invalidates the npm install cache
COPY . .
RUN npm install

Multi-Stage Builds

Multi-stage builds allow you to use multiple FROM statements in a single Dockerfile, copying only what you need into the final image.

Benefits:

  • Smaller final image size (no build tools in production image)
  • Reduced attack surface
  • Faster deployments
# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
 
# Runtime stage
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]

Common Pitfalls

PitfallWhy It MattersFix
No .dockerignoreBloated build context, slow builds, leaked secretsAdd .dockerignore with node_modules, .env, .git
Using latest tagNon-reproducible builds, unexpected breakagesPin to specific versions: node:18-alpine
Running as rootSecurity risk if container is compromisedUse USER instruction or run with --user flag
Hardcoded configLimits portability across environmentsUse ENV variables and config files mounted at runtime
Ignoring signalsContainers don’t shut down gracefullyUse exec in entrypoint scripts so PID 1 receives SIGTERM
Large imagesSlower pulls, more storage, larger attack surfaceUse Alpine or Distroless base images; multi-stage builds

Essential Build & Run Commands

CommandPurpose
docker build -t myapp:1.0 .Build image with tag from current directory
docker run -d -p 8080:3000 myapp:1.0Run container in detached mode, map ports
docker run -it --rm myapp:1.0 /bin/shInteractive shell access, auto-remove on exit
docker logs <container_id>View application logs
docker exec -it <container_id> /bin/shShell into a running container
docker inspect <image_id>Inspect image layers and metadata

Sources


Tags: docker dockerfile containerization devops cka multi-stage-builds