| 項目 | 內容 |
|---|---|
| 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 產生 |
現行客戶端部署(見 deploy/README.md)要在客戶 Linux server 做 8 個有先後依賴、有暗坑的手動步驟:
docker save | ssh docker load 搬 imagedeploy/.env 約 12 個變數collect-host-id.sh 抓 host MACfile-agent + agent-db 等註冊拿憑證certs/ 有檔--profile full 起 nginx(順序顛倒就起不來)痛點集中三處:步驟有先後依賴(憑證沒簽回 nginx 起不來)、手填一堆有暗坑的 env(AGENT_BASE_URL 必須 https://...:8443、MinIO 要填 LAN IP 不能用 service 名、PDF_CACHE_DIR 要同裝置)、moving parts 多(3 容器 + host-id 腳本)。
評估過三個方向:
| 方向 | 做法 | 結論 |
|---|---|---|
| **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」,而是部署步驟太碎。精靈解的是步驟,不換架構。
一個壓縮包 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 題 → 完成。
| 檢查項 | 缺了怎麼辦 |
|---|---|
| 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 類):
minio / local(minio 才續問 MINIO_ENDPOINT/ACCESS_KEY/SECRET_KEY/BUCKET)CLOUD_ENDPOINT(雲端 base,不含 /api/1.0)REGISTRATION_TOKEN(雲端管理頁產生的該 tenant token)自動推導,不用問:
AGENT_BASE_URL ← 偵測預設路由網卡 IP 組成 https://<ip>:8443,顯示並請部署人員確認「雲端能用這 IP 連到這台嗎?」可覆寫。這是手冊裡最常踩的暗坑(填成 http:8080 會讓雲端報 FILE_AGENT_500005),精靈幫擋。AGENT_AUTH_MODE=full(正式一律 full)、AGENT_IMAGE、AGENT_VERSION 固定值產出:
.env(含密碼,chmod 600,不入版控)answers.conf(不含任何密碼,可版控 / 複製到別台)重跑:偵測到既有 .env / answers.conf 就載入當預設,部署人員只改要改的。
collect-host-id.sh 抓 host MACdocker compose up -d file-agent agent-db/health 200 且 certs/agent.crt 出現(= enroll 成功);有 timeout;失敗就 docker compose logs --tail file-agent 把錯誤印出來停下docker compose --profile full up -d nginx部署人員完全不用知道「先 agent 後 nginx」這個順序陷阱。
/health 200、certs/ 憑證齊、agent log 出現 agent enrolled + heartbeatcurl -sk https://localhost:8443(預期被 400 擋 → 證明 TLS + port 8443 通、nginx mTLS 起得來)base_url = https://<ip>:8443)完整三層認證驗證天然在雲端側做(client 憑證在雲端),不綁進客戶端精靈;客戶端精靈確認「本機這側都 OK + 8443 TLS 通」即交棒,分工乾淨。
pgdata / filedata / certs(關鍵狀態,host bind-mount);精靈全程冪等、可安全重跑。.env 一律 chmod 600;answers.conf 不寫任何密碼;不把任何 secret 印進 stdout / log。deploy/ 由 .gitignore 擋。| 單元 | 職責 | 依賴 |
|---|---|---|
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 或分階段旗標驗證)。
.deb / 單一執行檔(C)pgdata / filedata / certs,任何情況都不行。answers.conf。.env 權限一律 chmod 600。