代码部署
Docker 部署
使用 Docker 容器部署 Better SaaS,实现一致且可扩展的部署方案
Docker 部署
使用 Docker 容器部署 Better SaaS,实现一致、可扩展且便携的跨环境部署。
前置要求
- Docker Engine 20.10+
- Docker Compose 2.0+
- 2GB+ 可用内存
- 基础 Docker 知识
Docker 快速开始
1. 克隆和设置
git clone https://github.com/your-org/better-saas.git
cd better-saas
cp env.example .env
2. 配置环境变量
编辑 .env
文件:
# 数据库
DATABASE_URL=postgresql://postgres:password@db:5432/bettersaas
# 认证
BETTER_AUTH_SECRET=your-super-secret-key-here
BETTER_AUTH_URL=http://localhost:3000
# GitHub OAuth
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# Stripe
STRIPE_SECRET_KEY=sk_test_your-stripe-secret-key
STRIPE_PUBLISHABLE_KEY=pk_test_your-stripe-publishable-key
STRIPE_WEBHOOK_SECRET=whsec_your-webhook-secret
# 文件存储 (Cloudflare R2)
CLOUDFLARE_R2_ACCESS_KEY_ID=your-access-key
CLOUDFLARE_R2_SECRET_ACCESS_KEY=your-secret-key
CLOUDFLARE_R2_BUCKET_NAME=your-bucket-name
CLOUDFLARE_R2_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
3. 构建和运行
# 构建并启动所有服务
docker-compose up -d
# 查看日志
docker-compose logs -f
# 停止服务
docker-compose down
Docker Compose 配置
创建 docker-compose.yml
:
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:password@db:5432/bettersaas
depends_on:
- db
- redis
volumes:
- ./uploads:/app/uploads
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: bettersaas
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
restart: unless-stopped
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: unless-stopped
volumes:
postgres_data:
redis_data:
Dockerfile 配置
创建优化的 Dockerfile
:
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
# 安装 pnpm
RUN npm install -g pnpm
# 复制包文件
COPY package.json pnpm-lock.yaml ./
COPY packages/ ./packages/
# 安装依赖
RUN pnpm install --frozen-lockfile
# 复制源代码
COPY . .
# 构建应用
RUN pnpm build
# 生产阶段
FROM node:18-alpine AS runner
WORKDIR /app
# 安装 pnpm
RUN npm install -g pnpm
# 创建非 root 用户
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# 复制构建的应用
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
# 设置正确的权限
RUN chown -R nextjs:nodejs /app
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
多阶段构建优化
开发环境 Dockerfile
FROM node:18-alpine
WORKDIR /app
RUN npm install -g pnpm
COPY package.json pnpm-lock.yaml ./
RUN pnpm install
COPY . .
EXPOSE 3000
CMD ["pnpm", "dev"]
生产环境 Dockerfile
FROM node:18-alpine AS deps
WORKDIR /app
RUN npm install -g pnpm
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --prod --frozen-lockfile
FROM node:18-alpine AS builder
WORKDIR /app
RUN npm install -g pnpm
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM node:18-alpine AS runner
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
RUN chown -R nextjs:nodejs /app
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
环境特定配置
开发环境
# docker-compose.dev.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
environment:
- NODE_ENV=development
volumes:
- .:/app
- /app/node_modules
depends_on:
- db
- redis
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: bettersaas_dev
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- postgres_dev_data:/var/lib/postgresql/data
volumes:
postgres_dev_data:
生产环境
# docker-compose.prod.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
restart: unless-stopped
depends_on:
- db
- redis
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: bettersaas
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
restart: unless-stopped
volumes:
postgres_data:
redis_data:
数据库迁移
在 Docker 中运行迁移
# 运行数据库迁移
docker-compose exec app pnpm db:migrate
# 填充数据
docker-compose exec app pnpm db:seed
# 重置数据库
docker-compose exec app pnpm db:reset
迁移脚本
创建 scripts/docker-migrate.sh
:
#!/bin/bash
# 等待数据库准备就绪
until docker-compose exec db pg_isready -U postgres; do
echo "等待数据库..."
sleep 2
done
# 运行迁移
docker-compose exec app pnpm db:migrate
# 填充初始数据
docker-compose exec app pnpm db:seed
echo "数据库迁移完成!"
健康检查
应用健康检查
# 添加到 Dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
Docker Compose 健康检查
services:
app:
# ... 其他配置
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
db:
# ... 其他配置
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 30s
timeout: 10s
retries: 3
监控和日志
集中式日志
# 添加到 docker-compose.yml
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
使用 Prometheus 监控
# 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:
安全最佳实践
1. 非 Root 用户
# 创建和使用非 root 用户
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
USER nextjs
2. 安全扫描
# 扫描漏洞
docker scout cves better-saas:latest
# 使用安全扫描器
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image better-saas:latest
3. 密钥管理
# 使用 Docker secrets
services:
app:
secrets:
- db_password
- stripe_secret
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
- STRIPE_SECRET_KEY_FILE=/run/secrets/stripe_secret
secrets:
db_password:
file: ./secrets/db_password.txt
stripe_secret:
file: ./secrets/stripe_secret.txt
性能优化
1. 多阶段构建
使用多阶段构建减少镜像大小:
# 分别构建依赖
FROM node:18-alpine AS deps
# ... 安装生产依赖
FROM node:18-alpine AS builder
# ... 构建应用
FROM node:18-alpine AS runner
# ... 复制构建的应用
2. 层缓存
# 首先复制包文件以获得更好的缓存
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
# 在依赖之后复制源代码
COPY . .
RUN pnpm build
3. 资源限制
services:
app:
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '1'
memory: 1G
故障排除
常见问题
-
端口已被占用
# 检查端口使用情况 lsof -i :3000 # 终止进程 kill -9 <PID>
-
数据库连接问题
# 检查数据库日志 docker-compose logs db # 测试连接 docker-compose exec db psql -U postgres -d bettersaas
-
构建失败
# 清理构建缓存 docker system prune -a # 无缓存重新构建 docker-compose build --no-cache
调试模式
# 使用调试输出运行
DEBUG=* docker-compose up
# 访问容器 shell
docker-compose exec app sh
# 查看容器日志
docker-compose logs -f app
部署命令
# 开发环境
docker-compose -f docker-compose.dev.yml up -d
# 生产环境
docker-compose -f docker-compose.prod.yml up -d
# 包含监控
docker-compose -f docker-compose.yml -f docker-compose.monitoring.yml up -d
# 扩展服务
docker-compose up -d --scale app=3