Docker容器化部署Node.js应用最佳实践
Docker已成为现代应用部署的标准工具。本文将详细介绍如何将Node.js应用容器化,并分享生产环境的最佳实践。
项目准备
示例项目结构
my-node-app/
├── src/
│ ├── index.js
│ ├── routes/
│ └── controllers/
├── package.json
├── package-lock.json
├── .dockerignore
├── Dockerfile
└── docker-compose.yml
基础应用代码
// src/index.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.json({ message: 'Hello from Docker!', timestamp: new Date() });
});
app.get('/health', (req, res) => {
res.json({ status: 'healthy' });
});
app.listen(PORT, '0.0.0.0', () => {
console.log(`Server running on port ${PORT}`);
});
Dockerfile编写
基础版本
# 使用官方Node.js镜像
FROM node:20-alpine
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制源代码
COPY src/ ./src/
# 暴露端口
EXPOSE 3000
# 启动应用
CMD ["node", "src/index.js"]
生产级优化版本
# ==================== 构建阶段 ====================
FROM node:20-alpine AS builder
WORKDIR /app
# 复制依赖文件
COPY package*.json ./
# 安装所有依赖(包括devDependencies)
RUN npm ci
# 复制源代码
COPY . .
# 如果使用TypeScript,进行编译
# RUN npm run build
# ==================== 生产阶段 ====================
FROM node:20-alpine AS production
# 安全:使用非root用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodeapp -u 1001
WORKDIR /app
# 只复制生产依赖
COPY --from=builder --chown=nodeapp:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodeapp:nodejs /app/package.json ./
COPY --from=builder --chown=nodeapp:nodejs /app/src ./src
# 切换到非root用户
USER nodeapp
# 环境变量
ENV NODE_ENV=production
ENV PORT=3000
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# 启动应用
CMD ["node", "--max-old-space-size=512", "src/index.js"]
.dockerignore配置
# 依赖目录
node_modules
npm-debug.log
# Git
.git
.gitignore
# 测试
coverage
.nyc_output
*.test.js
# 文档
README.md
docs
# IDE
.idea
.vscode
*.swp
# 环境文件
.env
.env.local
.env.*.local
# Docker
Dockerfile
docker-compose*.yml
.dockerignore
Docker Compose配置
开发环境
# docker-compose.dev.yml
version: '3.8'
services:
app:
build:
context: .
target: builder
ports:
- "3000:3000"
volumes:
- ./src:/app/src
- ./package.json:/app/package.json
environment:
- NODE_ENV=development
command: npm run dev
mongodb:
image: mongo:7
ports:
- "27017:27017"
volumes:
- mongo_data:/data/db
volumes:
mongo_data:
生产环境
# docker-compose.prod.yml
version: '3.8'
services:
app:
build:
context: .
target: production
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- MONGODB_URI=mongodb://mongodb:27017/production
depends_on:
mongodb:
condition: service_healthy
restart: unless-stopped
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
mongodb:
image: mongo:7
volumes:
- mongo_data:/data/db
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- app
restart: unless-stopped
volumes:
mongo_data:
Nginx反向代理配置
# nginx.conf
events {
worker_connections 1024;
}
http {
upstream app {
server app:3000;
keepalive 32;
}
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
location /health {
proxy_pass http://app/health;
access_log off;
}
}
}
常用命令
构建与运行
bash
# 构建镜像
docker build -t my-node-app:latest .
# 构建特定阶段
docker build --target production -t my-node-app:prod .
# 运行容器
---
📌 更多精彩内容,关注我的[博客](https://wdsega.github.io),每周更新!
Top comments (0)