正在加载,请稍候…

Docker Development Workflow: Compose, Multi-Stage Builds, and Dev Environments

Optimize your development workflow with Docker. Learn multi-stage builds, Docker Compose for local dev, bind mounts, hot reload, and production-grade Docker patterns.

Docker Development Workflow

Multi-Stage Dockerfile

# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci

# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

# Stage 3: Production (minimal image)
FROM node:20-alpine AS production
WORKDIR /app

# Non-root user
RUN addgroup -S app && adduser -S -G app app
USER app

COPY --chown=app:app --from=builder /app/dist ./dist
COPY --chown=app:app --from=deps /app/node_modules ./node_modules
COPY --chown=app:app package.json ./

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

# Stage 4: Development (with devDependencies and hot reload)
FROM node:20-alpine AS development
WORKDIR /app

# Install all deps including devDependencies
COPY package*.json ./
RUN npm install  # Not npm ci - allows updates

COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]

Docker Compose for Development

# docker-compose.yml
version: '3.9'

services:
  app:
    build:
      context: .
      target: development  # Use dev stage
    ports:
      - "3000:3000"
      - "9229:9229"  # Debug port
    volumes:
      - .:/app                          # Bind mount for hot reload
      - /app/node_modules               # Anonymous volume (prevents host overwrite)
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://user:pass@postgres:5432/devdb
      - REDIS_URL=redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    command: npm run dev

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: devdb
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d devdb"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

  adminer:
    image: adminer
    ports:
      - "8080:8080"
    depends_on:
      - postgres

volumes:
  postgres_data:
  redis_data:

Docker Compose Override for Production

# docker-compose.prod.yml
version: '3.9'

services:
  app:
    build:
      target: production
    restart: unless-stopped
    environment:
      - NODE_ENV=production
    volumes: []  # No bind mounts in production
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
# Use override file
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Debugging in Docker

# Exec into running container
docker exec -it myapp-app-1 sh

# Debug Node.js in container
# In docker-compose.yml:
# command: node --inspect=0.0.0.0:9229 dist/server.js

# Then connect VS Code debugger to port 9229

# View logs with timestamps
docker compose logs -f --timestamps app

# Inspect container state
docker inspect myapp-app-1 | jq '.[0].State'
docker stats --no-stream

# Copy files from container
docker cp myapp-app-1:/app/logs ./local-logs

BuildKit Advanced Features

# Enable BuildKit cache mounts
# syntax=docker/dockerfile:1

FROM node:20-alpine
WORKDIR /app
COPY package*.json ./

# Cache npm cache between builds
RUN --mount=type=cache,target=/root/.npm     npm ci --prefer-offline

COPY . .
RUN npm run build
# Build with BuildKit
DOCKER_BUILDKIT=1 docker build .

# Or set in daemon.json
{
  "features": { "buildkit": true }
}

# Build with multiple platforms
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest --push .

# Layer inspection
docker buildx imagetools inspect myapp:latest
docker history myapp:latest

Docker Networking

# Create custom network
docker network create myapp-network --driver bridge --subnet 172.20.0.0/16

# Connect containers
docker run --network myapp-network --name backend myapp-backend
docker run --network myapp-network --name frontend myapp-frontend

# DNS resolution: containers can reach each other by name
# http://backend:3000 works from frontend container

# Host networking (Linux only, for performance)
docker run --network host myapp

# Port inspection
docker port myapp-app-1

Useful Docker Commands

# Clean up
docker system prune -af --volumes  # Remove everything unused
docker image prune -a               # Remove all unused images

# Inspect build
docker buildx build --progress=plain . 2>&1 | head -50

# Size analysis
dive myapp:latest  # Interactive layer explorer

# Resource usage
docker stats --format "table {{.Name}}	{{.CPUPerc}}	{{.MemUsage}}"