随着 Node.js 应用从开发环境迁移到生产环境,传统的直接部署方式(如裸机、PM2 守护进程)虽然可行,但在环境一致性、快速部署、可扩展性上仍存在一定局限。
Docker 容器化部署提供了一种轻量、可移植、环境一致的解决方案,使得应用可以在任何支持 Docker 的环境中运行,且无需担心依赖冲突或环境差异。
本文将从实战角度,讲解如何将 Node.js 应用容器化,并完成从构建、运行到优化的全过程。
一、为什么选择 Docker 部署 Node.js 应用
Docker 提供了以下核心优势:
- 1. 环境隔离
每个应用运行在独立容器中,不会与系统环境或其他应用冲突。 - 2. 快速部署与迁移
一次构建的镜像可以在任何 Docker 支持的服务器上运行,部署过程几乎无需额外配置。 - 3. 便于 CI/CD
容器镜像可直接推送到镜像仓库,实现流水线自动化部署。 - 4. 轻量与高效
容器相比虚拟机占用更少资源,启动速度快。 - 5. 易于扩展与负载均衡
可配合 Docker Compose 或 Kubernetes,快速扩容多实例。
二、准备 Node.js 应用
假设我们的项目结构如下:
my-app/
├── app.js
├── package.json
└── package-lock.json
确保应用在本地可以正常启动:
node app.js
三、编写 Dockerfile
Dockerfile 是容器构建的核心。
1. 基础 Dockerfile 示例
# 使用官方 Node.js LTS 版本作为基础镜像
FROM node:20-alpine
# 设置工作目录
WORKDIR /usr/src/app
# 复制 package.json 和 package-lock.json
COPY package*.json ./
# 安装依赖
RUN npm install --production
# 复制应用代码
COPY . .
# 暴露容器端口
EXPOSE 3000
# 启动应用
CMD ["node", "app.js"]
说明:
- •
node:20-alpine是轻量级 Node.js 官方镜像 - •
WORKDIR定义容器内工作目录 - •
npm install --production仅安装生产依赖 - •
EXPOSE 3000用于容器端口映射 - •
CMD指定容器启动命令
2. 优化 Dockerfile
- 1. 缓存依赖安装
COPY package*.json ./
RUN npm ci --only=production
使用 npm ci 速度更快,并保证依赖一致性。
- 2. 减少镜像体积
FROM node:20-alpine AS builder
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --production
COPY . .
FROM node:20-alpine
WORKDIR /usr/src/app
COPY --from=builder /usr/src/app .
EXPOSE 3000
CMD ["node", "app.js"]
使用多阶段构建,仅将最终产物放入镜像,显著减小体积。
四、构建镜像
在项目根目录下执行:
docker build -t my-app:1.0 .
- •
my-app:1.0是镜像名称和标签 - •
.表示 Dockerfile 所在目录
构建完成后,可以查看镜像:
docker images
五、运行容器
docker run -d -p 3000:3000 --name my-app-container my-app:1.0
说明:
- •
-d后台运行 - •
-p 3000:3000将容器 3000 端口映射到宿主机 3000 端口 - •
--name指定容器名称
访问 http://localhost:3000 即可看到应用运行效果。
六、使用 Docker Compose 管理
当应用依赖数据库或缓存时,Docker Compose 可以统一管理多服务。
1. 示例 docker-compose.yml
version: "3.9"
services:
app:
build: .
container_name: my-app
ports:
- "3000:3000"
environment:
NODE_ENV: production
depends_on:
- redis
- db
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: mydb
ports:
- "3306:3306"
redis:
image: redis:7
ports:
- "6379:6379"
2. 启动多服务
docker-compose up -d
一条命令即可启动应用及依赖服务,并保持网络互通。
七、镜像优化与安全建议
-
- 使用 Alpine 或 Slim 镜像 减少体积
-
- 安装依赖尽量使用
--production或--only=prod
- 安装依赖尽量使用
-
- 多阶段构建,避免将开发工具带入生产镜像
-
- 配置 非 root 用户 运行应用
-
- 定期更新基础镜像,修复安全漏洞
-
- 使用
.dockerignore忽略不必要文件
- 使用
八、日志管理
Docker 容器的日志默认输出到标准输出(stdout)和标准错误(stderr)。可以通过以下方式查看:
docker logs -f my-app-container
结合 Docker Compose,可统一查看多服务日志:
docker-compose logs -f
生产环境建议配合 ELK 或 Loki 做集中日志管理与分析。
九、容器更新与滚动部署
-
- 构建新镜像:
docker build -t my-app:1.1 .
-
- 停止旧容器并删除:
docker stop my-app-container
docker rm my-app-container
-
- 启动新容器:
docker run -d -p 3000:3000 --name my-app-container my-app:1.1
配合 CI/CD 可实现自动化滚动更新,减少停机时间。
十、总结
使用 Docker 容器化部署 Node.js 应用有以下优势:
- • 环境一致性,避免依赖冲突
- • 快速部署与迁移
- • 多服务统一管理(Docker Compose)
- • 易于扩展与负载均衡
- • 集成 CI/CD 流程,实现自动化发布
在《Node.js 编程实战》系列中,Docker 部署为应用走向生产环境奠定了基础,同时也为后续 Kubernetes、高可用集群以及微服务架构提供了良好扩展性。