diff --git a/README.md b/README.md index 0b67e8e..a14ff2f 100644 --- a/README.md +++ b/README.md @@ -48,27 +48,34 @@ bash -c "$(curl -fsSLk https://release.baizhi.cloud/panda-wiki/manager.sh)" > 关于安装与部署的更多细节请参考 [安装 PandaWiki](https://pandawiki.docs.baizhi.cloud/node/01971602-bb4e-7c90-99df-6d3c38cfd6d5)。 -### 方式二:自行构建部署(本仓库修改版,功能全解锁) +### 方式二:一键部署脚本(本仓库修改版,功能全解锁) -推荐使用本仓库提供的 Docker Compose 方案自行构建,所有商业功能限制已移除。 +推荐使用本仓库提供的 `deploy.sh` 一键部署,所有商业功能限制已移除。 ```bash -# 1. 克隆本仓库 -git clone && cd PandaWiki +# 1. 将项目传输到服务器 +scp -r PandaWiki-3.85.0 user@your-server:/home/user/ -# 2. 创建环境变量配置 -cp .env.example .env # 修改密码等敏感信息 +# 2. 进入项目目录 +cd /home/user/PandaWiki-3.85.0 -# 3. 构建 Docker 镜像 -docker build -f backend/Dockerfile.api -t panda-wiki-api:latest ./backend -docker build -f backend/Dockerfile.consumer -t panda-wiki-consumer:latest ./backend +# 3. 给脚本添加执行权限 +chmod +x deploy.sh -# 4. 启动全部服务 -docker compose up -d +# 4. 一键部署 (自动构建镜像 + 启动全部服务) +./deploy.sh +``` -# 5. 访问 -# 管理后台: http://服务器IP:2443 -# 用户名: admin,密码见 .env 中 ADMIN_PASSWORD +部署完成后,脚本会自动生成随机密码并保存在 `.env` 文件中,同时输出访问地址和登录信息。 + +```bash +# 其他常用操作 +./deploy.sh --status # 查看服务运行状态 +./deploy.sh --restart # 重启所有服务 +./deploy.sh --stop # 停止所有服务 +./deploy.sh --logs # 查看实时日志 +./deploy.sh --skip-build # 跳过构建,直接启动已有镜像 +./deploy.sh --clean # 清理所有容器和数据 (危险!) ``` > 详细部署说明(含 Ubuntu 22.04 内网部署、离线部署、AI 模型配置)请参考: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9f04fe2 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,187 @@ +version: '3.8' + +services: + # ============================================ + # 基础设施 + # ============================================ + + postgres: + image: postgres:16-alpine + container_name: panda-wiki-postgres + restart: unless-stopped + environment: + POSTGRES_USER: panda-wiki + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-ChangeMe123!} + POSTGRES_DB: panda-wiki + volumes: + - pg_data:/var/lib/postgresql/data + networks: + - panda-wiki + healthcheck: + test: ["CMD-SHELL", "pg_isready -U panda-wiki"] + interval: 5s + timeout: 5s + retries: 10 + + redis: + image: redis:7-alpine + container_name: panda-wiki-redis + restart: unless-stopped + command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-ChangeMe123!} + volumes: + - redis_data:/data + networks: + - panda-wiki + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-ChangeMe123!}", "ping"] + interval: 5s + timeout: 5s + retries: 10 + + nats: + image: nats:2-alpine + container_name: panda-wiki-nats + restart: unless-stopped + command: > + -js + -m 8222 + --user ${NATS_USER:-panda-wiki} + --pass ${NATS_PASSWORD:-ChangeMe123!} + networks: + - panda-wiki + + minio: + image: minio/minio:latest + container_name: panda-wiki-minio + restart: unless-stopped + command: server /data --console-address ":9001" + environment: + MINIO_ROOT_USER: ${S3_ACCESS_KEY:-s3panda-wiki} + MINIO_ROOT_PASSWORD: ${S3_SECRET_KEY:-ChangeMe123!} + volumes: + - minio_data:/data + networks: + - panda-wiki + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 10s + timeout: 5s + retries: 10 + + # ============================================ + # 后端服务 + # ============================================ + + api: + build: + context: ./backend + dockerfile: Dockerfile.api + image: panda-wiki-api:latest + container_name: panda-wiki-api + restart: unless-stopped + environment: + PG_DSN: "host=panda-wiki-postgres user=panda-wiki password=${POSTGRES_PASSWORD:-ChangeMe123!} dbname=panda-wiki port=5432 sslmode=disable TimeZone=Asia/Shanghai" + MQ_NATS_SERVER: "nats://panda-wiki-nats:4222" + NATS_USER: ${NATS_USER:-panda-wiki} + NATS_PASSWORD: ${NATS_PASSWORD:-ChangeMe123!} + REDIS_ADDR: "panda-wiki-redis:6379" + REDIS_PASSWORD: ${REDIS_PASSWORD:-ChangeMe123!} + S3_ENDPOINT: "panda-wiki-minio:9000" + S3_ACCESS_KEY: ${S3_ACCESS_KEY:-s3panda-wiki} + S3_SECRET_KEY: ${S3_SECRET_KEY:-ChangeMe123!} + JWT_SECRET: ${JWT_SECRET:-$(openssl rand -hex 32)} + ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123} + RAG_CT_RAG_BASE_URL: ${RAG_BASE_URL:-http://host.docker.internal:5050} + LOG_LEVEL: ${LOG_LEVEL:-0} + ENV: ${ENV:-production} + SENTRY_ENABLED: "false" + ports: + - "${API_PORT:-8000}:8000" + networks: + - panda-wiki + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + minio: + condition: service_healthy + + consumer: + build: + context: ./backend + dockerfile: Dockerfile.consumer + image: panda-wiki-consumer:latest + container_name: panda-wiki-consumer + restart: unless-stopped + environment: + PG_DSN: "host=panda-wiki-postgres user=panda-wiki password=${POSTGRES_PASSWORD:-ChangeMe123!} dbname=panda-wiki port=5432 sslmode=disable TimeZone=Asia/Shanghai" + MQ_NATS_SERVER: "nats://panda-wiki-nats:4222" + NATS_USER: ${NATS_USER:-panda-wiki} + NATS_PASSWORD: ${NATS_PASSWORD:-ChangeMe123!} + REDIS_ADDR: "panda-wiki-redis:6379" + REDIS_PASSWORD: ${REDIS_PASSWORD:-ChangeMe123!} + S3_ENDPOINT: "panda-wiki-minio:9000" + S3_ACCESS_KEY: ${S3_ACCESS_KEY:-s3panda-wiki} + S3_SECRET_KEY: ${S3_SECRET_KEY:-ChangeMe123!} + JWT_SECRET: ${JWT_SECRET:-$(openssl rand -hex 32)} + RAG_CT_RAG_BASE_URL: ${RAG_BASE_URL:-http://host.docker.internal:5050} + LOG_LEVEL: ${LOG_LEVEL:-0} + ENV: ${ENV:-production} + SENTRY_ENABLED: "false" + networks: + - panda-wiki + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + + # ============================================ + # 前端 - 管理后台 (Nginx + React) + # 容器内 Nginx 监听 8080,对外暴露 ${ADMIN_PORT:-2443} + # ============================================ + + admin: + build: + context: ./web + dockerfile: Dockerfile.admin + image: panda-wiki-admin:latest + container_name: panda-wiki-admin + restart: unless-stopped + ports: + - "${ADMIN_PORT:-2443}:8080" + networks: + - panda-wiki + depends_on: + - api + + # ============================================ + # 前端 - Wiki 用户端 (Next.js) + # ============================================ + + app: + build: + context: ./web + dockerfile: Dockerfile.app + image: panda-wiki-app:latest + container_name: panda-wiki-app + restart: unless-stopped + ports: + - "${APP_PORT:-3010}:3010" + networks: + - panda-wiki + depends_on: + - api + +volumes: + pg_data: + driver: local + redis_data: + driver: local + minio_data: + driver: local + +networks: + panda-wiki: + driver: bridge diff --git a/web/.dockerignore b/web/.dockerignore new file mode 100644 index 0000000..7df1f01 --- /dev/null +++ b/web/.dockerignore @@ -0,0 +1,7 @@ +node_modules +dist +.next +.turbo +.git +**/node_modules +**/dist diff --git a/web/Dockerfile.admin b/web/Dockerfile.admin new file mode 100644 index 0000000..5d3fbe3 --- /dev/null +++ b/web/Dockerfile.admin @@ -0,0 +1,51 @@ +# ============================================ +# PandaWiki 管理后台 - 多阶段构建 +# 构建上下文: ./web 目录 +# ============================================ + +FROM node:22-alpine AS builder + +WORKDIR /build + +# 安装 pnpm +RUN corepack enable && corepack prepare pnpm@10 --activate + +# 复制 workspace 配置和锁文件 +COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./ + +# 复制所有 workspace 包的 package.json +COPY packages/icons/package.json packages/icons/ +COPY packages/themes/package.json packages/themes/ +COPY packages/ui/package.json packages/ui/ +COPY admin/package.json admin/ +COPY app/package.json app/ + +# 安装依赖 +RUN pnpm install --frozen-lockfile + +# 复制源码 +COPY packages/icons/ packages/icons/ +COPY packages/themes/ packages/themes/ +COPY packages/ui/ packages/ui/ +COPY admin/ admin/ + +# 构建管理后台 +RUN pnpm --filter panda-wiki-admin build + +# ============================================ +# 运行时镜像 (Nginx) +# ============================================ + +FROM nginx:alpine + +# 复制构建产物 +COPY --from=builder /build/admin/dist /opt/frontend/dist + +# 复制 Nginx 配置 +COPY admin/server.conf /etc/nginx/conf.d/server.conf +COPY admin/nginx.conf /etc/nginx/nginx.conf +COPY admin/ssl /etc/nginx/ssl + +EXPOSE 8080 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/web/Dockerfile.app b/web/Dockerfile.app new file mode 100644 index 0000000..08cb768 --- /dev/null +++ b/web/Dockerfile.app @@ -0,0 +1,68 @@ +# ============================================ +# PandaWiki Wiki 用户端 - 多阶段构建 +# 构建上下文: ./web 目录 +# ============================================ + +FROM node:22-alpine AS builder + +WORKDIR /build + +# 安装 pnpm +RUN corepack enable && corepack prepare pnpm@10 --activate + +# 复制 workspace 配置和锁文件 +COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./ + +# 复制所有 workspace 包的 package.json +COPY packages/icons/package.json packages/icons/ +COPY packages/themes/package.json packages/themes/ +COPY packages/ui/package.json packages/ui/ +COPY admin/package.json admin/ +COPY app/package.json app/ + +# 安装依赖 +RUN pnpm install --frozen-lockfile + +# 复制源码 (app 构建需要 workspace 包) +COPY packages/icons/ packages/icons/ +COPY packages/themes/ packages/themes/ +COPY packages/ui/ packages/ui/ +COPY app/ app/ + +# 构建 Next.js 应用 +RUN pnpm --filter panda-wiki-app build + +# ============================================ +# 运行时镜像 +# ============================================ + +FROM node:22-alpine AS runner + +ENV NODE_ENV=production + +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nextjs -u 1001 + +WORKDIR /app + +# 复制 public 目录 +COPY --from=builder --chown=nextjs:nodejs /build/app/public ./app/public + +# 复制 standalone 构建输出 +COPY --from=builder --chown=nextjs:nodejs /build/app/dist/standalone ./ + +# 复制静态资源 +COPY --from=builder --chown=nextjs:nodejs /build/app/dist/static ./app/dist/static + +# 如果存在 public 下的静态资源也复制 +RUN mkdir -p app/public && \ + cp -r /build/app/public/. app/public/ 2>/dev/null || true + +USER nextjs + +EXPOSE 3010 + +ENV PORT=3010 +ENV HOSTNAME="0.0.0.0" + +CMD ["node", "app/server.js"]