Dokploy Schedules 踩坑:搞懂三個排程 tab,順便繞過一個遠端 server 的 dockerode bug

新手剛接觸 Dokploy 容易被 Backups / Schedules / Volume Backups 三個 tab 搞混。本文釐清差異、舉例 Schedules 能做什麼,並記錄一個在遠端 server 上踩到的雷與繞過方法。

Dokploy Schedules 踩坑:搞懂三個排程 tab,順便繞過一個遠端 server 的 dockerode bug

起源

剛開始用 Dokploy 管理一堆 self-hosted 服務時,每個 service 頁面上有三個跟「定時」有關的 tab:

?tab=backups
?tab=schedules
?tab=volumeBackups

新手第一次看一定霧煞煞——這三個東西到底差在哪?我以為 Schedules 就是「設定什麼時候跑備份」,結果完全不是。釐清過程中還順便踩到一個遠端 server 才會出現的雷,記錄下來給後人參考。

三個 tab 在做什麼

它們完全獨立、互不相干,只是名字都跟「定時」有關。

Tab 在做什麼 救得回 救不回
Backups 定時跑 pg_dump / mysqldump 把 DB 內容倒成檔,上傳 S3 DB 內容(資料、設定) DB binary、檔案 volume、log
Volume Backups 把 docker volume 整顆打 tar.gz 上 S3 任何純檔案類資料 運行中的 DB(會抓到中間狀態,可能壞)
Schedules 到指定時間在容器/host 內跑一行 shell 指令 跟備份完全無關——是 cron job

重點:Backup 的「什麼時候跑」寫在 Backup 自己裡面(每筆 Backup 都有一個 cron 欄位,例如 0 4 * * 0)。Schedules tab 是另一個完全獨立的功能,用來定時跑你自己想跑的指令。

Schedules 能做什麼

凡是「定時跑一行指令」的需求都可以放這。一些例子:

1. DB 健康維護

Postgres 跑久了會累積 dead tuple,定期 VACUUM 可以維持效能:

docker exec myapp-postgres-1 psql -U myuser -d mydb -c "VACUUM ANALYZE;"
Code language: JavaScript (javascript)

2. 容器內暫存清理

find /app/tmp -type f -mtime +7 -delete
Code language: JavaScript (javascript)

3. 健康檢查 + 通報

curl -fsS --max-time 2 http://myapp:3000/ \
  || curl -X POST "https://api.telegram.org/bot<TOKEN>/sendMessage" \
       -d chat_id=<YOUR_ID> -d "text=myapp 掛了"
Code language: JavaScript (javascript)

4. 第三方服務的 GC

例如 MLflow、Sentry 之類有自己 GC 指令的服務。

什麼時候**不**該用 Dokploy Schedules

  • 業務邏輯(爬蟲、ETL、報表)→ 用該領域的 orchestrator(例如 Airflow / Dagster / Prefect)
  • 需要看血緣、retry、依賴關係 → 同上
  • 「失敗了客戶會哀號」的事 → 同上,因為 Dokploy Schedules 沒有好的失敗通知機制

判斷口訣:這件事如果連續失敗 3 天我會不會痛?

  • 會痛 → 不要放 Dokploy Schedules
  • 不會痛 → Dokploy Schedules 很方便

踩到的雷:scheduleType=compose 對遠端 server 會壞

症狀

我建了一個 schedule 給某個 compose service:

  • scheduleType: compose
  • serviceName: postgres(compose 裡的服務名)
  • command: psql -U myuser -d mydb -c "VACUUM ANALYZE;"
  • cron: 0 3 * * 0

UI 顯示 200 OK,但 manual run 立刻 500,Dokploy 容器 log 出現:

The URL ssh:192.168.50.10:22192.168.50.10 is invalid
Execution error: Error: No response from server
Code language: JavaScript (javascript)

注意那個 URL:ssh:<host>:<port><host>——port 跟 host 黏在一起了,看起來像 dockerode 在組 SSH URL 時的 bug。

為什麼會壞

挖了 Dokploy 源碼後發現執行流程是:

schedule.runManuallyrunCommandgetComposeContainer(compose, serviceName)
      → getRemoteDocker(serverId)
        → new Dockerode({ protocol: "ssh", host, port, username, sshOptions })
Code language: CSS (css)

getComposeContainer() 為了拿 container ID,用 dockerode 的 SSH protocol 直接連遠端 docker daemon。而 dockerode 的 SSH protocol 在現行版本有 URL 組成 bug,連不上 → No response from server

對照之下,下列兩條路完全沒問題:

  • scheduleType=server 的執行路徑 → 走 execAsyncRemote()(純 ssh2 spawn shell)
  • Dokploy UI 的 container list → 走 docker ps over SSH(也是純 ssh2)

問題只出在「dockerode 透過 SSH 直連 docker daemon」這條路。

繞過方法:改用 scheduleType=server + script

不要讓 Dokploy 用 dockerode SSH 找 container,自己在 script 裡呼叫 docker exec 就好:

#!/bin/bash
set -e
docker exec myapp-postgres-1 psql -U myuser -d mydb -c "VACUUM ANALYZE;"
Code language: JavaScript (javascript)

對應的 schedule 設定:

欄位
scheduleType server
serverId 你的遠端 server ID
composeId (空)
serviceName (空)
script 上面那段 bash
cronExpression 0 3 * * 0

Dokploy 會把這份 script 寫到遠端 server 的 /etc/dokploy/schedules/<appName>/script.sh,cron 觸發時 SSH 過去 bash script.sh。執行 log 在同個目錄下的 *.log

用 MCP / API 怎麼建

如果你用 Dokploy MCP 或 API 建(不從 UI),呼叫 schedule-create 時注意:

{
  "name": "DB Vacuum",
  "cronExpression": "0 3 * * 0",
  "scheduleType": "server",
  "serverId": "<your server id>",
  "script": "#!/bin/bash\nset -e\ndocker exec myapp-postgres-1 psql -U myuser -d mydb -c \"VACUUM ANALYZE;\"\n",
  "shellType": "bash",
  "enabled": true,
  "command": ""
}
Code language: JSON / JSON with Comments (json)

command 欄位給 server-type 用不到,但 schema 可能要求填字串,給空字串即可。

UI 位置

注意:改成 scheduleType=server 後,這筆 schedule 不會出現在原本 compose service 頁面的 Schedules tab,而是在:

Settings → Servers → 你的 server → Schedules tab

因為它現在掛在 server 底下、不掛在 service 底下。

小結

  1. Dokploy 三個 tab 完全獨立:Backups 備 DB、Volume Backups 備檔案、Schedules 跑 cron 指令。
  2. Backups 的排程寫在 Backup 自己,不是 Schedules tab。
  3. scheduleType=compose 對遠端 server 會踩 dockerode SSH bug,改用 scheduleType=server + script 裡 docker exec 就好。
  4. 本機 dokploy(service 跑在 dokploy 自己機器上)的 compose-type schedule 沒這問題;只有跨機器才會踩。

希望這篇能省下後人挖源碼的時間。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *