Skip to content
返回部署

使用 Docker 容器部署

构建、优化和部署 Web 应用的多阶段 Docker 镜像,遵循安全最佳实践。

容器进阶

为什么

Docker 容器将应用与所有依赖打包,确保开发、预发布和生产环境行为一致。多阶段构建将镜像大小减少 80% 以上,并将构建工具与运行时隔离。

Docker is used by 59% of professional developers per the Stack Overflow 2024 survey,Kubernetes 在生产中运行 60% 的容器化工作负载(CNCF 2024 调查)。容器编排通过声明式滚动发布将部署相关事故减少 35%。

何时使用

部署到 Kubernetes、ECS 或任何容器编排平台时使用 Docker。也适用于本地开发一致性和 CI 可复现性。

如何做

1. 编写 Dockerfile — 多阶段:builder(依赖 + 构建)+ runner(最小运行时) 2. 选择基础镜像 — 生产用 distroless 或 alpine,不用 debian 3. 层顺序 — 先复制 package.json(缓存依赖),再复制源码 4. 构建 — docker build -t myapp:latest .(用 BuildKit 并行阶段) 5. 优化 — docker-slim 或 .dockerignore 排除 node_modules、.git 6. 扫描 — 推送前用 trivy 或 grype 检查漏洞 7. 运行 — docker run -p 3000:3000 --env-file .env myapp:latest 8. 编排 — docker-compose.yml 用于多容器应用(app + db + cache)

示例

# Dockerfile — 多阶段 Node.js 应用 # 阶段 1:构建器 FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --ignore-scripts COPY . . RUN npm run build # 阶段 2:运行器(最小化,无构建工具) FROM node:20-alpine AS runner WORKDIR /app RUN addgroup -S app && adduser -S app -G app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules COPY package*.json ./ USER app EXPOSE 3000 HEALTHCHECK --interval=30s CMD wget --spider http://localhost:3000/health || exit 1 CMD ["node", "dist/server.js"] # .dockerignore node_modules .git *.md .env* dist # docker-compose.yml services: app: build: . ports: ["3000:3000"] environment: DATABASE_URL: postgres://user:pass@db:5432/app depends_on: [db] db: image: postgres:16-alpine volumes: ["pgdata:/var/lib/postgresql/data"] volumes: pgdata:

常见问题

  • ⚠镜像 1.5GB — 用 node:20(完整 Debian)而非 node:20-alpine 或多阶段
  • ⚠每次构建缓存失效 — COPY . . 在 COPY package.json 前破坏层缓存
  • ⚠以 root 运行 — 容器逃逸给攻击者 host root 权限,始终用 USER 指令
  • ⚠密钥烤入镜像 — ENV 设置 API key 意味着任何拿到镜像的人都能提取

最佳实践

  • ✓使用多阶段构建 — 最终镜像不应包含 npm、tsc 或源文件
  • ✓固定基础镜像摘要 — FROM node:20-alpine@sha256:abc... 而非仅 :20-alpine
  • ✓使用 BuildKit — DOCKER_BUILDKIT=1 并行阶段构建和缓存挂载
  • ✓CI 中扫描每个镜像 — trivy image myapp:latest,HIGH/CRITICAL CVE 时失败

常见问题解答

为什么 Docker 镜像 1.2 GB?

用了完整 Node 基础镜像(node:18)而非 node:18-alpine。换 alpine 并加 .dockerignore 排除 node_modules、.git、测试——镜像降到 ~120 MB。

如何在 Docker 中缓存 node_modules?

先复制 package.json 和 lockfile,跑 npm ci,再复制其余。lockfile 未变时 Docker 层缓存跳过安装,重建从 60s 降到 5s。

容器内该用 root 运行吗?

不该——创建非 root 用户(USER node)并设文件归属。容器内 root 逃逸后即宿主 root。node:18-alpine 基础镜像含 node 用户。

为什么容器报 EADDRINUSE 崩溃?

应用监听容器内已占用端口。用 env 的 PORT(process.env.PORT)并 EXPOSE 该端口。别硬编码 3000——编排器分配动态端口。

如何调试立即退出的容器?

运行 docker run --entrypoint sh <image> 获取 shell。docker logs <id> 查日志。常见原因:缺环境变量、CMD 错误、OOM。