部署上线 #
一、部署准备 #
1.1 环境变量 #
.env.production:
env
NODE_ENV=production
PORT=3000
HOST=0.0.0.0
JWT_SECRET=your-production-secret-key
DATABASE_URL=postgresql://user:pass@host:5432/db
1.2 生产配置 #
src/config/index.js:
javascript
module.exports = {
port: parseInt(process.env.PORT, 10) || 3000,
host: process.env.HOST || '0.0.0.0',
env: process.env.NODE_ENV || 'development',
isProduction: process.env.NODE_ENV === 'production',
isDevelopment: process.env.NODE_ENV === 'development'
};
二、PM2部署 #
2.1 安装PM2 #
bash
npm install -g pm2
2.2 PM2配置 #
ecosystem.config.js:
javascript
module.exports = {
apps: [{
name: 'hapi-app',
script: './src/index.js',
instances: 'max',
exec_mode: 'cluster',
autorestart: true,
watch: false,
max_memory_restart: '1G',
env: {
NODE_ENV: 'development',
PORT: 3000
},
env_production: {
NODE_ENV: 'production',
PORT: 3000
},
error_file: './logs/error.log',
out_file: './logs/out.log',
log_file: './logs/combined.log',
time: true
}]
};
2.3 PM2命令 #
bash
pm2 start ecosystem.config.js --env production
pm2 stop hapi-app
pm2 restart hapi-app
pm2 delete hapi-app
pm2 logs hapi-app
pm2 monit
pm2 save
pm2 startup
三、Docker部署 #
3.1 Dockerfile #
dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
USER node
CMD ["node", "src/index.js"]
3.2 docker-compose.yml #
yaml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
depends_on:
- db
- redis
restart: always
db:
image: postgres:14-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
volumes:
- postgres_data:/var/lib/postgresql/data
restart: always
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
restart: always
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
restart: always
volumes:
postgres_data:
redis_data:
3.3 Docker命令 #
bash
docker build -t hapi-app .
docker run -p 3000:3000 hapi-app
docker-compose up -d
docker-compose down
docker-compose logs -f
四、Nginx配置 #
4.1 nginx.conf #
nginx
events {
worker_connections 1024;
}
http {
upstream hapi_app {
server app:3000;
}
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://hapi_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://hapi_app/health;
access_log off;
}
}
}
五、CI/CD配置 #
5.1 GitHub Actions #
.github/workflows/deploy.yml:
yaml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build Docker image
run: docker build -t hapi-app .
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /app
git pull
docker-compose down
docker-compose up -d --build
六、健康检查 #
6.1 健康检查路由 #
javascript
server.route({
method: 'GET',
path: '/health',
options: {
auth: false
},
handler: async (request, h) => {
const health = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage(),
env: process.env.NODE_ENV
};
return health;
}
});
server.route({
method: 'GET',
path: '/health/ready',
options: {
auth: false
},
handler: async (request, h) => {
try {
await checkDatabaseConnection();
await checkRedisConnection();
return { status: 'ready' };
} catch (error) {
return h.response({ status: 'not ready', error: error.message }).code(503);
}
}
});
七、日志管理 #
7.1 日志配置 #
javascript
const fs = require('fs');
const path = require('path');
const logDir = path.join(__dirname, '../logs');
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
server.events.on('response', (request) => {
const log = {
timestamp: new Date().toISOString(),
method: request.method,
path: request.path,
status: request.response.statusCode,
duration: request.info.responded - request.info.received,
ip: request.info.remoteAddress
};
console.log(JSON.stringify(log));
});
7.2 日志轮转 #
bash
npm install rotating-file-stream
javascript
const rfs = require('rotating-file-stream');
const accessLog = rfs.createStream('access.log', {
path: path.join(__dirname, 'logs'),
size: '10M',
interval: '1d',
compress: 'gzip'
});
八、监控告警 #
8.1 进程监控 #
javascript
setInterval(() => {
const memoryUsage = process.memoryUsage();
const cpuUsage = process.cpuUsage();
if (memoryUsage.heapUsed > 500 * 1024 * 1024) {
console.warn('High memory usage:', memoryUsage);
}
}, 60000);
8.2 错误追踪 #
javascript
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection:', reason);
});
server.events.on({ name: 'request', channels: 'error' }, (request, event) => {
console.error('Request error:', event.error);
});
九、性能优化 #
9.1 启用压缩 #
javascript
const server = Hapi.server({
port: 3000,
compression: {
minBytes: 1024
}
});
9.2 启用缓存 #
javascript
server.method('getData', async (key) => {
return await fetchData(key);
}, {
cache: {
expiresIn: 60 * 1000,
generateTimeout: 100
}
});
9.3 连接池 #
javascript
const { Pool } = require('pg');
const pool = new Pool({
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000
});
十、部署检查清单 #
10.1 检查项 #
- [ ] 环境变量配置
- [ ] 数据库连接
- [ ] Redis连接
- [ ] 日志配置
- [ ] 错误处理
- [ ] 健康检查
- [ ] HTTPS配置
- [ ] 监控告警
- [ ] 备份策略
- [ ] 回滚方案
10.2 部署命令 #
bash
pm2 start ecosystem.config.js --env production
pm2 save
pm2 startup
十一、总结 #
部署要点:
| 工具 | 用途 |
|---|---|
| PM2 | 进程管理 |
| Docker | 容器化部署 |
| Nginx | 反向代理 |
| GitHub Actions | CI/CD |
恭喜你完成Hapi.js完全指南的学习!
最后更新:2026-03-28