交付流程 · 產物閱讀
MARKDOWNdocs/DASHBOARD-DEPLOY.md

共用 Dashboard 部署(更新後的 v0.6.2)

各 contracts repo 只保留 .delivery-contracts 的 dcx_ref、.dashboard-deploy.json 與 CI 入口。 建置、工具鏈、接收器、主機安裝範本及回復邏輯都隨 framework 版本管理,不複製到產品 repo。 既有 dcx board 離線 HTML 與 dcx board build 指令維持不變。

產品設定與 CI

產品 ID 直接讀 .delivery-contracts 的 product,不重複宣告。 .dashboard-deploy.json(可省略,預設 instance=product、target=linux/amd64、port=8000):

json
{"instance": "im", "target": "linux/amd64", "port": 8000}

instance 是 1–20 個小寫英數/連字號、以英文字母開頭。它决定 Linux 帳號與服務名稱, 例如 dcx-im、dcx-im-deploy、dcx-im.service。其他產品只要改 instance,毋須改共用程式。 目標支援 linux/amd64、linux/arm64,port 必須在 1024–65535。 同主機上不同 instance 使用不同 port,產品資料、identity、secret 完全分開;目前是各產品獨立服務。

contracts repo 中已提交契約及上述設定後:

sh
# 已有相容 Node/npm 與 Go 時:
bin/dcx board package --output dist/dashboard
# Linux CI 自動下載固定版 Node/Go 並驗證官方 SHA256:
bin/dcx board package --install-toolchain --output dist/dashboard
# 消費同一條 pipeline 的 artifact,透過受限制 SSH key 傳送:
bin/dcx board deploy --artifact dist/dashboard

package 的輸出目錄必須不存在。CI checkout 應清除上次 job 的未追蹤輸出,並把 /dist/ 放進 gitignore。 Node 24.20.0 與 Go 1.27.1 只在建置時安裝到獨立暫存目錄,結束後清除,不改 runner 系統。 Runner 需 Python 3.9+、Git、tar(原 CI 如建立 venv 也需 venv);部署 job 另外需 SSH client。 需可連線 framework Git repo、nodejs.org、go.dev、npm 與 Go module proxy。

CI 只需呼叫上述指令並傳遞 dist/dashboard/ artifact,設定自己的 runner tag、規則及 resource_group。 建議 MR/主分支建置,只有 protected 主分支且 TEAM_DASHBOARD_DEPLOY_ENABLED=true 才部署。 Artifact 含私有契約,限制下載權限並設定保存期限。build 與 deploy 必須使用同一個 dcx_ref。

text
dist/dashboard/
  dashboard.tar.gz          # Go executable + frontend + private snapshot
  dashboard.tar.gz.sha256
  build-info.json
  host-setup/               # 從釘住版本的共用範本產生,不是另一份維護來源
    install-host.sh
    dashboard.service
    receive / receive.py / deployment.json
    config.example.json / README.md
    observe-source.py / observer.example.json
    source-observer.service / source-observer.timer  # 可選,不自動安裝或啟用

Ubuntu 主機初始化

將 host-setup/ 整個目錄交給 SRE,以 root 執行 sh install-host.sh。 Ubuntu 需 systemd、Python 3、sudo、OpenSSH server 及 CA 憑證;不需要 Go/Node 編譯器。 以下以 instance im 為例;其他 instance 替換路徑中的 im:

  • 程式版本:/opt/dcx-im/releases/;目前版本:/opt/dcx-im/current。

  • 設定:/etc/dcx-im/config.json;secret:/etc/dcx-im/env。

  • 身份檔:/var/lib/dcx-im/identity/identities.json。

  • service:dcx-im.service,執行帳號 dcx-im,SSH 帳號 dcx-im-deploy。

安裝腳本重跑保留 runtime config、session secret、identity 與 authorized_keys; 但更新接收器及 service 範本。設定產品/instance 不應用於既有 instance 的改名或產品替換。 新版 framework 有接收協定/安裝包改動時,SRE 先更新 host-setup,再啟用新版部署。

修改 runtime config 的 HTTPS base_url 與 Google Web Client ID;保留生成的資料路徑。 Google Web Client 設定 HTTPS origin 與 /auth/google redirect URI。 allowed_hd=[] 允許現行 ownership 清單中具 Dashboard 角色的 Google verified email 首次登入時自動綁定;設定 Workspace domain 可再限制登入來源。已撤銷身分仍須管理員明確核准才能恢復。 nginx 另行反向代理到生成設定中的 loopback port,勿公開部署包或 data 目錄。

sh
sudo -u dcx-im /opt/dcx-im/current/dcx-dashboard identity list --file /var/lib/dcx-im/identity/identities.json
sudo -u dcx-im /opt/dcx-im/current/dcx-dashboard identity approve --file /var/lib/dcx-im/identity/identities.json --product im --sub GOOGLE_SUB

將專用 CI SSH 公鑰寫入 /home/dcx-im-deploy/.ssh/authorized_keys,前綴如下:

text
restrict,command="sudo -n /usr/local/sbin/dcx-im-receive" ssh-ed25519 AAAA... CI-dashboard

sudoers 僅允許該產品接收器且不允許參數;SSH 帳號不能寫入程式或接收器目錄。 接收器設定由 root 擁有,不從 SSH 客戶端接受產品或目的地路徑。

CI 變數

變數用途
DELIVERY_FRAMEWORK_REPO既有 framework URL/job token 取得設定
TEAM_DASHBOARD_DEPLOY_ENABLED設為 true 才讓產品 CI 啟用部署,Protected
TEAM_DASHBOARD_DEPLOY_HOST目標 IP/DNS,Protected
TEAM_DASHBOARD_DEPLOY_PORTSSH port,預設 22,Protected
TEAM_DASHBOARD_DEPLOY_USER可省略,預設 dcx-<instance>-deploy,Protected
TEAM_DASHBOARD_DEPLOY_KEY_FILE可選:專用 SSH 私鑰,File/Protected;省略使用 Runner SSH 身分
TEAM_DASHBOARD_KNOWN_HOSTS_FILE可選:經 SRE 核實的 host key,File/Protected;省略使用 Runner known_hosts

CI_COMMIT_SHA、CI_PIPELINE_ID 由 GitLab 提供。接收器檢查 checksum、product、CPU 架構、commit、 封包路徑及 pipeline 順序;只接受乾淨 framework 產物。新版本獨立解壓,原子切換 current 後重啟服務。 啟動檢查失敗則回復上一版;首次部署失敗則停止服務。/login 檢查不代替真實 Google 登入驗收。 舊或已部署的 pipeline 被拒絕;修正後啟動新的主分支 pipeline。舊版本不自動清理,由 SRE 保留所需版本。

從 IM 專用腳本轉換/發版順序

  1. 先提交並推送包含本功能的 framework commit,再將 v0.6.2 tag 更新到該 commit 並推送 tag。

  2. 產品 dcx_ref 改為該版本,套用薄 CI 與部署設定,執行 package 建置。

  3. SRE 安裝該版本生成的 host-setup、補 OAuth/SSH 設定後才開啟部署。

IM 舊的 /opt/im-dashboard、im-dashboard.service 及 v2 forced command 不會自動改寫。 若曾實際部署,需停用舊服務、遷移身份檔與 runtime 設定並核對權限後再換新服務。 尚未部署的新主機直接使用生成的 dcx-im 安裝包即可。

本次沿用並更新 v0.6.2 tag。已使用過舊 v0.6.2 的本機須刪除 bootstrap 的該版本快取: ${XDG_CACHE_HOME:-$HOME/.cache}/delivery-framework/v0.6.2,再執行 bin/dcx。 GitLab CI 使用每個 job 的獨立快取,會重新取得更新後的 tag。 請等遠端 tag 更新完成後才啟動產品的新 CI;更新前已啟動的 job 應重新執行。

使用 SRE 已配置的 Runner SSH 身分

省略 TEAM_DASHBOARD_DEPLOY_KEY_FILE 時,沿用執行 job 帳號的 SSH config、預設金鑰或 agent; 省略 TEAM_DASHBOARD_KNOWN_HOSTS_FILE 時,沿用該帳號的 known_hosts。 主機驗證仍為 StrictHostKeyChecking=yes,Runner 必須已有核實過的主機公鑰。 這適用於已配置的 shell runner;Docker executor 不會自動取得宿主機的 SSH 設定。 若明確設定 File 變數但檔案不存在,會失敗,不會退回其他身分。

SRE 若已提供 root 登入,可設 TEAM_DASHBOARD_DEPLOY_USER=root;工具會直接呼叫 安裝好的 /usr/local/sbin/dcx-<instance>-receive。非 root 部署帳號維持既有 forced-command 協定。 網域與 OAuth 尚未補齊時,可先執行 host-setup 初始化;暫不開啟 CI 部署,服務維持未啟動。

先驗證 CI 傳輸(不啟動服務)

設定 TEAM_DASHBOARD_DEPLOY_ENABLED=true、TEAM_DASHBOARD_DEPLOY_MODE=stage, 受保護主分支的部署 job 會傳送同 pipeline 的完整產物,接收器驗證 checksum、 產品、架構、來源 commit 及封包內容後,保存到 /opt/dcx-<instance>/releases/staged-<pipeline>-<commit>/。 成功 log 為 Staged ... (verified; service unchanged);不更新 current,也不啟動或重啟服務。 因此不需先完成 OAuth 或 nginx,即可驗證 Runner 到主機的真實部署傳輸。

主機須先更新本版接收器;舊版會拒絕 stage 協定,不會意外啟動服務。 正式上線時將 mode 設為 activate(省略時的既有預設),執行新的 pipeline。 stage 產物不會自動清除,可由 SRE 按保存策略清理。

個人待辦、MCP 與來源更新狀態

本節為新版程式的接入方式,不能據此認定現有 IM 主機已完成升級。 不需建立其他產品即可先在 IM 試行。未來產品各自保有 contracts repo、 dcx_ref、ownership 與部署快照;共用服務的 products、Google 身分綁定、 MCP 授權產品與來源檢查檔均以 product ID 分開。現行 package/接收器仍按單產品部署, 本次沒有把它改成會一次部署全部產品的控制器。

dcx todo --json、Google Dashboard 的「我的待辦」與 MCP get_my_work 共用快照中的 my_work.by_handle。服務依已驗證身分選擇 handle,AI 不能傳信箱或 handle 冒充他人。個人指派與角色共同待辦分開;缺少索引或資料有錯時顯示未確認, 不回報「沒有工作」。保留 dcx inbox 的重驗用途,完整待辦改查 todo。 blocks=[] 的 Gap 以提醒呈現,不升格成阻擋工作;Run 的缺口事實也不會自動指派給人。

MCP 的 OAuth client 預先註冊、Google 登入後的產品同意、PKCE 與唯讀工具設定, 見 Go 服務說明。MCP 預設關閉,沒有寫契約、 操作 Jira、執行 CI 或合併 MR 的工具。使用者查到工作後,在該產品 repo 的工作起點 更新契約,再以 whoami/open 開工;工作中仍遵守固定版本紀律。

資料更新分成兩件事:合併進契約主分支後,既有 CI 建置並部署新快照;另外由 可選的來源檢查工作讀取遠端主分支 commit。MCP/網頁請求只讀本機私有快照及檢查結果, 不會在查詢時 clone、pull 或執行未受信任的 Git URL。

source_status.state呈現方式
current快照符合 checked_at 最近觀察到的遠端 commit,並且檢查未超過期限
stale最近觀察到的遠端 commit 與已部署快照不同,應查部署 pipeline 或重新核對來源
unknown未設定、資料缺損、檢查逾時或來源不確定;不能宣稱最新
check_failed最近一次遠端檢查失敗;舊的成功結果不會繼續冒充成功

每次回覆同時保留完整快照 commit、產生時間、觀察到的 commit/檢查時間,以及 產品的 dcx_ref、實際 framework commit/dirty 狀態。觀察早於快照產生時間時顯示未確認。 current 是截至檢查時間的 結論,並不保證之後沒有新提交,也不代表全部 AC 已完成。

可選:安裝來源檢查工作(IM 範例)

host-setup 包含 observe-source.py、observer.example.json 與 systemd 範本; install-host.sh 不會替你啟用。由 SRE 設定固定的唯讀 Git 身分與核實過的 known_hosts, 並確認主機已安裝 Python 3.9+、Git 與需要的 SSH client。 該身分只需讀取契約 repo。不要使用 CI 部署私鑰代替讀取身分,也不要把 token 放進 URL。 Git 認證由主機的 credential helper 或專用 SSH 設定提供,不會出現在 MCP 回覆。

將範例的 remote 改為 IM 契約 repo 的實際 Git URL,保存至 /etc/dcx-im/observer.json(root 擁有,dcx-im 群組可讀)。例如結構為:

json
{
  "products": {
    "im": {
      "remote": "git@YOUR_GIT_HOST:YOUR_GROUP/im-delivery-contracts.git",
      "ref": "refs/heads/main",
      "output": "/var/lib/dcx-im/source-status/im.json"
    }
  }
}

保留 repo 的實際受保護分支名稱,不應因範例寫 main 就更換分支。先建立 /var/lib/dcx-im/source-status(dcx-im 擁有、0750),並將 helper 安裝到 /usr/local/lib/dcx-dashboard/im/observe-source.py(root 擁有、0755)。 先手動確認服務帳號能完成唯讀查詢:

sh
sudo -u dcx-im /usr/bin/python3 /usr/local/lib/dcx-dashboard/im/observe-source.py --config /etc/dcx-im/observer.json

成功後,在 Dashboard runtime config 新增:

json
{
  "freshness_files": {"im": "/var/lib/dcx-im/source-status/im.json"},
  "freshness_max_age_seconds": 300
}

這兩個欄位要合併進原設定,不能覆蓋 Google、identity、web_dir、products 等欄位。 檢查檔位於網頁與不可變 release 目錄之外。服務不接受未知產品的路徑或符號連結檢查檔。 將 host-setup 中的 service/timer 分別安裝為 /etc/systemd/system/dcx-im-source-observer.service 與 .timer,執行 daemon-reload, 再啟用 dcx-im-source-observer.timer,最後重新啟動 Dashboard 讀取 runtime 設定。 範本每 60 秒檢查一次,TTL 預設 300 秒;停止 timer 後,成功觀察也會自然變成未確認。 每次 Git 檢查最多 20 秒,失敗會寫入 check_failed 並回傳非零結果,方便既有監控接手。

來源觀察器可接受多個已配置產品,每個使用獨立輸出檔;多產品同一個 service 時, SRE 需依產品數調整 TimeoutStartSec(範本 45 秒供單產品)及允許寫入目錄。 新增產品必須另外加入已驗證的 repo/release/ownership/授權設定,本次未啟用 StreamX。

靜態唯讀副本 · 可直接開啟,不需伺服器;不改變核准或執行結果