跳轉至

Dockhand

概述

Dockhand 係 fnsys/dockhand 嘅容器編排同 GitOps 中樞,負責管理 oracle-arm-stacks 倉庫入面嘅 56+ 個 Docker Compose stacks。Dockhand 透過掛載 Docker socket 同 Docker daemon 直接互動,可以偵測 compose 檔案變更、同步環境變數,以及執行 stack 嘅部署/更新/移除。所有 secret 唔會直接 hardcode 喺 compose 檔案,而係經由外部 secret provider Infisical 注入,確保敏感資料淨係喺執行時間先出現。

Dockhand 喺設計上維持「零 Port 暴露」:Host 上完全冇 publish 任何容器 port,對外路由一律交由 cf_network 入面嘅 cloudflared 處理,避免管理介面目視於公網,減少攻擊面。

架構

Dockhand 部署喺 Oracle Cloud ARM 主機,使用外部 Docker network cf_network,並固定 IPv4 172.21.0.15。由於 cf_network 已經存在,compose 檔案用 external: true 宣告,Dockhand 直接加入現有主網絡;同一網絡內嘅 cloudflared 可以用 http://dockhand:8080 或者 http://172.21.0.15:8080 作為 upstream。

Dockhand 依賴以下元件:

  • PostgreSQL:以 pg-main 容器提供資料庫服務,Dockhand 使用 dockhand 資料庫,用戶同樣係 dockhand,密碼由 ${DOCKHAND_DB_PASSWORD} 提供。
  • Docker socket/var/run/docker.sock 俾 Dockhand 管理 host 上其他 containers。
  • Infisical:負責存放同加解密環境變數同 secrets;Dockhand 部署時會向 Infisical 攞最新 secret 再寫入執行環境。
  • Cloudflare Tunnel:作為唯一對外入口,令管理員可以經內部域名存取 Dockhand,但唔需要開任何 Host port。
  • oracle-arm-stacks 倉庫:裝載所有 stacks 嘅 compose 同 .env 範本,Dockhand 以 GitOps 方式同步,當 repo 有更新時會觸發重新部署。

部署(Docker Compose 片段)

以下係精簡版 docker-compose.yml,已移除敏感值,直接可用於 oracle-arm-stacks 入面嘅 Dockhand stack:

services:
  dockhand:
    image: fnsys/dockhand:latest
    container_name: dockhand
    restart: unless-stopped
    # 刻意唔寫 ports:,維持零 Port 暴露
    environment:
      - TZ=Asia/Hong_Kong
      - DATABASE_URL=postgres://dockhand:${DOCKHAND_DB_PASSWORD}@pg-main:5432/dockhand
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - dockhand_data:/app/data
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    networks:
      cf_network:
        ipv4_address: 172.21.0.15

volumes:
  dockhand_data:
    name: dockhand_data_vol

networks:
  cf_network:
    external: true

部署前請確保 cf_network 已經存在;如果未建立,需要先執行:

docker network create --subnet 172.21.0.0/16 cf_network

之後用 docker compose up -d dockhand 啟動服務。

配置與環境變數

Dockhand 嘅主要環境變數包括:

  • TZ=Asia/Hong_Kong:設定容器時區為香港時間,並同步 /etc/localtime/etc/timezone
  • DATABASE_URL:PostgreSQL 連線字串,格式為 postgres://dockhand:${DOCKHAND_DB_PASSWORD}@pg-main:5432/dockhand
  • ${DOCKHAND_DB_PASSWORD}:必須由 Infisical 注入,唔好寫入 repo。
  • INFISICAL_URLINFISICAL_TOKEN:如果 Dockhand 原生整合 Infisical,需要喺部署環境注入,等佢可以喺執行時間抓取 secrets。

所有敏感變數建議由 Infisical 管理,並喺 CI/CD 或 host 上嘅 deploy script 度解析成環境變數,避免 .env 入面出現明文密碼。Dockhand 每次收到 Git push 或 repo 更新後,會以最新 secrets 重新建立相關 containers。

維運與監控

日常維運可以透過以下指令檢查 Dockhand 狀態:

# 睇 Dockhand 即時 log
docker logs -f dockhand

# 確認容器已加入 cf_network 及 static IP
docker inspect dockhand --format '{{.NetworkSettings.Networks.cf_network.IPAddress}}'

# 測試同 PostgreSQL 嘅連線
docker exec dockhand psql "$DATABASE_URL" -c 'SELECT 1;'

# 檢查容器內部管理服務
docker exec dockhand curl -s http://localhost:8080/healthz

# 強制重新建立 Dockhand 容器
docker compose up -d --force-recreate dockhand

監控重點:

  • 確保 cf_network 冇異動,避免 IP 衝突;尤其當其他 containers 都用固定 IP 時,要檢查 172.21.0.15 冇畀人佔用。
  • 留意 Docker socket 權限,如果 Dockhand 冇辦法讀取 containers,會出現 permission denied;需要確認容器內 process 有足夠權限。
  • 定期檢查 dockhand_data_vol 容量,避免 /app/data 寫滿。
  • Cloudflare Tunnel 如果斷線,Dockhand 仍然喺 cf_network 入面運作,但管理介面會暫時無法存取;可以檢查 cloudflared 嘅 log 同 tunnel credentials。

常見問題

1. 點解 Dockhand 有 static IP 但外面訪問唔到? 因為 Dockhand 冇 publish 任何 Host port,對外必須經 cf_network 入面嘅 cloudflared。請確認 cloudflared 同 Dockhand 喺同一個 network,而且 tunnel config 入面 upstream 係 http://dockhand:8080 或者 http://172.21.0.15:8080

2. Dockhand 連唔到 PostgreSQL? 先檢查 pg-main 容器係咪正常:docker ps | grep pg-main。然後確認 DATABASE_URL 入面嘅 username、password 同 database 名正確。最常見問題係 ${DOCKHAND_DB_PASSWORD} 未有由 Infisical 注入,導致字串入面有空白或者變數名。

3. Docker socket permission denied? 確認執行 Dockhand image 嘅用戶有權限訪問 /var/run/docker.sock。如果 host 上 Docker group 嘅 GID 同 container 入面唔一致,可能要重建 image 或者用 group_add 指定 GID。

4. GitOps sync 冇觸發部署? Check Dockhand 有冇正確 read-only mount oracle-arm-stacks 或者有冇 webhook 連到 GitHub。如果係用 polling 模式,確認 /app/data 入面嘅 cache 冇損壞,必要時 restart Dockhand。

相關鏈接