mcpField
D
docker

docker

github.com/bobmatnyc云与 DevOps781.0k 次安装15 周前更新
代码仓库

关于 docker

面向开发者的 Docker 容器化指南,适用于本地开发、CI/CD 和部署场景。通过示例介绍镜像构建、多容器配置、安全措施、故障排查与生产实践。

主要功能

  1. 01Dockerfile 与镜像构建基础
  2. 02使用 Compose 配置多容器
  3. 03多阶段镜像构建
  4. 04容器安全与资源限制
  5. 05容器故障排查技巧

适用场景

  1. 01创建一致的本地开发环境
  2. 02构建可复现的 CI/CD 工作流
  3. 03打包服务以便部署
  4. 04运行临时数据库进行集成测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bobmatnyc/claude-mpm-skills --skill docker

安装后在 Claude Code 中输入/docker确认已加载。

附带文件metadata.json

详细介绍

Docker 容器化技能

概要

Docker 提供容器化功能,可将应用及其依赖打包成隔离、可移植的单元。容器可确保开发、测试和生产环境之间的一致性,消除“在我的机器上能运行”的问题。

适用场景

  • 本地开发:确保团队成员使用一致的开发环境
  • CI/CD 流水线:可复现的构建和测试环境
  • 微服务:可独立扩展的隔离服务
  • 生产部署:可在不同云服务商之间移植的应用
  • 数据库/服务测试:用于集成测试的临时数据库
  • 旧版应用隔离:并行运行彼此不兼容的依赖

快速开始

1. 创建 Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
2. 构建镜像
docker build -t myapp:1.0 .
3. 运行容器
docker run -p 3000:3000 myapp:1.0

核心概念

镜像与容器
  • 镜像:包含应用代码、运行时和依赖的只读模板
  • 容器:镜像的运行实例,带有可写层
  • 镜像仓库:镜像的存储位置(Docker Hub、GitHub Container Registry)
层与缓存

Dockerfile 中的每条指令都会创建一个层。Docker 会缓存未更改的层,从而加快构建速度。

# GOOD: Dependencies change less frequently than code
FROM python:3.11-slim
COPY requirements.txt .
RUN pip install -r requirements.txt  # Cached unless requirements.txt changes
COPY . .                              # Rebuild only when code changes

# BAD: Invalidates cache on every code change
FROM python:3.11-slim
COPY . .                              # Changes frequently
RUN pip install -r requirements.txt  # Reinstalls on every build
卷

容器重启后仍保留的持久化数据存储。

# Named volume (managed by Docker)
docker run -v mydata:/app/data myapp

# Bind mount (host directory)
docker run -v $(pwd)/data:/app/data myapp

# Anonymous volume (temporary)
docker run -v /app/data myapp
网络

容器通过 Docker 网络进行通信。

# Create network
docker network create mynetwork

# Run containers on network
docker run --network mynetwork --name db postgres
docker run --network mynetwork --name app myapp
# App can connect to db using hostname "db"

Dockerfile 基础

必要指令
# Base image
FROM node:18-alpine

# Metadata
LABEL maintainer="[email protected]"
LABEL version="1.0"

# Set working directory
WORKDIR /app

# Copy files
COPY package*.json ./
COPY src/ ./src/

# Run commands (creates layer)
RUN npm ci --only=production

# Set environment variables
ENV NODE_ENV=production
ENV PORT=3000

# Expose ports (documentation only)
EXPOSE 3000

# Default command
CMD ["node", "src/server.js"]

# Alternative: ENTRYPOINT (not overridden by docker run args)
ENTRYPOINT ["node"]
CMD ["src/server.js"]  # Default args for ENTRYPOINT
提升缓存效率的指令顺序
# 1. Base image (rarely changes)
FROM python:3.11-slim

# 2. System dependencies (rarely change)
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# 3. Application dependencies (change occasionally)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 4. Application code (changes frequently)
COPY . .

# 5. Runtime configuration
ENV PYTHONUNBUFFERED=1
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
.dockerignore

从构建上下文中排除文件(加快构建速度,减小镜像体积)。

# .dockerignore
node_modules/
npm-debug.log
.git/
.gitignore
*.md
.env
.vscode/
__pycache__/
*.pyc
.pytest_cache/
coverage/
dist/
build/

多阶段构建

将构建阶段与运行阶段分开,以优化镜像体积。

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

# Production stage
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/server.js"]

优势:

  • 构建依赖(TypeScript、webpack)不会包含在最终镜像中
  • 最终镜像约为 50MB,而包含构建工具时约为 500MB
  • 部署更快,攻击面更小
Python 示例
# Build stage
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

# Runtime stage
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
Go 示例(最小镜像)
# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server

# Runtime stage (scratch = empty base image)
FROM scratch
COPY --from=builder /app/server /server
EXPOSE 8080
ENTRYPOINT ["/server"]

结果:最终镜像约为 10MB,仅包含编译后的二进制文件。


Docker Compose

使用 YAML 定义多容器应用。

基本结构
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://db:5432/myapp
    depends_on:
      - db
    volumes:
      - ./src:/app/src  # Hot reload in development

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - db_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  db_data:
命令
# Start all services
docker-compose up

# Start in background
docker-compose up -d

# Rebuild images
docker-compose up --build

# Stop services
docker-compose down

# Stop and remove volumes
docker-compose down -v

# View logs
docker-compose logs -f app

# Run one-off command
docker-compose run app npm test
完整技术栈示例
version: '3.8'

services:
  # Frontend
  web:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ./frontend/src:/app/src
    environment:
      - REACT_APP_API_URL=http://localhost:8000

  # Backend API
  api:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    volumes:
      - ./backend:/app
    command: uvicorn main:app --host 0.0.0.0 --reload

  # Database
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

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

  # Worker (background jobs)
  worker:
    build: ./backend
    command: celery -A tasks worker --loglevel=info
    environment:
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
      - db

volumes:
  db_data:
  redis_data:

networks:
  default:
    name: myapp_network

开发工作流

使用卷实现热重载
Node.js
services:
  app:
    build: .
    volumes:
      - ./src:/app/src        # Sync source code
      - /app/node_modules     # Prevent overwriting container's node_modules
    command: npm run dev
# Dockerfile.dev
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install  # Include dev dependencies
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
Python(Django/FastAPI)
services:
  web:
    build: .
    volumes:
      - .:/app
    command: python manage.py runserver 0.0.0.0:8000
    # or for FastAPI:
    # command: uvicorn main:app --host 0.0.0.0 --reload
VS Code Dev Containers

.devcontainer/devcontainer.json:

{
  "name": "Python Dev Container",
  "dockerComposeFile": "../docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/app",
  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance"
      ],
      "settings": {
        "python.defaultInterpreterPath": "/usr/local/bin/python"
      }
    }
  },
  "postCreateCommand": "pip install -r requirements-dev.txt",
  "remoteUser": "vscode"
}
本地数据库容器
# PostgreSQL
docker run -d \
  --name dev-postgres \
  -e POSTGRES_PASSWORD=localdev \
  -e POSTGRES_DB=myapp_dev \
  -p 5432:5432 \
  -v pgdata:/var/lib/postgresql/data \
  postgres:15-alpine

# MySQL
docker run -d \
  --name dev-mysql \
  -e MYSQL_ROOT_PASSWORD=localdev \
  -e MYSQL_DATABASE=myapp_dev \
  -p 3306:3306 \
  -v mysqldata:/var/lib/mysql \
  mysql:8

# MongoDB
docker run -d \
  --name dev-mongo \
  -p 27017:27017 \
  -v mongodata:/data/db \
  mongo:7

# Redis
docker run -d \
  --name dev-redis \
  -p 6379:6379 \
  redis:7-alpine

生产环境模式

健康检查
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

# Health check endpoint
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD node healthcheck.js

EXPOSE 3000
CMD ["node", "server.js"]
// healthcheck.js
const http = require('http');

const options = {
  host: 'localhost',
  port: 3000,
  path: '/health',
  timeout: 2000
};

const request = http.request(options, (res) => {
  if (res.statusCode === 200) {
    process.exit(0);
  } else {
    process.exit(1);
  }
});

request.on('error', () => process.exit(1));
request.end();
安全最佳实践
FROM python:3.11-slim

# 1. Use non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser

# 2. Install dependencies as root
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 3. Copy application files
COPY --chown=appuser:appuser . .

# 4. Switch to non-root user
USER appuser

# 5. Drop unnecessary privileges
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

其他安全措施:

  • 使用最小化基础镜像(alpine、distroless)
  • 扫描镜像中的漏洞:docker scan myapp:latest
  • 不要在镜像中包含机密信息(使用环境变量或机密管理器)
  • 保持基础镜像为最新版本
  • 尽可能使用只读根文件系统
机密信息管理
# Docker Swarm secrets (production)
echo "db_password_here" | docker secret create db_password -
version: '3.8'
services:
  app:
    image: myapp
    secrets:
      - db_password
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password

secrets:
  db_password:
    external: true

替代方案:环境文件

# docker-compose.yml
services:
  app:
    env_file:
      - .env.production  # Never commit this file
# .env.production (gitignored)
DATABASE_URL=postgresql://user:pass@db:5432/prod
SECRET_KEY=your-secret-key
资源限制
services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
# Command-line resource limits
docker run -d \
  --memory="512m" \
  --cpus="1.0" \
  --restart=unless-stopped \
  myapp

特定框架示例

Python:Django
FROM python:3.11-slim

ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application
COPY . .

# Collect static files
RUN python manage.py collectstatic --noinput

# Create non-root user
RUN useradd -m -u 1000 django && chown -R django:django /app
USER django

EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "myproject.wsgi:application"]

docker-compose.yml:

version: '3.8'

services:
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/app
    ports:
      - "8000:8000"
    environment:
      - DEBUG=1
      - DATABASE_URL=postgres://postgres:postgres@db:5432/django_dev
    depends_on:
      - db

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: django_dev
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
Python:FastAPI
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
Node.js:Next.js
# Multi-stage build for Next.js
FROM node:18-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci

FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

CMD ["node", "server.js"]

next.config.js(独立输出所必需):

module.exports = {
  output: 'standalone',
}
Node.js:Express
FROM node:18-alpine

WORKDIR /app

# Install dependencies
COPY package*.json ./
RUN npm ci --only=production

# Copy application
COPY . .

# Create non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

EXPOSE 3000

CMD ["node", "server.js"]
TypeScript 构建
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json tsconfig.json ./
RUN npm ci
COPY src/ ./src/
RUN npm run build

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

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

容器编排基础

Docker Swarm(内置)
# Initialize swarm
docker swarm init

# Deploy stack
docker stack deploy -c docker-compose.yml myapp

# Scale service
docker service scale myapp_web=5

# Update service (zero-downtime)
docker service update --image myapp:2.0 myapp_web

# Remove stack
docker stack rm myapp
Kubernetes 对比
特性Docker ComposeDocker SwarmKubernetes
复杂度低中高
使用场景本地开发小型集群大规模生产环境
设置单个文件内置单独安装
扩展手动自动自动 + 高级功能
高可用性否是是
生态系统有限Docker庞大

何时使用:

  • Docker Compose:本地开发、简单部署
  • Docker Swarm:小型生产集群,比 K8s 更简单
  • Kubernetes:大规模生产环境、多云、复杂编排

CI/CD 集成

GitHub Actions
# .github/workflows/docker.yml
name: Build and Push Docker Image

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v2
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=sha

      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Run tests
        run: |
          docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} npm test
GitLab CI
# .gitlab-ci.yml
stages:
  - build
  - test
  - deploy

variables:
  DOCKER_DRIVER: overlay2
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG

test:
  stage: test
  script:
    - docker run --rm $IMAGE_TAG npm test

deploy:
  stage: deploy
  script:
    - docker pull $IMAGE_TAG
    - docker tag $IMAGE_TAG $CI_REGISTRY_IMAGE:latest
    - docker push $CI_REGISTRY_IMAGE:latest
  only:
    - main

调试容器

查看日志
# Stream logs
docker logs -f container_name

# Last 100 lines
docker logs --tail 100 container_name

# Logs since timestamp
docker logs --since 2024-01-01T10:00:00 container_name

# With timestamps
docker logs -t container_name

# Docker Compose logs
docker-compose logs -f service_name
在运行中的容器内执行命令
# Interactive shell
docker exec -it container_name /bin/sh
# or
docker exec -it container_name /bin/bash

# Run single command
docker exec container_name ls -la /app

# Run as different user
docker exec -u root container_name apt-get update
检查容器
# Full container details
docker inspect container_name

# Specific field (IP address)
docker inspect -f '{{.NetworkSettings.IPAddress}}' container_name

# Environment variables
docker inspect -f '{{.Config.Env}}' container_name

# Mounted volumes
docker inspect -f '{{.Mounts}}' container_name
资源使用情况
# Real-time stats
docker stats

# Single container
docker stats container_name

# No streaming (single snapshot)
docker stats --no-stream
网络调试
# List networks
docker network ls

# Inspect network
docker network inspect bridge

# Test connectivity between containers
docker exec container1 ping container2

# Check DNS resolution
docker exec container_name nslookup other_container
调试构建问题
# Build with no cache
docker build --no-cache -t myapp .

# Show build progress
docker build --progress=plain -t myapp .

# Build specific stage
docker build --target builder -t myapp-builder .

# Inspect intermediate layers
docker history myapp:latest

本地 Docker 模式(mcp-browser、mcp-memory)

mcp-browser 开发环境 compose
  • docker-compose.yml 使用端口范围 8875-8895 运行 mcp-server,并提供可选的 chrome 配置文件。
  • 代码以只读方式挂载(./src:/app/src:ro),并使用持久化日志和临时卷。
  • 环境变量默认值:MCP_DEBUG=true、MCP_LOG_LEVEL=DEBUG、MCP_HOST=0.0.0.0、MCP_PORT=8875。
  • 可选配置文件:chrome(浏览器)和 tools(开发工具容器)。
mcp-browser Dockerfile.dev
  • ARG PYTHON_VERSION=3.11,安装 watchdog 和 Playwright Chromium。
  • 以可编辑模式安装软件包,并运行 python -m src.dev_runner。
  • 使用非 root 用户,并对 /health 执行健康检查。
mcp-memory 生产环境 Dockerfile
  • 多阶段构建,在 /opt/venv 中创建虚拟环境,并使用 python:3.11-slim。
  • 运行时安装 curl 用于健康检查,并设置 PYTHONPATH=/app。
  • 使用非 root 用户,通过 CMD ["python", "run_api_server.py"] 启动,并检查 /health。

故障排除

常见问题
“端口已被占用”
# Find process using port
lsof -i :3000
# or
netstat -tulpn | grep 3000

# Kill process
kill -9 <PID>

# Or use different host port
docker run -p 3001:3000 myapp
“无法连接到 Docker 守护进程”
# Check Docker is running
docker info

# Restart Docker Desktop (Mac/Windows)
# or
sudo systemctl restart docker  # Linux

# Check permissions (Linux)
sudo usermod -aG docker $USER
# Log out and back in
“设备上没有剩余空间”
# Remove unused containers, images, volumes
docker system prune -a --volumes

# Remove only dangling images
docker image prune

# Remove stopped containers
docker container prune

# Remove unused volumes
docker volume prune

# Check disk usage
docker system df
“构建上下文过大”
# Create .dockerignore
cat > .dockerignore << EOF
node_modules/
.git/
*.log
dist/
coverage/
EOF

# Build with specific context
docker build -f Dockerfile -t myapp ./src
容器立即退出
# Check logs
docker logs container_name

# Run with interactive shell to debug
docker run -it myapp /bin/sh

# Override entrypoint
docker run -it --entrypoint /bin/sh myapp

# Check exit code
docker inspect -f '{{.State.ExitCode}}' container_name
容器内权限被拒绝
# Run as root to debug
docker exec -u root -it container_name /bin/sh

# Fix ownership
docker exec -u root container_name chown -R appuser:appuser /app

# Or rebuild with correct permissions in Dockerfile
性能问题
构建缓慢
# Use BuildKit (faster, better caching)
DOCKER_BUILDKIT=1 docker build -t myapp .

# Multi-stage builds to reduce layers
# Order instructions by change frequency
# Use .dockerignore to exclude unnecessary files
内存使用量过高
# Set memory limits
docker run -m 512m myapp

# Monitor memory
docker stats container_name

# Check for memory leaks in application
卷挂载缓慢(Mac/Windows)
# Use delegated consistency (Mac)
volumes:
  - ./src:/app/src:delegated

# Or use named volumes instead of bind mounts
volumes:
  - node_modules:/app/node_modules

最佳实践

优化层
  1. 按更改频率排序:最不常更改的内容放在前面
  2. 合并 RUN 命令:减少层数
  3. 在同一层中清理:立即删除临时文件
# GOOD
RUN apt-get update && apt-get install -y \
    package1 \
    package2 \
    && rm -rf /var/lib/apt/lists/*

# BAD (creates 3 layers, apt cache remains in layer 2)
RUN apt-get update
RUN apt-get install -y package1 package2
RUN rm -rf /var/lib/apt/lists/*
减小镜像体积
  1. 使用 Alpine 镜像:5MB,而完整 Linux 镜像为 100MB+
  2. 多阶段构建:从最终镜像中排除构建工具
  3. 删除不必要的文件:文档、示例、测试
  4. 使用 .dockerignore:排除开发文件
# Before: 800MB
FROM node:18
COPY . .
RUN npm install
CMD ["node", "server.js"]

# After: 120MB
FROM node:18-alpine
COPY package*.json ./
RUN npm ci --only=production
COPY server.js .
CMD ["node", "server.js"]
安全检查清单
  • 使用可信来源提供的官方基础镜像
  • 指定准确的镜像版本(而不是 latest)
  • 以非 root 用户运行
  • 扫描镜像以查找漏洞
  • 保持基础镜像更新
  • 不要将机密嵌入镜像
  • 尽可能使用只读根文件系统
  • 尽量缩小攻击面(alpine、distroless)
  • 启用 Docker Content Trust(镜像签名)
开发环境与生产环境

开发环境:

FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install  # Include dev dependencies
COPY . .
CMD ["npm", "run", "dev"]

生产环境:

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

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]
日志记录最佳实践
# Log to stdout/stderr (Docker captures these)
CMD ["node", "server.js"]  # Good

# Don't log to files (lost when container stops)
CMD ["node", "server.js", ">", "app.log"]  # Bad
// Application logging
console.log('Info message');   // stdout
console.error('Error message'); // stderr

// Use structured logging
console.log(JSON.stringify({
  level: 'info',
  timestamp: new Date().toISOString(),
  message: 'Request processed',
  requestId: '123'
}));
环境配置
# Use ARG for build-time variables
ARG NODE_ENV=production
ENV NODE_ENV=$NODE_ENV

# Use ENV for runtime variables
ENV PORT=3000
ENV LOG_LEVEL=info

# Override at runtime
# docker run -e PORT=8080 -e LOG_LEVEL=debug myapp
健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1
# docker-compose.yml
services:
  app:
    image: myapp
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s
优雅关闭
// Node.js example
process.on('SIGTERM', () => {
  console.log('SIGTERM received, closing server...');
  server.close(() => {
    console.log('Server closed');
    process.exit(0);
  });
});
# Use exec form to properly handle signals
CMD ["node", "server.js"]  # Good
CMD node server.js          # Bad (wrapped in /bin/sh, signals not forwarded)

快速参考

基本命令
# Images
docker build -t name:tag .
docker pull image:tag
docker push image:tag
docker images
docker rmi image:tag

# Containers
docker run -d --name container image
docker ps                    # Running containers
docker ps -a                 # All containers
docker stop container
docker start container
docker restart container
docker rm container
docker logs -f container
docker exec -it container /bin/sh

# Cleanup
docker system prune -a       # Remove all unused resources
docker container prune       # Remove stopped containers
docker image prune          # Remove dangling images
docker volume prune         # Remove unused volumes

# Compose
docker-compose up -d
docker-compose down
docker-compose logs -f
docker-compose exec service /bin/sh
docker-compose build
常用标志
# docker run flags
-d              # Detached (background)
-it             # Interactive with TTY
-p 8080:80      # Port mapping (host:container)
--name myapp    # Container name
-e VAR=value    # Environment variable
-v /host:/container  # Volume mount
--network name  # Connect to network
--rm            # Remove container on exit
-m 512m         # Memory limit
--cpus 1.0      # CPU limit
Dockerfile 指令
FROM image:tag           # Base image
WORKDIR /path            # Set working directory
COPY src dst             # Copy files
ADD src dst              # Copy (with URL/tar support)
RUN command              # Execute command
ENV KEY=value            # Environment variable
EXPOSE port              # Document port
CMD ["executable"]       # Default command
ENTRYPOINT ["exec"]      # Command prefix
VOLUME /path             # Create mount point
USER username            # Set user
ARG name=default         # Build argument
LABEL key=value          # Metadata
HEALTHCHECK CMD command  # Health check

概要

Docker 容器化可提供:

  • 一致性:从开发到生产环境保持一致
  • 隔离性:不同应用的依赖不会相互冲突
  • 可移植性:可在任何运行 Docker 的环境中运行(云端、本地、CI)
  • 效率:与虚拟机相比更轻量,启动速度更快
  • 可扩展性:通过编排轻松实现水平扩展

关键工作流:

  1. 开发:使用带热重载卷的 docker-compose
  2. CI/CD:构建、测试并将镜像推送到注册表
  3. 生产:拉取镜像,并设置资源限制和健康检查后运行

后续步骤:

  • 掌握多阶段构建,以优化镜像大小
  • 实现健康检查和优雅关停
  • 设置 docker-compose,用于本地开发
  • 将 Docker 集成到 CI/CD 流水线中
  • 探索编排方案(Swarm 或 Kubernetes),以满足生产规模需求

评论

支持 Markdown