从‘它怎么又挂了’到‘服务真稳’:我是如何用Docker给老旧Node.js项目续命的
·
从‘它怎么又挂了’到‘服务真稳’:我是如何用Docker给老旧Node.js项目续命
接手一个祖传Node.js项目就像继承一座年久失修的老宅——表面光鲜,实则暗藏无数隐患。上周五深夜,当我第7次被报警短信吵醒,面对生产环境又一次莫名其妙的Error: Cannot find module 'lodash'时,终于下定决心用Docker给这个2016年的"老古董"做个全面手术。
1. 解剖老项目的"疑难杂症"
那个凌晨三点,我对着报错日志做了次彻底尸检。这个使用Express 4.x和Node 8构建的电商后台系统,存在三类典型"老年病":
依赖地狱(Dependency Hell)
package-lock.json从未被提交到Git仓库- 开发环境用npm 5,生产环境用npm 6
- 三个子模块分别依赖不同版本的
bluebird
环境玄学(Environment Voodoo)
# 在Jenkins上总是报错的神秘命令
NODE_ENV=production && npm install --production && node server.js
配置漂移(Configuration Drift)
- 数据库连接字符串散落在5个配置文件中
- 开发环境用
.env,测试环境用config.json - 生产环境配置居然写在服务器
/etc/environment里
提示:使用
npm ls --depth=10可以可视化依赖树,快速发现版本冲突
2. 构建Docker化的手术方案
2.1 制作项目"标本"
首先用Docker的node:8-alpine镜像制作基础环境标本——这个2016年的项目只能用Node 8运行:
# 基于官方Node 8镜像
FROM node:8-alpine as builder
# 锁定npm版本
RUN npm install -g npm@5.10.0
# 解决时区问题
RUN apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
2.2 解决依赖冲突
通过多阶段构建隔离不同环境的依赖:
# 开发阶段安装所有依赖
FROM builder as dev
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
# 生产阶段只装必要依赖
FROM builder as production
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
CMD ["node", "server.js"]
关键技巧:
- 使用
alpine版本减少镜像体积(从900MB降到120MB) - 通过
npm ci替代npm install保证依赖一致性 - 用
.dockerignore排除node_modules
3. 配置管理的现代化改造
3.1 环境变量统一管理
将散落的配置集中到config.js中:
module.exports = {
db: {
host: process.env.DB_HOST || 'localhost',
port: process.env.DB_PORT || 27017
},
// 其他配置...
}
3.2 启动脚本标准化
创建可靠的启动脚本start.sh:
#!/bin/sh
set -e
# 等待数据库就绪
while ! nc -z $DB_HOST $DB_PORT; do
sleep 1
done
exec node server.js
在Dockerfile中赋予执行权限:
COPY start.sh .
RUN chmod +x start.sh
CMD ["./start.sh"]
4. 从CI/CD到监控的全链路加固
4.1 构建优化检查清单
| 检查项 | 传统方式 | Docker方案 |
|---|---|---|
| 依赖一致性 | ❌ 各环境不同 | ✅ 锁定在镜像中 |
| 环境变量管理 | ❌ 容易泄露 | ✅ 通过-e传递 |
| 快速回滚 | ❌ 需重新部署 | ✅ 切换镜像标签 |
| 资源隔离 | ❌ 端口冲突 | ✅ 独立网络命名空间 |
4.2 监控方案升级
在docker-compose.yml中添加健康检查:
services:
app:
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 30s
timeout: 5s
retries: 3
配合Prometheus实现指标收集:
# 暴露监控端口
EXPOSE 3000 9090
# 安装监控代理
RUN npm install prom-client --save
5. 那些年我们踩过的坑
字体缺失问题
Alpine镜像默认没有中文字体,导致PDF生成乱码:
RUN apk add --no-cache wqy-zenhei
时区陷阱
容器内默认UTC时间,需显式设置:
ENV TZ=Asia/Shanghai
内存泄漏诊断
旧版Node的--inspect参数在容器中需要特殊处理:
docker run -p 9229:9229 --cap-add=SYS_PTRACE app
现在这个曾经每天崩溃三次的系统已经稳定运行了217天。上周当我看到新来的实习生用docker-compose up三秒搭起完整开发环境时,突然理解了什么叫做"前人栽树后人乘凉"。
更多推荐
所有评论(0)