Skip to main content

Images & Dockerfiles

Complete guide to Docker image management, Dockerfile creation, and building best practices.

Image Management

Basic Image Operations

# Pull an image
docker pull nginx:latest

# Build an image
docker build -t myapp:latest .

# Build with custom Dockerfile
docker build -f Dockerfile.prod -t myapp:prod .

# Push to registry
docker push myapp:latest

# List images
docker images

# Remove image
docker rmi myapp:latest

# Remove unused images
docker image prune

# Remove all unused images
docker image prune -a

Image Information

# Inspect image
docker inspect myapp:latest

# Show image history
docker history myapp:latest

# Show image layers
docker inspect myapp:latest | grep -A 10 "RootFS"

# Tag an image
docker tag myapp:latest myapp:v1.0

# Save image to tar file
docker save myapp:latest > myapp.tar

# Load image from tar file
docker load < myapp.tar

Dockerfile Reference

Basic Structure

# Base image
FROM node:18-alpine

# Set working directory
WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy source code
COPY . .

# Expose port
EXPOSE 3000

# Set environment variables
ENV NODE_ENV=production

# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# Change ownership
RUN chown -R nextjs:nodejs /app
USER nextjs

# Define entrypoint
ENTRYPOINT ["npm", "start"]

Dockerfile Instructions

FROM

# Use specific tags, not 'latest'
FROM node:18.17-alpine

# Use official images
FROM nginx:1.24-alpine

# Multi-stage build base
FROM node:18-alpine AS builder

WORKDIR

# Set working directory
WORKDIR /app

# Multiple working directories
WORKDIR /app/src
WORKDIR /data

COPY vs ADD

# COPY - preferred for simple file copying
COPY package*.json ./
COPY src/ ./src/

# ADD - has additional features (auto-extract, URLs)
ADD https://example.com/file.tar.gz /tmp/
ADD archive.tar.gz /extracted/ # Auto-extracts

RUN

# Minimize layers by combining commands
RUN apt-get update && apt-get install -y \
curl \
vim \
git \
&& rm -rf /var/lib/apt/lists/*

# Use cache mounts for package managers
RUN --mount=type=cache,target=/var/cache/apt \
apt-get update && apt-get install -y curl

# Install Node.js dependencies with cache
RUN --mount=type=cache,target=/root/.npm \
npm ci --only=production

USER

# Create and switch to non-root user
RUN addgroup -g 1001 -S appgroup
RUN adduser -S appuser -u 1001 -G appgroup
USER appuser

# Switch back to root if needed
USER root
RUN apt-get update
USER appuser

ENV & ARG

# Build-time variables
ARG NODE_VERSION=18
ARG BUILD_DATE

# Runtime environment variables
ENV NODE_ENV=production
ENV PORT=3000
ENV PATH="/app/bin:$PATH"

# Use ARG in FROM
ARG NODE_VERSION=18
FROM node:${NODE_VERSION}-alpine

# Use ARG as ENV
ARG API_URL
ENV API_URL=$API_URL

EXPOSE

# Document exposed ports
EXPOSE 3000
EXPOSE 8080/tcp
EXPOSE 53/udp

VOLUME

# Create mount points
VOLUME ["/data", "/logs"]
VOLUME /var/lib/mysql

HEALTHCHECK

# Health check configuration
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1

# Disable health check
HEALTHCHECK NONE

Multi-Stage Builds

Basic Multi-Stage

# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# Test stage
FROM builder AS tester
RUN npm ci
COPY . .
RUN npm test

# Production stage
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
USER node
CMD ["npm", "start"]

Advanced Multi-Stage

# Dependencies stage
FROM node:18-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Runtime stage
FROM node:18-alpine AS runtime
WORKDIR /app
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
COPY --from=deps --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
USER nextjs
EXPOSE 3000
CMD ["node", "dist/index.js"]

Building Specific Stages

# Build only the builder stage
docker build --target builder -t myapp:builder .

# Build production stage
docker build --target production -t myapp:prod .

# Build with build args
docker build --build-arg NODE_ENV=production -t myapp .

# Build with cache from another image
docker build --cache-from myapp:latest -t myapp:new .

Dockerfile Best Practices

Optimization Techniques

# 1. Use specific base image tags
FROM node:18.17-alpine # ✓ Specific
FROM node:latest # ✗ Unstable

# 2. Minimize layers
RUN apt-get update && apt-get install -y curl vim \
&& rm -rf /var/lib/apt/lists/* # ✓ Single layer

RUN apt-get update # ✗ Multiple layers
RUN apt-get install -y curl
RUN apt-get install -y vim

# 3. Order instructions by change frequency
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./ # Changes less frequently
RUN npm ci
COPY . . # Changes more frequently

# 4. Use .dockerignore
# Create .dockerignore file:
# node_modules
# .git
# .env
# *.log

Security Best Practices

# Use minimal base images
FROM alpine:3.18
FROM distroless/nodejs18

# Don't run as root
FROM node:18-alpine
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs

# Don't store secrets in images
# ✗ Bad
ENV API_KEY=secret123

# ✓ Good - use runtime secrets
ENV API_KEY_FILE=/run/secrets/api_key

# Keep images up to date
FROM node:18.17-alpine # Use specific, recent versions
RUN apk update && apk upgrade

.dockerignore

# Dependencies
node_modules
npm-debug.log*

# Build outputs
dist
build
.next

# Development
.git
.gitignore
README.md
Dockerfile*
.dockerignore

# IDE
.vscode
.idea

# OS
.DS_Store
Thumbs.db

# Logs
*.log

# Environment
.env
.env.local
.env.*.local

Build Context & Performance

Optimizing Build Context

# Check build context size
docker build --no-cache --progress=plain .

# Build with specific context
docker build -f Dockerfile.prod ./app

# Build from stdin
docker build -t myapp - < Dockerfile

Build Arguments

# Pass build arguments
docker build --build-arg NODE_ENV=production \
--build-arg VERSION=1.0.0 \
-t myapp:1.0.0 .

# Use build arguments in Dockerfile
ARG NODE_ENV=development
ARG VERSION
ENV APP_VERSION=$VERSION

Build Cache

# Disable cache
docker build --no-cache -t myapp .

# Use cache from specific image
docker build --cache-from myapp:latest -t myapp:new .

# Use BuildKit for advanced caching
DOCKER_BUILDKIT=1 docker build -t myapp .

Quick Reference

Essential Commands

  • docker build -t name . - Build image
  • docker images - List images
  • docker rmi image - Remove image
  • docker tag source target - Tag image
  • docker push image - Push to registry
  • docker pull image - Pull from registry

Best Practices

  • Use specific base image tags
  • Leverage multi-stage builds
  • Minimize layers and image size
  • Use .dockerignore effectively
  • Don't run containers as root
  • Keep base images updated
  • Cache package installations