FR-039 evidence-agent 安裝精靈(install.sh)— 設計文件

項目 內容
FR 編號 FR-039(子題:客戶端部署體驗優化)
提出日期 2026-06-19
關聯 母設計 design.md(分散式檔案 agent)、design-agent-auth.md(mTLS 認證 v2)、deploy/README.md(現行手動部署手冊)
實作 repo evidence-agent(deploy/install.sh 等), compliance-manager-be
狀態 設計定案(2026-06-19 brainstorm 完成,user 核可)
範圍 把客戶端 8 步有序、有暗坑的手動部署,收斂成「解壓一包 → ./install.sh → 回答 4 題 → 完成」
出 scope 不換掉 Docker 架構;不做 SQLite / in-app mTLS(後續 B 方向);不做 .deb/單一執行檔(後續 C,已評估勸退);不碰雲端側 PKI / token 產生

1. 問題與動機

1.1 現況痛點

現行客戶端部署(見 deploy/README.md)要在客戶 Linux server 做 8 個有先後依賴、有暗坑的手動步驟:

  1. 裝 Docker + docker compose
  2. docker save | ssh docker load 搬 image
  3. 手填 deploy/.env 約 12 個變數
  4. collect-host-id.sh 抓 host MAC
  5. file-agent + agent-db 等註冊拿憑證
  6. 確認 certs/ 有檔
  7. --profile full 起 nginx(順序顛倒就起不來)
  8. 回雲端 FE 設 storage-config 指向這台

痛點集中三處:步驟有先後依賴(憑證沒簽回 nginx 起不來)、手填一堆有暗坑的 env(AGENT_BASE_URL 必須 https://...:8443、MinIO 要填 LAN IP 不能用 service 名、PDF_CACHE_DIR 要同裝置)、moving parts 多(3 容器 + host-id 腳本)。

1.2 方向決策(已選定)

評估過三個方向:

方向 做法 結論
**A(本設計) install.sh 安裝精靈,Docker 架構不動 採用**:風險最低、最快見效
B 砍 moving parts(SQLite + in-app mTLS,3 容器→1) 後續再評估;要動 agent 程式
C 原生安裝檔(.deb / PyInstaller 單一執行檔) 勸退:LibreOffice(約 400MB 原生)+ DB 兩個硬依賴,單一執行檔/套件會一直跟原生依賴打架,失去 Docker 打包環境一致的價值

為何 Docker 是資產不是負擔:agent 硬依賴 LibreOffice(預覽轉檔,設計 §3.4 刻意放客戶端不可拿掉),Docker 幫你把它跟環境一致地打包。問題從來不是「用 Docker」,而是部署步驟太碎。精靈解的是步驟,不換架構。


2. 出貨形態

一個壓縮包 evidence-agent-deploy-<version>.tar.gz,內含:

evidence-agent-deploy-0.1.0/
├── install.sh                      ← 安裝精靈(本設計主體)
├── docker-compose.yml              ← 沿用既有
├── nginx/agent.conf                ← 沿用既有
├── collect-host-id.sh              ← 沿用既有(精靈自動呼叫)
├── .env.example                    ← 沿用既有
├── answers.conf.example            ← 新增:精簡必填清單(無人值守用)
├── README.md                       ← 部署手冊(精簡版,指回精靈)
└── evidence-agent-0.1.0.image.tar  ← image tar(精靈偵測缺 image 時自動 load)

部署人員體驗:解壓一包 → ./install.sh → 回答 4 題 → 完成


3. 精靈四階段

① Preflight 檢查(缺什麼清楚報錯停下,不自動修)

檢查項 缺了怎麼辦
Docker + compose plugin 報「請先安裝 Docker,參考 <連結>」並停(不自動裝 — 跨發行版坑多、企業客戶常有自己的安裝政策/離線環境)
是 Linux(/sys/class/dmi/id/product_uuid/etc/machine-id 可讀) 報錯停(指紋算不出來)
8443 port 未被占用 報「8443 已被占用」並停
image 在不在 不在 → 自動 docker load 同目錄 *.image.tar;tar 也找不到才報錯

② 設定收集(互動為主 + 無人值守接口)

模式:

  • 預設互動式,即時問即時填
  • --config answers.conf / --non-interactive:讀設定檔跑完,適合大量複製部署 / 部署文件
  • 互動模式跑完會把答案存成 answers.conf(不含密碼),方便下次重灌或複製到別台

要問的(精簡到 4 類):

  1. 儲存模式 minio / local(minio 才續問 MINIO_ENDPOINT/ACCESS_KEY/SECRET_KEY/BUCKET)
  2. CLOUD_ENDPOINT(雲端 base,不含 /api/1.0)
  3. REGISTRATION_TOKEN(雲端管理頁產生的該 tenant token)
  4. DB 密碼(可選「自動產一組強密碼」,免部署人員自己想)

自動推導,不用問:

  • AGENT_BASE_URL ← 偵測預設路由網卡 IP 組成 https://<ip>:8443,顯示並請部署人員確認「雲端能用這 IP 連到這台嗎?」可覆寫。這是手冊裡最常踩的暗坑(填成 http:8080 會讓雲端報 FILE_AGENT_500005),精靈幫擋。
  • AGENT_AUTH_MODE=full(正式一律 full)、AGENT_IMAGEAGENT_VERSION 固定值

產出:

  • .env(含密碼,chmod 600,不入版控)
  • answers.conf(不含任何密碼,可版控 / 複製到別台)

重跑:偵測到既有 .env / answers.conf 就載入當預設,部署人員只改要改的。

③ 啟動編排(精靈最大價值 — 自動解掉憑證兩段式)

  1. 自動跑 collect-host-id.sh 抓 host MAC
  2. docker compose up -d file-agent agent-db
  3. 輪詢等待:等 file-agent /health 200 certs/agent.crt 出現(= enroll 成功);有 timeout;失敗就 docker compose logs --tail file-agent 把錯誤印出來停下
  4. 憑證就緒才 docker compose --profile full up -d nginx

部署人員完全不用知道「先 agent 後 nginx」這個順序陷阱。

④ 自我驗證 + 交棒(本機這側驗到位,資料面交棒雲端)

  • file-agent /health 200、certs/ 憑證齊、agent log 出現 agent enrolled + heartbeat
  • 本機 curl -sk https://localhost:8443(預期被 400 擋 → 證明 TLS + port 8443 通、nginx mTLS 起得來)
  • 印出明確下一步:
    • 回雲端 FE storage-config 指向本台(base_url = https://<ip>:8443)
    • 雲端那台(有 client 憑證)跑 README §9-1 的三層認證驗證(400 / 200 / 401)

完整三層認證驗證天然在雲端側做(client 憑證在雲端),不綁進客戶端精靈;客戶端精靈確認「本機這側都 OK + 8443 TLS 通」即交棒,分工乾淨。


4. 安全 / 可重跑(守 evidence-agent 硬規則)

  • 絕不刪 pgdata / filedata / certs(關鍵狀態,host bind-mount);精靈全程冪等、可安全重跑。
  • .env 一律 chmod 600;answers.conf 不寫任何密碼;不把任何 secret 印進 stdout / log。
  • full 模式下不對外 publish 8080(用 compose override / profile 收掉對外 8080),避免繞過 mTLS。現行手冊靠人工提醒(README §7 結尾),精靈直接幫做。
  • 憑證 / 密碼禁入版控(專案硬規則),精靈產生的檔都落在 deploy/.gitignore 擋。

5. 元件邊界

單元 職責 依賴
install.sh 整支精靈進入點,串四階段 docker / compose、同目錄各檔
preflight 函式群 純檢查、回報、停 host 環境
設定收集函式群 互動 prompt / 讀 answers.conf / 寫 .env+answers.conf / 自動推導 IP
啟動編排函式群 依序拉起 + 輪詢憑證就緒 + 失敗 tail log docker compose、collect-host-id.sh
自我驗證函式群 健康/憑證/log/本機 8443 檢查 + 印交棒提示 curl、docker compose logs
answers.conf.example 無人值守必填清單範本
compose override(full 收 8080) full 模式不對外 publish 8080 docker-compose.yml

各單元以 shell 函式隔離,可單獨讀懂、單獨測(可用 --dry-run 或分階段旗標驗證)。


6. 不做的(YAGNI / 出 scope)

  • 不裝 Docker、不裝 LibreOffice(在 image 內)
  • 不碰雲端側(PKI 設定、產 registration token 都在雲端那台 / FE)
  • 不做 B 階段的 SQLite / in-app mTLS、不做 .deb / 單一執行檔(C)
  • 不做 agent 升級 / 滾動更新流程(重跑精靈換 image tag 即可,複雜版本管理列後續)

7. 不變式(implementation 時要守住)

  • 精靈不得刪除 pgdata / filedata / certs,任何情況都不行。
  • 精靈不得把密碼 / token / MinIO key 印到 stdout 或寫進 answers.conf
  • 精靈不自動安裝 Docker,缺就報錯停。
  • 啟動順序一律「先 file-agent enroll 拿憑證 → 再 nginx」,nginx 不得在憑證就緒前啟動。
  • full 模式對外只留 nginx:8443,不對外 publish file-agent:8080。
  • .env 權限一律 chmod 600