Skip to content

前言

Docker 实操:从 0 到 1 构建生产级容器化应用

第一阶段:重新理解 Docker 的本质

  • Docker 不是虚拟机,它是“进程隔离 + 文件系统快照”
    基于 cgroups(资源限制)、namespaces(隔离)、UnionFS(分层镜像)
  • 镜像(Image)vs 容器(Container):只读层 vs 可写层
    docker run = 启动一个可写层挂载在镜像之上
  • Registry 机制:docker pull 从哪里下载?manifest 如何支持多架构?
    index.docker.io/library/node:18-alpine
  • TypeScript/Nest/Bun 项目为何必须容器化?
    环境一致性、依赖隔离、部署标准化
  • DevOps 流水线基石:Docker 是 CI/CD 的“交付单元”

第二阶段:深入 Dockerfile 构建优化

FROM 指令

  • 选择基础镜像:node:18-alpine vs node:18-slim vs distroless
    Alpine 最小(~5MB),但 musl libc 兼容性问题;distroless 无 shell,最安全
  • 多阶段构建(Multi-stage Build):--from=builder 如何分离构建与运行环境?
    示例:前端 npm run build 输出静态文件,最终镜像只包含 nginxdist/
  • AS 命名阶段:FROM node:18 AS builder,便于引用

COPY vs ADD

  • COPY . /app:仅复制文件,推荐用于源码
    更透明、更安全
  • ADD 特殊行为:自动解压 tar/gz,支持 URL 下载
    风险:URL 变更导致构建失败,隐藏逻辑
  • 最佳实践:优先用 COPY,除非需要 ADD 的特殊功能

.dockerignore

  • 为什么比 .gitignore 更重要?
    防止 node_modules.envlogs/ 被复制进构建上下文
  • 常见忽略项:node_modules, .git, .env.local, npm-debug.log

分层缓存优化

  • Docker 缓存机制:每层指令结果缓存,仅当上层变更时失效
    COPY package*.json ./RUN npm ciCOPY . . 的顺序为何关键?
  • npm ci vs npm install:为何 CI 环境必须用 ci
    ci 删除 node_modules 重装,避免缓存污染
  • --cache-from:CI 中如何复用远程缓存?

WORKDIRUSER

  • WORKDIR /app:设置工作目录,避免路径混乱
  • 最小权限原则:USER node 运行非 root 用户
    安全加固,防止容器逃逸

第三阶段:掌握容器运行与调试

docker run 核心参数

  • -d:后台运行,-it:交互式终端
    docker run -it ubuntu:22.04 /bin/bash
  • -p 3000:3000:端口映射,主机 3000 → 容器 3000
  • -v /host/path:/container/path:卷挂载,开发环境热更新
    docker run -v $(pwd):/app node:18 npm run dev
  • -e NODE_ENV=production:环境变量注入
  • --network:自定义网络,服务间通信

调试技巧

  • docker logs <container>:查看输出日志
  • docker exec -it <container> sh:进入运行中容器
    Alpine 用 sh,Debian 用 bash
  • docker inspect <container>:查看详细配置(IP、挂载点、环境变量)
  • docker top <container>:查看容器内运行的进程
  • 高级调试:strace -p <pid> 抓系统调用,tcpdump 抓包

第四阶段:生产级 docker-compose 编排

docker-compose.yml 结构

yaml
version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - db
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: myapp
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

关键特性

  • depends_on:启动顺序控制,但不等待服务就绪
    需配合健康检查
  • healthcheck:如何判断服务是否 ready?
    test: ["CMD-SHELL", "pg_isready -U postgres"]
  • networks:自定义网络,服务间通过服务名通信
    webhttp://db:5432
  • secrets / configs:安全注入密码与配置文件

开发 vs 生产配置

  • docker-compose.dev.yml:挂载源码、开启调试
  • docker-compose.prod.yml:使用预构建镜像、关闭 shell 访问
  • docker-compose -f docker-compose.yml -f docker-compose.prod.yml up

第五阶段:CI/CD 与自动化部署

GitHub Actions 实战

yaml
name: Deploy
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker Image
        run: |
          docker build -t myapp:${{ github.sha }} .
      - name: Push to Registry
        run: |
          echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
          docker push myapp:${{ github.sha }}
      - name: Deploy to Server
        run: |
          ssh user@server "docker pull myapp:${{ github.sha }} && docker restart myapp"

镜像标签策略

  • latest 危险:永远不要在生产用 latest
    不可追溯,版本混乱
  • 推荐:git shav1.2.3-${sha})或语义化版本
  • digestsha256:abc...,最精确的镜像标识

第六阶段:安全加固与性能优化

安全实践

  • 最小化镜像:移除 curlvim 等非必要工具
  • 扫描漏洞:docker scan myapp:latesttrivy
  • USER node:禁止 root 运行
  • 只读文件系统:--read-only + tmpfs
  • distroless / scratch:极致精简,无 shell 入侵风险

性能优化

  • 多阶段构建:最终镜像仅包含运行时依赖
  • .dockerignore:减少构建上下文传输时间
  • 并行构建:DOCKER_BUILDKIT=1 启用 BuildKit
  • 缓存共享:--cache-to type=registry 推送缓存到远程

第七阶段:与 K8s 和边缘部署衔接

kubernetes 部署

  • Deployment:管理 Pod 副本,声明式更新
  • Service:暴露服务,ClusterIP/NodePort/LoadBalancer
  • Ingress:7 层路由,基于域名和路径转发
  • ConfigMap / Secret:外部化配置与密钥

边缘部署(Edge)

  • bun + Docker:极致轻量镜像,冷启动 < 100ms
  • Cloudflare Workers / Vercel:Serverless 替代方案
  • Wasm + Docker:运行 WebAssembly 模块