跳到主要内容

部署运维完全指南

快速部署方案对比

平台难度成本性能推荐场景
Vercel$0-20/月⭐⭐⭐静态网站+Serverless API
Render⭐⭐$7+/月⭐⭐⭐⭐全栈应用(推荐新手)
Fly.io⭐⭐$5+/月⭐⭐⭐⭐边缘计算
Railway⭐⭐$5+/月⭐⭐⭐快速原型
AWS/GCP⭐⭐⭐⭐⭐$50+/月⭐⭐⭐⭐⭐企业级应用

方案1: Render部署(推荐新手)

1分钟部署步骤

# 1. 准备代码
git init
git add .
git commit -m "Initial commit"

# 2. 推送到GitHub
gh repo create --public --push

# 3. 在Render.com创建新服务
# - 选择 "Web Service"
# - 连接GitHub仓库
# - 构建命令: npm install && npm run build
# - 启动命令: npm start
# - 完成!

render.yaml配置

services:
# Web服务
- type: web
name: realtime-app
env: node
buildCommand: npm install && npm run build
startCommand: npm start
healthCheckPath: /health
envVars:
- key: NODE_ENV
value: production
- key: DATABASE_URL
fromDatabase:
name: postgres-db
property: connectionString
- key: REDIS_URL
fromDatabase:
name: redis-db
property: connectionString

# PostgreSQL数据库
- type: pserv
name: postgres-db
env: postgresql
plan: starter
ipAllowList: []

# Redis
- type: redis
name: redis-db
plan: starter
ipAllowList: []

方案2: Fly.io部署(边缘计算)

部署步骤

# 1. 安装Fly CLI
curl -L https://fly.io/install.sh | sh

# 2. 登录
flyctl auth login

# 3. 初始化应用
flyctl launch

# 4. 部署
flyctl deploy

# 5. 打开应用
flyctl open

fly.toml配置

app = "my-realtime-app"
primary_region = "sjc"

[build]
builder = "heroku/buildpacks:20"

[env]
NODE_ENV = "production"
PORT = "8080"

[[services]]
internal_port = 8080
protocol = "tcp"

[[services.ports]]
port = 80
handlers = ["http"]

[[services.ports]]
port = 443
handlers = ["tls", "http"]

[services.concurrency]
type = "connections"
hard_limit = 1000
soft_limit = 800

[[services.http_checks]]
interval = "10s"
timeout = "2s"
method = "GET"
path = "/health"

# 数据库
[[statics]]
guest_path = "/app/public"
url_prefix = "/static/"

添加PostgreSQL:

flyctl postgres create --name my-app-db
flyctl postgres attach my-app-db

添加Redis:

flyctl redis create

方案3: Docker + AWS/GCP

Dockerfile

# 多阶段构建
FROM node:18-alpine AS builder

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .
RUN npm run build

# 生产镜像
FROM node:18-alpine

WORKDIR /app

# 只复制必要文件
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

ENV NODE_ENV=production
EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"

CMD ["node", "dist/server.js"]

docker-compose.yml(本地开发)

version: '3.8'

services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://postgres:password@db:5432/myapp
REDIS_URL: redis://redis:6379
NODE_ENV: development
volumes:
- ./src:/app/src
- /app/node_modules
depends_on:
db:
condition: service_healthy
redis:
condition: service_started

db:
image: postgres:15-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5

redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redisdata:/data

volumes:
pgdata:
redisdata:

AWS ECS部署

# 1. 创建ECR仓库
aws ecr create-repository --repository-name my-app

# 2. 构建并推送镜像
aws ecr get-login-password | docker login --username AWS --password-stdin <account-id>.dkr.ecr.us-east-1.amazonaws.com
docker build -t my-app .
docker tag my-app:latest <account-id>.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
docker push <account-id>.dkr.ecr.us-east-1.amazonaws.com/my-app:latest

# 3. 创建ECS任务定义和服务(使用AWS Console或CLI)

方案4: Kubernetes(企业级)

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: realtime-app
spec:
replicas: 3
selector:
matchLabels:
app: realtime-app
template:
metadata:
labels:
app: realtime-app
spec:
containers:
- name: app
image: myregistry/realtime-app:latest
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
- name: REDIS_URL
value: "redis://redis-service:6379"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: realtime-app-service
spec:
type: LoadBalancer
selector:
app: realtime-app
ports:
- port: 80
targetPort: 3000
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: realtime-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: realtime-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80

CI/CD自动化

GitHub Actions

# .github/workflows/deploy.yml
name: Deploy to Production

on:
push:
branches: [main]

jobs:
test:
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 linter
run: npm run lint

- name: Run tests
run: npm test

- name: Build
run: npm run build

deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'

steps:
- uses: actions/checkout@v3

- name: Deploy to Render
env:
RENDER_API_KEY: ${{ secrets.RENDER_API_KEY }}
SERVICE_ID: ${{ secrets.RENDER_SERVICE_ID }}
run: |
curl -X POST \
"https://api.render.com/v1/services/$SERVICE_ID/deploys" \
-H "Authorization: Bearer $RENDER_API_KEY" \
-H "Content-Type: application/json"

notify:
needs: deploy
runs-on: ubuntu-latest
if: always()
steps:
- name: Notify Slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'Deployment ${{ job.status }}'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

监控告警

1. Prometheus + Grafana

# docker-compose.monitoring.yml
version: '3.8'

services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus

grafana:
image: grafana/grafana
ports:
- "3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana

volumes:
prometheus-data:
grafana-data:
# prometheus.yml
global:
scrape_interval: 15s

scrape_configs:
- job_name: 'app'
static_configs:
- targets: ['app:3000']

- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']

- job_name: 'redis'
static_configs:
- targets: ['redis-exporter:9121']

2. 日志聚合(ELK Stack)

version: '3.8'

services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.5.0
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"

logstash:
image: docker.elastic.co/logstash/logstash:8.5.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf

kibana:
image: docker.elastic.co/kibana/kibana:8.5.0
ports:
- "5601:5601"

性能优化

1. 数据库优化

-- 创建索引
CREATE INDEX idx_messages_room_created
ON messages(room_id, created_at DESC);

-- 分区表(按时间)
CREATE TABLE messages_2024_01 PARTITION OF messages
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');

-- 定期清理旧数据
DELETE FROM messages
WHERE created_at < NOW() - INTERVAL '90 days';

2. Redis优化

# redis.conf
maxmemory 256mb
maxmemory-policy allkeys-lru
save "" # 禁用RDB持久化(使用AOF)
appendonly yes
appendfsync everysec

3. Nginx优化

# nginx.conf
worker_processes auto;
worker_connections 4096;

http {
# Gzip压缩
gzip on;
gzip_types text/plain application/json application/javascript;

# 缓存
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m;

# 限流
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

server {
listen 80;

# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}

# WebSocket
location /ws {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}

# API限流
location /api {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://backend;
}
}
}

备份策略

1. 数据库备份

#!/bin/bash
# backup.sh

DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups"
DB_NAME="myapp"

# PostgreSQL备份
pg_dump $DB_NAME | gzip > "$BACKUP_DIR/db_$DATE.sql.gz"

# 上传到S3
aws s3 cp "$BACKUP_DIR/db_$DATE.sql.gz" s3://my-backups/db/

# 保留最近30天
find $BACKUP_DIR -name "db_*.sql.gz" -mtime +30 -delete

# 定时任务
# crontab -e
# 0 2 * * * /path/to/backup.sh

2. Redis备份

# 自动AOF重写
redis-cli BGREWRITEAOF

# 复制AOF文件
cp /var/lib/redis/appendonly.aof /backups/redis_$(date +%Y%m%d).aof

安全加固

1. 环境变量管理

# 不要将secrets提交到git
echo ".env" >> .gitignore

# 使用secrets管理工具
# AWS Secrets Manager
aws secretsmanager get-secret-value --secret-id prod/database/url

# 或使用dotenv-vault
npx dotenv-vault push
npx dotenv-vault pull production

2. SSL证书

# Let's Encrypt免费证书
certbot --nginx -d yourdomain.com -d www.yourdomain.com

# 自动续期
crontab -e
0 0 * * * certbot renew --quiet

3. 防火墙配置

# UFW(Ubuntu)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

应急响应

快速回滚

# Docker
docker ps # 找到旧版本的container ID
docker start <old-container-id>
docker stop <new-container-id>

# Kubernetes
kubectl rollout undo deployment/realtime-app

# Render
# 在Dashboard中选择之前的deploy并点击"Redeploy"

紧急扩容

# Kubernetes
kubectl scale deployment realtime-app --replicas=10

# Docker Swarm
docker service scale myapp=10

成本优化建议

  1. 使用Spot实例(节省70%)
  2. 设置自动伸缩(按需付费)
  3. 使用CDN(减少源站流量)
  4. 数据库连接池(减少数据库规格)
  5. Redis作为缓存(减少数据库查询)
  6. 定期清理日志(减少存储成本)

部署检查清单

部署前确认:

  • 环境变量已配置
  • 数据库迁移已完成
  • SSL证书已配置
  • 健康检查endpoint已实现
  • 日志已配置
  • 监控已设置
  • 备份策略已实施
  • 告警规则已配置
  • 文档已更新
  • 团队已知晓

部署后验证:

  • 应用可以访问
  • WebSocket连接正常
  • 数据库连接正常
  • Redis连接正常
  • 日志正常输出
  • 监控指标正常
  • 负载测试通过
  • 回滚计划已验证

推荐学习路径:

  1. 新手: Render一键部署
  2. 进阶: Docker + Fly.io
  3. 高级: Kubernetes + AWS

选择适合你的方案,从简单开始!