Ctrl K
ComunidadGuías…

docker-compose.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
services:
  app:
    # 發版時 release.yml 推的映像(linux/amd64、linux/arm64),標籤取自 .env 的 KNOTEBOOK_VERSION。
    # Release 附件版的這個檔由 release.yml 產生:預設標籤換成該版版號、拿掉 build:(只能 pull)。
    # 刻意不設 pull_policy——compose 的預設行為正是要的:
    # - `docker compose up -d`:本機沒有這個映像才 pull;有 build: 時 pull 失敗會改從原始碼 build。
    # - `docker compose pull`:一律重拉。明設 pull_policy: missing 的話,本機已有的標籤(例如 latest)
    #   會被跳過,升級拉不到新版(Compose v2.27 實測)。
    # - `docker compose up -d --build`(repo 裡):一律從原始碼 build(不 pull),產物標成這個映像名。
    image: ghcr.io/sw-willie-wu/knotebook:${KNOTEBOOK_VERSION:-latest}
    build:
      context: .
      dockerfile: docker/Dockerfile
    env_file: .env
    # 日誌輪替上限(issue #50 的治標半):docker 的 json-file driver 預設**沒有**大小
    # 上限,任何能讓 app 持續寫日誌的路徑(不只 #50 那條,未來的都算)最終症狀都是
    # 自架者的磁碟被灌爆。50MB × 5 檔對排錯綽綽有餘;治本(對灌日誌的連線斷線)在
    # collab/server.ts 的訊息預檢。
    logging:
      driver: json-file
      options:
        max-size: 50m
        max-file: "5"
    # 選配:限制 app 能用的 CPU 與記憶體(#398)。設了之後,沒設 PARSE_WORKERS 時 server 會照這裡的上限
    # (容器的 cgroup)推算解析 worker 數:min(CPU − 1,最多 4;floor(記憶體 × 0.5 ÷ PARSE_WORKER_MEMORY_MB)),至少 1。
    # 不設就照主機的 CPU 與記憶體算。怎麼挑數字見 docs/self-hosting.md「Parse workers」。
    # deploy:
    #   resources:
    #     limits:
    #       cpus: "2"
    #       memory: 4g
    # 預設只綁 loopback:public 拓撲(docs/self-hosting.md「Deployment prerequisites」)的假設是
    # app 只透過反代對外曝露;若直接 "3000:3000"(等同 0.0.0.0:3000),docker 會
    # 直接在 iptables 開洞,繞過 host 防火牆規則,讓區網/公網能不經反代直接打到
    # app。Quickstart 的 `curl http://localhost:3000/...` 不受影響(127.0.0.1 對本機
    # 而言就是 localhost)。要用 trusted-LAN plain-http 拓撲,改用下面註解掉的替代寫法。
    ports:
      - "127.0.0.1:3000:3000"
      # LAN mode(trusted-LAN plain-http,見 docs/self-hosting.md「Deployment prerequisites」):
      # 換成 "3000:3000" 會把 app 直接曝露到你的網段(等同 0.0.0.0:3000),並透過
      # docker 自己在 iptables 開的洞繞過 host 防火牆規則——啟用前務必先讀過
      # docs/self-hosting.md 的風險清單(cleartext 密碼/session cookie、無 Secure flag)。
      # - "3000:3000"
    # 上傳圖片持久化——不掛 volume 的話,圖片只存在 container 的可寫層,
    # `docker compose down`/重建 container 會整批遺失。掛載點與 Dockerfile 建的
    # `/app/uploads`(已 chown 給 node)一致,`src/index.ts` 用同一個相對路徑
    # (`process.cwd()/uploads`,WORKDIR 為 /app)解析。
    volumes:
      - uploads:/app/uploads
    # 讓 DATABASE_URL 能用 host.docker.internal 指到「跑 docker 的這台主機」上的 PostgreSQL
    # (Linux 的 docker 預設不提供這個名字)。用內建 db 時用不到,留著無害。見
    # docs/self-hosting.md「Using your own PostgreSQL」。
    extra_hosts:
      - "host.docker.internal:host-gateway"
    # BUNDLED_DB=0(不起內建 db,見下方 db 的 scale)時 compose 不等這個依賴:scale 為 0 的依賴
    # 不等是 Docker Compose v2.3.0 起的有意行為(`shouldWaitForDependency` 的 `GetScale() == 0`
    # 分支,commit 09e0fa94;v2.27 實測同),所以 BUNDLED_DB 需要 Compose v2.3.0 以上。這裡不必寫
    # required: false——寫了的話,內建 db 起不來時 app 也會照樣被啟動,預設起法的失敗行為就變了。
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      # 用 127.0.0.1 而非 localhost:避免容器內 /etc/hosts 或 Node DNS 解析(部分
      # image 的 getaddrinfo 在無 IPv6 時可能先嘗試 ::1)導致的額外延遲/失敗,
      # 明確指定 loopback IPv4 位址。
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/healthz').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s
    restart: unless-stopped

  db:
    image: pgvector/pgvector:pg17
    # 內建 PostgreSQL:預設會起(BUNDLED_DB 未設=1)。改用自己的 PostgreSQL 時在 .env 設
    # BUNDLED_DB=0、並把 DATABASE_URL 指過去——這個容器就不會被建立,已在跑的會被移除
    # (db_data volume 保留)。只接受 0 或 1:非數字插值失敗、負數讓 compose panic、大於 1 會讓
    # 多個 postgres 共用同一個 db_data。
    scale: ${BUNDLED_DB:-1}
    environment:
      POSTGRES_USER: knotebook
      # 可用 shell/.env 的 POSTGRES_PASSWORD 覆寫預設值;注意 Postgres 只在「第一次
      # 初始化空 data 目錄」時套用這個變數(見 docs/known-limitations.md),事後改這裡
      # 不會自動生效。
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-knotebook}
      POSTGRES_DB: knotebook
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      # CMD 陣列形(不經 shell)、走 TCP:
      # - CMD-SHELL 形會讓 sh 留著當 pg_isready 的父程序;逾時時 docker 只殺 sh,孤兒 pg_isready
      #   被 PID 1 的 postmaster 收養,之後以 exit 2 結束會被當成 backend 崩潰、整座 cluster 重啟。
      # - 走 unix socket 的話,第一次初始化(initdb)期間那個只聽 socket 的暫時 server 會讓它提早
      #   回報就緒;走 TCP 要等正式 server 起來才通。
      # timeout 5s 大於 pg_isready 自己的 3 秒連線逾時,讓它自己結束。start_period 60s:首次初始化
      # 較慢的機器在這段期間的失敗不計入 retries,一成功就 healthy,所以快的機器不會因此等更久。
      test: ["CMD", "pg_isready", "--host", "127.0.0.1", "--username", "knotebook", "--dbname", "knotebook"]
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 60s
    restart: unless-stopped

volumes:
  db_data:
  uploads: