Ink&Horizon
HomeBlogTutorialsLanguages
Ink&Horizon— where knowledge meets the horizon —Learn to build exceptional software. Tutorials, guides, and references for developers — from first brushstroke to masterwork.

Learn

  • Blog
  • Tutorials
  • Languages

Company

  • About Us
  • Contact Us
  • Privacy Policy

Account

  • Sign In
  • Register
  • Profile
Ink & Horizon

© 2026 InkAndHorizon. All rights reserved.

Privacy PolicyTerms of Service
Back to Blog
DevOps

Docker 27 for Developers: Containers, Multi-Stage Builds & Security

Dockerfiles, Compose v2, multi-stage builds, security scanning, and production hardening patterns

2026-02-05 22 min read
ContentsDocker 27: What Developers Need to KnowWriting Efficient DockerfilesDocker Compose v2: Multi-Service DevelopmentSecurity Scanning & HardeningKey Takeaways

Docker 27: What Developers Need to Know

Docker 27 is the latest stable release with significant improvements: BuildKit is the default builder (faster, more efficient layer caching), Compose v2 is integrated into the Docker CLI (docker compose instead of docker-compose), and containerd is the default runtime.

As a developer, Docker solves the "it works on my machine" problem by packaging your application with ALL its dependencies into a standardized container. The container runs identically on your laptop, CI server, staging, and production.

The key concepts: a Dockerfile defines how to build an image. An image is a read-only template. A container is a running instance of an image. A volume persists data outside the container lifecycle. A network connects containers.

Key Takeaways

Docker 27: BuildKit default, Compose v2 integrated, containerd runtime.
Image = read-only template. Container = running instance. Volume = persistent data.
Dockerfile → Image (build) → Container (run).
Containers are ephemeral — data lives in volumes, not containers.

Writing Efficient Dockerfiles

A Dockerfile defines the steps to build your image. The order of instructions matters enormously for build speed: Docker caches each layer, and changing one layer invalidates all subsequent layers. Put things that change rarely (OS packages, dependencies) first, and things that change often (your code) last.

The biggest mistake: copying all source code before installing dependencies. This means every code change re-installs all packages. Instead, copy only package.json first, install dependencies, then copy source code.

For production images: use slim/alpine base images (90% smaller), run as non-root user, and set explicit WORKDIR.

Snippet
# ❌ BAD: Code change invalidates dependency cache
FROM node:22
WORKDIR /app
COPY . .                    # Code change → re-installs ALL deps!
RUN npm install
CMD ["node", "dist/server.js"]

# ✅ GOOD: Dependencies cached separately from source
FROM node:22-slim AS builder
WORKDIR /app

# 1. Copy dependency files FIRST (rarely change)
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile

# 2. Copy source code AFTER dependencies (frequently change)
COPY . .
RUN pnpm build

# 3. Production stage — minimal image
FROM node:22-slim
WORKDIR /app

# Security: run as non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser

# Copy only production artifacts
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

# Set non-root user
USER appuser

# Health check
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD node -e "fetch('http://localhost:3000/health').then(r => r.ok ? process.exit(0) : process.exit(1))"

EXPOSE 3000
CMD ["node", "dist/server.js"]

Key Takeaways

Copy package.json BEFORE source code — dependency layer caches independently.
Multi-stage builds: builder stage compiles, production stage runs (smaller image).
--frozen-lockfile ensures reproducible builds (no surprise package updates).
Non-root USER in production — prevents container escape attacks.
HEALTHCHECK enables orchestrator health monitoring.

Docker Compose v2: Multi-Service Development

Docker Compose v2 defines and runs multi-container applications. A single compose.yaml file describes your entire development stack: app server, database, cache, message broker — all started with one command.

Compose v2 is integrated into the Docker CLI (docker compose instead of docker-compose). It supports profiles (enable/disable services), watch mode (hot reload on file changes), and GPU access.

Snippet
# compose.yaml — Full development stack
services:
  app:
    build:
      context: .
      target: builder  # Use the builder stage for dev (includes dev deps)
    ports:
      - "3000:3000"
    volumes:
      - .:/app          # Hot reload: mount source code
      - /app/node_modules  # Don't override container's node_modules
    environment:
      - DATABASE_URL=postgresql://postgres:secret@db:5432/inkdb
      - REDIS_URL=redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    develop:
      watch:
        - action: sync
          path: ./src
          target: /app/src
        - action: rebuild
          path: ./package.json

  db:
    image: postgres:17
    environment:
      POSTGRES_DB: inkdb
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: pg_isready -U postgres
      interval: 5s
      timeout: 3s
      retries: 5

  cache:
    image: redis:8-alpine
    ports:
      - "6379:6379"
    volumes:
      - redisdata:/data

volumes:
  pgdata:
  redisdata:

Key Takeaways

depends_on with condition: service_healthy waits for DB to be ready.
volumes mount source code for hot reload during development.
develop.watch enables Compose Watch — hot sync without restart.
Named volumes (pgdata) persist data across container restarts.
One command: docker compose up --build -d

Security Scanning & Hardening

Container security is a critical production concern. Docker Scout (built into Docker 27) scans your images for known CVEs (Common Vulnerabilities and Exposures) in base images and dependencies. Run it in CI to block deployments with critical vulnerabilities.

Beyond scanning: use distroless or Alpine base images (fewer attack vectors), never run as root, use read-only file systems where possible, and set resource limits to prevent container escape via resource exhaustion.

Snippet
# Scan for vulnerabilities
docker scout cves myapp:latest
docker scout recommendations myapp:latest

# .dockerignore — Never copy these into the image
.git
.env
node_modules
*.log
.DS_Store
tests/
docs/

# Production hardening in compose.yaml
services:
  app:
    image: myapp:latest
    read_only: true          # Read-only filesystem
    tmpfs:
      - /tmp                 # Writable temp directory
    security_opt:
      - no-new-privileges    # Prevent privilege escalation
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 128M

Key Takeaways

docker scout cves: scan for known vulnerabilities in your images.
.dockerignore: exclude .git, .env, node_modules, tests from image.
read_only: true + tmpfs for writable dirs — minimal attack surface.
no-new-privileges: prevent privilege escalation inside container.
Resource limits prevent a single container from starving others.

Key Takeaways

Docker is the foundation of modern deployment. Master Dockerfiles (layer caching, multi-stage builds), Compose (multi-service development), and security (scanning, non-root, read-only) to build production-ready containers.

For interviews: explain how layer caching works, demonstrate a multi-stage build, discuss the difference between COPY and ADD, explain why containers should run as non-root, and describe how Compose dependencies with health checks prevent race conditions.

Key Takeaways

Layer caching: order instructions from least-changed to most-changed.
Multi-stage builds: separate build-time deps from runtime image.
Non-root user: mandatory for production containers.
Compose v2: docker compose (not docker-compose), Watch mode, profiles.
Docker Scout: built-in vulnerability scanning for images.
.dockerignore: exclude .git, .env, node_modules from images.
AS
Article Author
Ashutosh
Lead Developer

Related Knowledge

Tutorial

Docker & Kubernetes for Production

5m read
Article

Understanding Closures in JavaScript: The Complete 2026 Guide

22 min read
Article

React 19 Server Components: The Definitive 2026 Guide

28 min read
Article

Next.js 15 App Router Masterclass: Everything You Need to Know

25 min read