Invidious高性能部署:Web 与 Worker 读写分离架构

目錄

通过 Docker Compose 实现 Invidious 的读写分离与性能优化,包含通用 Docker 与 1Panel 面板两种部署方案,大幅提升私有 YouTube 前端的响应速度。

🌟 核心架构亮点

  • 架构分离:专门的 Worker 容器处理耗时任务,Web 容器仅负责渲染,互不干扰。
  • 资源隔离:针对性分配线程资源,防止内存泄露。
  • 极速交互:关闭 Web 端的非必要数据库写入,提升并发处理能力。
  • 网络优化:海外服务端 + 国内客户端依然能正常加载字幕(无需客户端代理)。

📚 官方资源引用


🛠️ 部署前准备

无论使用哪种部署方式,都需要先准备好目录结构和初始化文件。

1. 规划目录

我们需要两个核心文件挂载到数据库容器中,用于初始化数据结构。

  1. 下载官方初始化 SQL 脚本:init-invidious-db.sh
  2. 创建如下目录结构:
invidious/
├── config/
│   └── sql/               # 存放额外的 SQL update 脚本(如有)
└── docker/
    └── init-invidious-db.sh

🚀 方式一:Docker Compose 通用部署 (CLI)

适用于所有 Linux 发行版,直接使用命令行管理。

1. 创建 docker-compose.yml

将以下配置保存为 docker-compose.yml

⚠️ 注意:请务必修改配置中的 your_secure_passwordGENERATE_RANDOM_KEY 等敏感信息。

version: "3.8"

services:
  # --- 1. Web 节点 (只负责前端交互,速度最快) ---
  invidious:
    image: quay.io/invidious/invidious:latest
    container_name: invidious-web
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      INVIDIOUS_CONFIG: |
        db:
          dbname: invidious
          user: kemal
          password: your_secure_db_password # [修改] 数据库密码
          host: invidious-db
          port: 5432
        check_tables: true
        
        # 性能优化:关闭通知与写入
        enable_user_notifications: false
        use_innertube_for_captions: true # 使用 Google 内部 API 获取字幕,更稳定
        playlist_length_limit: 500
        
        # 架构分离:完全禁用此容器的后台任务
        channel_threads: 0
        feed_threads: 0
        jobs:
          refresh_channels: { enable: false }
          refresh_feeds: { enable: false }
          clear_expired_items: { enable: false }
             
        # 外部服务配置
        invidious_companion:
          - private_url: "http://companion:8282/companion"
            public_url: "https://your-domain.com/companion" # [修改] 您的域名
        invidious_companion_key: "GENERATE_A_RANDOM_KEY_1" # [修改] 随机字串
        hmac_key: "GENERATE_A_RANDOM_KEY_2"            # [修改] 必须与 Worker 保持一致
        
    healthcheck:
      test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/stats || exit 1
      interval: 30s
      timeout: 5s
    logging: &logging
      options:
        max-size: "1G"
        max-file: "4"
    depends_on:
      - invidious-db

  # --- 2. Worker 节点 (只负责脏活累活) ---
  invidious-worker:
    image: quay.io/invidious/invidious:latest
    container_name: invidious-worker
    restart: unless-stopped
    environment:
      INVIDIOUS_CONFIG: |
        db:
          dbname: invidious
          user: kemal
          password: your_secure_db_password # [修改] 与 db 保持一致
          host: invidious-db
          port: 5432
        check_tables: true
        
        # 架构分离:在此容器启用后台任务
        channel_threads: 2
        feed_threads: 2
        jobs:
          refresh_channels: { enable: true }
          refresh_feeds: { enable: true }
          clear_expired_items: { enable: true }
             
        hmac_key: "GENERATE_A_RANDOM_KEY_2" # [修改] 必须与 Web 端一致
        
    logging: *logging
    depends_on:
      - invidious-db

  # --- 3. 辅助组件 ---
  companion:
    image: quay.io/invidious/invidious-companion:latest
    container_name: invidious-companion
    environment:
      - SERVER_SECRET_KEY=GENERATE_A_RANDOM_KEY_1 # [修改] 与上面的 companion_key 一致
    restart: unless-stopped
    logging: *logging
    read_only: true
    volumes:
      - companioncache:/var/tmp/youtubei.js:rw
    security_opt:
      - no-new-privileges:true

  # --- 4. 数据库 ---
  invidious-db:
    image: postgres:14
    container_name: invidious-db
    restart: unless-stopped
    volumes:
      - postgresdata:/var/lib/postgresql/data
      # 挂载相对路径的初始化脚本
      - ./config/sql:/config/sql
      - ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
    environment:
      POSTGRES_DB: invidious
      POSTGRES_USER: kemal
      POSTGRES_PASSWORD: your_secure_db_password # [修改]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]

volumes:
  postgresdata:
  companioncache:

2. 启动服务

docker compose up -d

💻 方式二:1Panel 面板部署 (推荐)

结合官方文档与 1Panel 特性,这是最稳妥的安装方式。官方强烈建议先克隆仓库以获取必要的数据库初始化脚本。

1. 准备项目文件 (终端操作)

通过终端直接拉取官方源码,确保数据库初始化环境完整。

  1. 登录 1Panel,进入 主机 -> 终端(或使用 SSH)。
  2. 执行以下命令创建目录并下载文件:
# 进入 1Panel 应用目录
cd /opt/1panel/apps

# 创建并进入 invidious 目录
mkdir -p invidious && cd invidious

# 克隆官方仓库到当前目录(注意最后的点 ".")
git clone https://github.com/iv-org/invidious.git .

2. 生成安全密钥

Invidious 需要两个唯一密钥。在终端继续执行:

# 生成第一个密钥 (用于 HMAC_KEY)
# 若提示 pwgen command not found,可改用: openssl rand -hex 16
pwgen 16 1

# 生成第二个密钥 (用于 invidious_companion_key)
pwgen 16 1

记下这两个密钥,下一步会用到。

3. 创建容器编排

  1. 进入 1Panel 容器 -> 编排 -> 创建编排
  2. 模式选择: 点击顶部的“编辑”圆点(不要选“路径选择”)。
  3. 文件夹: 填写 invidious(系统会自动识别为 /opt/1panel/docker/compose/invidious)。
  4. 内容: 粘贴下方的 YAML。
version: "3"

services:
  # --- 1. Web 节点 ---
  invidious:
    image: quay.io/invidious/invidious:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"  # 仅监听本地
    environment:
      INVIDIOUS_CONFIG: |
        db:
          dbname: invidious
          user: kemal
          password: your_secure_db_password # [修改] 数据库密码
          host: invidious-db
          port: 5432
        check_tables: true
        
        # 性能优化
        enable_user_notifications: false
        use_innertube_for_captions: true
        playlist_length_limit: 500
        channel_threads: 0
        feed_threads: 0
        jobs:
          refresh_channels: { enable: false }
          refresh_feeds: { enable: false }
          clear_expired_items: { enable: false }
        
        # 辅助服务配置
        invidious_companion:
          - private_url: "http://companion:8282/companion"
            public_url: "https://your-domain.com/companion" # [修改] 您的域名
        invidious_companion_key: "KEY_1_FROM_STEP_2"       # [修改] 填写上面生成的第一个密钥
        hmac_key: "KEY_2_FROM_STEP_2"                   # [修改] 填写上面生成的第二个密钥
        
    depends_on:
      - invidious-db

  # --- 2. Worker 节点 ---
  invidious-worker:
    image: quay.io/invidious/invidious:latest
    restart: unless-stopped
    environment:
      INVIDIOUS_CONFIG: |
        db:
          dbname: invidious
          user: kemal
          password: your_secure_db_password # [修改]
          host: invidious-db
          port: 5432
        check_tables: true
        # 启用后台脏活
        channel_threads: 2
        feed_threads: 2
        jobs:
          refresh_channels: { enable: true }
          refresh_feeds: { enable: true }
          clear_expired_items: { enable: true }
        
        hmac_key: "KEY_2_FROM_STEP_2" # [修改] 必须与 Web 端一致
    depends_on:
      - invidious-db

  # --- 3. Companion (辅助代理) ---
  companion:
    image: quay.io/invidious/invidious-companion:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:8282:8282" # 映射 8282 端口供 Nginx 反代
    environment:
      - SERVER_SECRET_KEY=KEY_1_FROM_STEP_2 # [修改]
    read_only: true
    volumes:
      - companioncache:/var/tmp/youtubei.js:rw
    security_opt:
      - no-new-privileges:true

  # --- 4. 数据库 ---
  invidious-db:
    image: postgres:14
    restart: unless-stopped
    volumes:
      - postgresdata:/var/lib/postgresql/data
      # 使用 1Panel 绝对路径挂载
      - /opt/1panel/apps/invidious/config/sql:/config/sql
      - /opt/1panel/apps/invidious/docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
    environment:
      POSTGRES_DB: invidious
      POSTGRES_USER: kemal
      POSTGRES_PASSWORD: your_secure_db_password # [修改]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]

volumes:
  postgresdata:
  companioncache:

4. 创建网站并开启 HTTPS

  1. 在 1Panel 网站 -> 创建网站
  2. 运行环境: 选择 反向代理
  3. 主域名: 填写您的域名(如 vid.example.com)。
  4. 代理地址: 填写 127.0.0.1:3000
  5. 创建成功后,进入该网站的 网站设置 -> HTTPS,申请并启用证书。

5. 修改 Nginx 配置 (配置 Companion 转发)

这是确保视频加载流畅的关键一步。我们需要手动注入 Companion 的转发规则。

  1. 进入 网站设置 -> 配置文件
  2. 找到 location ^~ / { ... } 块,在其下方(即 } 之后)添加以下代码:
    # === Invidious Companion 专用规则 ===
    location /companion {
        proxy_pass http://127.0.0.1:8282;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
  1. 点击 保存并重载

5. 资源限制和压榨配置的版本

version: "3"

services:
  # ==========================================
  # 1. Web 服务 (只负责前端交互)
  # ==========================================
  invidious:
    image: ghcr.io/sjnhnp/invidious:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    deploy:
      resources:
        limits:
          cpus: '0.80'     # 限制使用 80% CPU
          memory: 400M     # 限制内存 400M
    environment:
      INVIDIOUS_CONFIG: |
        db:
          dbname: invidious
          user: kemal
          password: kemal
          host: invidious-db
          port: 5432
          pool: 5          # 连接池限制
          idle_pool: 1
        check_tables: true
        
        # --- 性能优化 ---
        enable_user_notifications: false
        use_innertube_for_captions: true
        playlist_length_limit: 100
        cache_annotations: false
        statistics_enabled: false
        
        # --- 默认偏好设置 ---
        default_user_preferences:
          local: false      # 默认关闭代理
          quality: "dash"
          autoplay: false
        
        # --- 架构分离:禁用后台任务 ---
        channel_threads: 0
        feed_threads: 0
        jobs:
          refresh_channels:
             enable: false
          refresh_feeds:
             enable: false
          clear_expired_items:
             enable: false
             
        # --- 外部服务 ---
        invidious_companion:
          - private_url: "http://companion:8282/companion"
            public_url: "https://techcrunch.9527000.xyz/companion"
        invidious_companion_key: "Xo3ietu6lu4ealua"
        hmac_key: "oe7af5yaeGh8Ilio"
        
    healthcheck:
      test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/stats || exit 1
      interval: 30s
      timeout: 5s
      retries: 2
    logging: &logging
      options:
        max-size: "10m"
        max-file: "3"
    depends_on:
      - invidious-db
      - companion          # 等待 Companion 启动

  # ==========================================
  # 2. Worker 服务 (后台任务)
  # ==========================================
  invidious-worker:
    image: ghcr.io/sjnhnp/invidious:latest
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '0.20'     # 仅允许 20% CPU
          memory: 256M
    environment:
      INVIDIOUS_CONFIG: |
        db:
          dbname: invidious
          user: kemal
          password: kemal
          host: invidious-db
          port: 5432
          pool: 3
        check_tables: true
        
        # --- 启用后台任务 ---
        channel_threads: 1 # 单线程
        feed_threads: 1    # 单线程
        jobs:
          refresh_channels:
             enable: true
          refresh_feeds:
             enable: true
          clear_expired_items:
             enable: true
             
        hmac_key: "oe7af5yaeGh8Ilio"
        
    logging: *logging
    depends_on:
      - invidious-db
      - companion

  # ==========================================
  # 3. 辅助服务
  # ==========================================
  companion:
    image: quay.io/invidious/invidious-companion:latest
    deploy:
      resources:
        limits:
          memory: 300M    # 【修正】放宽到 300M 以防启动崩溃
    ports:
      - "127.0.0.1:8282:8282"
    environment:
      - SERVER_SECRET_KEY=Xo3ietu6lu4ealua
    restart: unless-stopped
    logging: *logging
    cap_drop:
      - ALL
    read_only: true
    volumes:
      - companioncache:/var/tmp/youtubei.js:rw
    security_opt:
      - no-new-privileges:true

  # ==========================================
  # 4. 数据库
  # ==========================================
  invidious-db:
    image: docker.io/library/postgres:14
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 300M
    volumes:
      - postgresdata:/var/lib/postgresql/data
      - /opt/1panel/apps/invidious/config/sql:/config/sql
      - /opt/1panel/apps/invidious/docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
    environment:
      POSTGRES_DB: invidious
      POSTGRES_USER: kemal
      POSTGRES_PASSWORD: kemal
      POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256"
    command: 
      - "postgres"
      - "-c"
      - "shared_buffers=128MB"
      - "-c"
      - "max_connections=50"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]

volumes:
  postgresdata:
  companioncache:

🧐 常见问题 Q&A

Q: 为什么要有两个 quay.io/invidious/invidious 容器?

A: 术业有专攻。 Invidious 的后台刷新任务(更新订阅用的)非常消耗资源。如果把这些任务和处理用户访问放在同一个容器里,一旦后台开始大量刷新,前台网页就会卡顿。拆分后,Web 容器永远保持空闲响应用户,Worker 容器慢慢在后台跑任务,互不影响。

評論