Docker 与 JavaScript:Node.js 应用的容器化(高级水平)

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:从简单到复杂,探索容器化世界

\n\n

在初级阶段,使用 Docker 和 JavaScript (Node.js) 通常只是创建一个简单的 Dockerfile 并启动容器。然而,在实际的生产系统中,这远远不够。高级水平要求深入理解构建机制、镜像大小优化、依赖管理、网络隔离和安全性。

\n\n

在本文中,我们将探讨 Node.js 应用专业容器化的关键方面。您将学习如何使用多阶段构建 (multi-stage builds)、为微服务架构配置 Docker Compose、管理环境变量以及最小化攻击面。本文面向已经熟悉 Docker 和 JavaScript 基础的开发者。

\n\n

1. Node.js 的多阶段构建 (Multi-stage builds)

\n\n

容器化 Node.js 应用时的一个主要问题是最终镜像体积过大。使用单个 Dockerfile 的标准方法会包含构建工具 (TypeScript, Webpack, Babel),而这些在运行时并不需要。多阶段构建允许将过程分为构建和执行两个阶段。

\n\n

1.1. 两阶段 Dockerfile 示例

\n\n
# 构建阶段 (build)\nFROM node:20-alpine AS builder\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci --only=production\nCOPY . .\nRUN npm run build  # 假设 build 脚本用于构建项目\n\n# 执行阶段 (production)\nFROM node:20-alpine AS production\nWORKDIR /app\n# 仅复制 node_modules 和构建后的文件\nCOPY --from=builder /app/node_modules ./node_modules\nCOPY --from=builder /app/dist ./dist\nCOPY package*.json ./\n\nEXPOSE 3000\nUSER node\nCMD ["node", "dist/index.js"]
\n\n

关键点:

\n
    \n
  • node:20-alpine — 基于 Alpine Linux 的轻量级镜像(约 30 MB)。
  • \n
  • npm ci — 严格按照 package-lock.json 进行纯净安装。
  • \n
  • --only=production — 排除开发依赖 (TypeScript, 测试工具)。
  • \n
  • USER node — 放弃 root 用户以提高安全性。
  • \n
\n\n

最终镜像仅包含运行所需的文件,体积从 300-400 MB 减少到 80-120 MB。

\n\n

1.2. 优化层缓存

\n\n

Docker 会缓存每一层(命令)。为了加速重复构建,请在复制所有源代码 之前 复制 package*.json。如果依赖项未更改,则 npm ci 层将从缓存中获取。

\n\n
COPY package*.json ./\nRUN npm ci --only=production\nCOPY . .  # 仅在源代码更改时复制
\n\n

2. 用于微服务架构的 Docker Compose

\n\n

在生产环境中,Node.js 应用很少独立运行。通常需要数据库 (PostgreSQL, MongoDB)、缓存 (Redis) 或消息队列 (RabbitMQ)。Docker Compose 允许在一个 YAML 文件中描述整个基础设施。

\n\n

2.1. Node.js + Redis 的 docker-compose.yml 示例

\n\n
version: '3.8'\nservices:\n  app:\n    build:\n      context: .\n      dockerfile: Dockerfile.prod\n    ports:\n      - "3000:3000"\n    environment:\n      - NODE_ENV=production\n      - REDIS_URL=redis://redis:6379\n    depends_on:\n      - redis\n    networks:\n      - backend\n\n  redis:\n    image: redis:7-alpine\n    ports:\n      - "6379:6379"\n    volumes:\n      - redis_data:/data\n    networks:\n      - backend\n\nvolumes:\n  redis_data:\n\nnetworks:\n  backend:\n    driver: bridge
\n\n

重要方面:

\n
    \n
  • 网络隔离: 服务通过内部网络 backend 通信。Redis 外部不可访问(除非映射端口)。
  • \n
  • 命名卷: redis_data 用于持久化数据。
  • \n

博客

书籍推荐