🐳 容器化:Docker / Compose / Kubernetes

把"在我电脑上能跑"变成"在哪都能跑"——容器是现代 SaaS 的基础设施基石
📑 目录

为什么需要容器

容器解决的核心问题:环境一致性。开发、测试、生产环境完全相同,消除了"在我电脑上能跑"的困境。

容器 vs 虚拟机

虚拟机 (VM)

App A
Bins/Libs
Guest OS (1-2GB)
Hypervisor
Host OS
Infrastructure

每个 VM 自带完整 OS,资源开销大

容器 (Container)

App A
Bins/Libs (MB级)
Docker Engine
Host OS
Infrastructure

共享宿主内核,轻量快速

维度虚拟机容器
启动时间分钟级秒级(~0.5s)
磁盘占用GB 级MB 级
内存开销每个 VM 1-2GB+ OS只占应用所需
隔离性强(硬件级)中(进程级)
密度每主机几个每主机数百个

Docker 深入

Docker 是容器的事实标准。从 2013 年发布至今,几乎改变了软件交付方式。

来源:github.com/moby/moby(Docker Engine 开源上游,2026-05)。Docker Engine 从 v29 起模块路径迁移至 github.com/moby/moby/v2。

Docker 核心概念

🖼️ Image(镜像)

只读模板,包含运行应用所需的一切。通过 Dockerfile 构建,分层存储。

# 查看本地镜像
docker images

# 拉取镜像
docker pull node:22-alpine

# 构建镜像
docker build -t myapp:latest .
📦 Container(容器)

镜像的运行实例。可创建、启动、停止、删除。每个容器是隔离的进程。

# 运行容器
docker run -d -p 3000:3000 --name app myapp:latest

# 查看运行中容器
docker ps

# 进入容器
docker exec -it app sh
🌐 Network(网络)

容器间通信。默认 bridge 网络,自定义网络支持 DNS 解析。

# 创建自定义网络
docker network create mynet

# 容器加入网络
docker run --network mynet --name api myapi
docker run --network mynet --name db postgres

# api 容器内可通过 db:5432 访问数据库
💾 Volume(数据卷)

持久化存储。容器删除后数据不丢失。

# 创建数据卷
docker volume create pgdata

# 挂载到容器
docker run -v pgdata:/var/lib/postgresql/data postgres

# 绑定挂载(开发用)
docker run -v ./src:/app/src myapp

Dockerfile 最佳实践

1. Next.js SaaS 的生产级 Dockerfile

# ---- 多阶段构建 ----

# Stage 1: 依赖安装
FROM node:22-alpine AS deps
RUN corepack enable pnpm
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile --prod=false

# Stage 2: 构建
FROM node:22-alpine AS builder
RUN corepack enable pnpm
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN pnpm build

# Stage 3: 生产运行
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

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
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

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

2. FastAPI 后端 Dockerfile

FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt

FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Dockerfile 优化技巧

📏 镜像大小优化
  • alpine 基础镜像(~5MB vs ~1GB)
  • 多阶段构建:编译阶段和运行阶段分离
  • .dockerignore 排除无关文件
  • pnpm install --prod 只装生产依赖
  • Next.js 用 output: 'standalone' 输出精简包
⚡ 构建速度优化
  • 先 COPY 依赖文件,再 COPY 源码(利用缓存层)
  • 用 BuildKit:DOCKER_BUILDKIT=1
  • 缓存挂载:--mount=type=cache
  • 并行构建:docker buildx
  • 远程缓存:--cache-from type=gha
🔧 缓存挂载示例
# Dockerfile 中使用缓存挂载
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
    pnpm install --frozen-lockfile

# 多平台构建缓存
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    apt-get update && apt-get install -y ...
⚠️ 不要做的事

Docker Compose:多容器编排

Docker Compose 用一个 YAML 文件定义和运行多容器应用。开发环境利器。

来源:github.com/docker/compose(2026-05)。Compose v5 基于 Go 重写,v1 (Python) 已停止维护。

SaaS 全栈开发环境示例

# compose.yaml
services:
  # Next.js 前端
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp
      - REDIS_URL=redis://redis:6379
      - NEXTAUTH_SECRET=dev-secret
    volumes:
      - ./src:/app/src        # 热重载
      - ./public:/app/public
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    command: pnpm dev

  # PostgreSQL
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: myapp
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

  # Redis
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redisdata:/data

  # MinIO (S3 兼容存储)
  minio:
    image: minio/minio
    ports:
      - "9000:9000"
      - "9001:9001"  # 管理面板
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    volumes:
      - miniodata:/data
    command: server /data --console-address ":9001"

  # Meilisearch (搜索)
  search:
    image: getmeili/meilisearch:v1.8
    ports:
      - "7700:7700"
    environment:
      MEILI_MASTER_KEY: dev-master-key
    volumes:
      - searchdata:/meili_data

volumes:
  pgdata:
  redisdata:
  miniodata:
  searchdata:

Compose 常用命令

命令用途
docker compose up -d后台启动所有服务
docker compose down停止并删除容器、网络
docker compose down -v同时删除数据卷(⚠️ 数据丢失)
docker compose logs -f web查看 web 服务实时日志
docker compose exec db psql -U postgres进入数据库
docker compose build --no-cache重新构建(不使用缓存)
docker compose pull拉取最新镜像
docker compose up -d --build重新构建并启动

多平台构建

当你的用户使用 ARM(M1/M2 Mac、ARM 服务器)和 x86 时,需要构建多平台镜像。

来源:Docker Docs - Multi-platform builds(docs.docker.com,2026-05)。Docker Engine 29+ 默认使用 containerd image store,原生支持多平台。

# 创建多平台 builder
docker buildx create --name multiplatform --use

# 同时构建 amd64 和 arm64 并推送
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t ghcr.io/myapp:latest \
  --push .

# 使用交叉编译(推荐,比 QEMU 快)
# Dockerfile 中:
FROM --platform=$BUILDPLATFORM node:22-alpine AS builder
ARG TARGETPLATFORM
ARG TARGETARCH
RUN echo "Building for $TARGETARCH"
# 用交叉编译工具链代替 QEMU 模拟
💡 三种多平台构建策略
  1. QEMU 模拟:最简单,但慢(编译型任务可能 5-10x)
  2. 多原生节点:最快,但需要多台不同架构的机器
  3. 交叉编译:推荐!Go/Rust/C++ 等编译型语言原生支持,JavaScript 无需关心

Kubernetes:生产级容器编排

Kubernetes (K8s) 是 Google 基于 Borg 系统经验开源的容器编排平台,由 CNCF 托管。当你的 SaaS 需要高可用、自动扩缩、滚动部署时,K8s 是终极选择。

来源:github.com/kubernetes/kubernetes(2026-05)、kubernetes.io(2026-05)

K8s 架构总览

Control Plane(控制面)

kube-apiserver
REST API 入口
etcd
状态存储
scheduler
Pod 调度
controller
状态协调

Worker Nodes(工作节点)

Node 1
Pod: api
Pod: worker
kubelet + kube-proxy
Node 2
Pod: api
Pod: web
kubelet + kube-proxy
Node 3
Pod: db
Pod: redis
kubelet + kube-proxy

核心资源对象

📦 Pod

最小调度单位,包含一个或多个容器。同一 Pod 内共享网络和存储。

apiVersion: v1
kind: Pod
metadata:
  name: api
spec:
  containers:
    - name: api
      image: myapp:latest
      ports:
        - containerPort: 3000
      resources:
        requests:
          memory: "256Mi"
          cpu: "250m"
        limits:
          memory: "512Mi"
          cpu: "500m"
🔄 Deployment

管理 Pod 副本集,支持滚动更新和回滚。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: myapp:latest
          ports:
            - containerPort: 3000
          readinessProbe:
            httpGet:
              path: /health
              port: 3000
🌐 Service

为 Pod 提供稳定的网络端点(ClusterIP/NodePort/LoadBalancer)。

apiVersion: v1
kind: Service
metadata:
  name: api
spec:
  selector:
    app: api
  ports:
    - port: 80
      targetPort: 3000
  type: ClusterIP
🚪 Ingress

HTTP 路由规则,将外部流量导入 Service。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 80

K8s 自动扩缩 (HPA)

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

托管 K8s 对比

除非你有专职运维团队,否则<强>强烈推荐托管 K8s——云厂商负责控制面维护、升级、安全补丁。

维度 GKE (Google) EKS (AWS) AKS (Azure) 自建 K8s
控制面费用 免费(含 Autopilot) $0.10/hour (~$73/月) 免费 需自建 + 运维
节点费用 按 GCE 定价
Autopilot: 按Pod资源计费
按 EC2 定价 按 VM 定价 按 VPS 定价
自动升级 ✅ 原生支持 ✅ 需配置 ✅ 原生支持 ❌ 手动
集成生态 GCP 全家桶 AWS 全家桶 Azure 全家桶 自选
学习曲线
适合场景 通用、ML 工作负载 AWS 深度用户 企业/微软生态 完全自控需求

来源:各云厂商官方定价页(2026-05),价格可能随时调整

💡 小团队建议:如果你只有 1-3 个服务,不要上 K8s。用 Vercel/Railway/Fly.io 等托管平台即可。K8s 的运维成本远超其收益,除非你确实需要自动扩缩、多区域部署、或已有专职 DevOps。

Docker 替代方案

🦭 Podman

Red Hat 出品的 Docker 替代品。无守护进程、rootless 安全、兼容 Docker CLI。

来源:podman.io(2026-05),最新稳定版 5.8.2,Apache 2.0 许可

  • 无 Daemon(更安全)
  • Rootless 模式
  • 兼容 Docker CLI(alias docker=podman
  • 原生 K8s YAML 生成
  • Docker Compose 兼容需 Podman Compose
  • 生态不如 Docker 成熟
🔧 Buildah + Skopeo

与 Podman 配套的构建和镜像传输工具。

  • Buildah:构建 OCI 镜像(无需 Dockerfile,可直接用脚本)
  • Skopeo:镜像复制/检查(无需 pull 整个镜像)
# Buildah 构建
buildah bud -t myapp:latest .

# Skopeo 复制镜像
skopeo copy docker://docker.io/library/nginx:alpine \
  docker://ghcr.io/myorg/nginx:alpine

容器化开发环境

Dev Containers (VS Code)

VS Code 的 Dev Containers 让整个开发环境容器化——团队成员 clone 后一键启动,无需本地安装 Node/Python/PostgreSQL。

// .devcontainer/devcontainer.json
{
  "name": "SaaS Dev",
  "dockerComposeFile": ["../compose.yaml"],
  "service": "web",
  "workspaceFolder": "/app",
  "features": {
    "ghcr.io/devcontainers/features/node:1": { "version": "22" },
    "ghcr.io/devcontainers/features/github-cli:1": {}
  },
  "postCreateCommand": "pnpm install",
  "forwardPorts": [3000, 5432, 6379],
  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "bradlc.vscode-tailwindcss",
        "prisma.prisma"
      ]
    }
  }
}

其他开发环境方案

方案原理优势劣势
Dev ContainersVS Code + Docker一键启动、团队一致首次构建慢、依赖 Docker
Gitpod云端开发环境浏览器即可开发延迟、付费
GitHub Codespaces云端 VS CodeGitHub 深度集成$0.18/hour(4-core)
Docker Compose + 本地 IDE服务容器化 + 代码挂载灵活、热重载需要本地安装 IDE

容器安全

🔒 容器安全清单
层次措施工具
镜像安全扫描已知漏洞Trivy、Snyk、Grype
基础镜像使用最小化镜像distroless、alpine、chainguard
运行权限非 root 运行Dockerfile USER 指令、K8s SecurityContext
密钥管理不硬编码 secretsDocker Secrets、K8s Secrets、Vault
网络隔离最小网络暴露K8s NetworkPolicy、服务网格
资源限制防止资源耗尽K8s Resource Limits、Docker --memory
镜像签名验证镜像来源cosign、Notation
运行时安全检测异常行为Falco、Tracee
# K8s SecurityContext 示例
securityContext:
  runAsNonRoot: true
  runAsUser: 1001
  readOnlyRootFilesystem: true
  allowPrivilegeEscalation: false
  capabilities:
    drop: ["ALL"]

选型决策树

🌳 你需要什么级别的容器编排?

Level 0:不用容器

  • Vercel/Railway/Fly.io 托管部署
  • 适合:MVP 阶段、个人项目、前端 SaaS

Level 1:Docker + Compose

  • 开发环境统一、单机部署
  • 适合:小团队、1-3 个服务、1 台 VPS

Level 2:Docker + 托管容器服务

  • AWS ECS / GCP Cloud Run / Azure Container Apps
  • 适合:需要自动扩缩但不想管 K8s

Level 3:Kubernetes

  • 多服务、多环境、多区域
  • 适合:10+ 微服务、专职 DevOps、合规需求

Level 4:K8s + 服务网格

  • Istio/Linkerd + GitOps (ArgoCD)
  • 适合:大规模微服务、mTLS、精细流量控制
⚠️ 容器化反模式

🔗 相关内容

🔄 CI/CD

CI 中构建 Docker 镜像

☁️ 托管方案

容器运行在哪

📁 文件存储

容器持久化存储方案

📊 监控

容器监控与日志

🏗️ 架构模式

微服务 vs 单体的容器策略

⚡ 缓存

Redis 容器化部署