Better SaaS Docs
代码部署

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

故障排除

常见问题

  1. 端口已被占用

    # 检查端口使用情况
    lsof -i :3000
    
    # 终止进程
    kill -9 <PID>
  2. 数据库连接问题

    # 检查数据库日志
    docker-compose logs db
    
    # 测试连接
    docker-compose exec db psql -U postgres -d bettersaas
  3. 构建失败

    # 清理构建缓存
    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