這篇是自己的備忘錄。記錄為什麼不直接
git pull就好,以及 Config Repo 模式的設計邏輯和它的不完整之處。
# 傳統部署(推式 / Push-based)
最直覺的做法:
# 在 server 上
git clone https://github.com/org/teleagent-backend
cd teleagent-backend
git pull
docker-compose up --build
# 兩種型態
型態一:純手動
ssh user@server
cd /app/teleagent-backend
git pull
docker-compose up --build -d
完全靠人,每次部署都要 SSH 進去手動執行。
型態二:CI 自動 SSH
# GitHub Actions
- name: Deploy
uses: appleboy/ssh-action@v1
with:
host: $<!--swig0-->
script: |
cd /app/teleagent-backend
git pull
docker-compose up --build -d
CI 幫你自動 SSH 進去跑指令,看起來像「自動化」,但本質還是一樣——CI 主動把指令推進 server 執行(Push-based)。
# 流程
開發者 push code
│
▼
GitHub Actions(CI)
└─ 跑測試
└─ SSH 進 server(自動或手動)
│
▼
Server
└─ git pull(拿 source code)
└─ docker-compose up --build -d(在 server 上 build + 跑)
兩種型態的本質都一樣:CI 是核心,主動 push 變更進 server。
# 缺點
1. 程式碼、設定、密鑰混在一起
docker-compose.yml、.env、SSL 憑證都跟 source code 放在同一個 repo,甚至同一個目錄下。萬一 repo 外洩,密鑰也跟著洩漏。
2. Server 需要完整開發環境
因為要 --build,server 上得有 Go / Node / Python 等語言環境、build tool,純粹跑服務的機器卻要安裝一堆不必要的東西。
3. 多台 server 很難管
三台 server 就要 SSH 三次,手動依序更新,容易漏掉或搞錯版本。
4. 沒有部署記錄
「誰、什麼時候、把哪個版本部署到哪台 server」這件事完全沒有記錄,debug 出問題很難追溯。
# GitOps / Config Repo 模式(拉式 / Pull-based)
# 核心概念
把「程式碼」跟「部署設定」分成兩個 repo 管理。
- Application Repo(
teleagent-backend):只管程式碼和 CI - Config Repo(
tbd-teleagent-120):只管這台 server 的部署設定
Git 本身就是「什麼版本應該跑在哪裡」的唯一事實來源(Single Source of Truth)。
# Config Repo 結構
tbd-teleagent-120/ ← 這台 120 server 專屬的 repo
├── teleagent-backend/
│ ├── docker-compose.yml ← 寫明要跑哪個 image tag
│ ├── credentials/ ← 這台專屬的密鑰(不在 app repo 裡)
│ └── .envrc ← 這台專屬的環境變數
├── ssos/
│ └── docker-compose.yml
└── aiphone-backend/
└── docker-compose.yml
# 流程
開發者 push code
│
▼
GitHub Actions(CI)
└─ 跑測試
└─ build Docker image
└─ push image 到 ECR(帶版本 tag,例如 v1.2.3)
│
▼
手動(或自動工具)更新 config repo:
docker-compose.yml 裡的 image tag 改成 v1.2.3
│
▼
Server 上的部署工具偵測到 config repo 有變動
└─ docker pull image(從 ECR)
└─ docker-compose up -d(不 build,直接用 image)
關鍵差異:server 不需要 source code,只需要 Docker。Image 在 CI 環境 build 好,server 只負責「拉 image、跑起來」。
# 優點
1. 密鑰與程式碼徹底分離
credentials/ 只在 config repo,而 config repo 通常是 private + 存取受限。即使 app repo 外洩,密鑰不受影響。
2. Server 乾淨,只需要 Docker
不需要 Go、Node、Python、build tool。一台純 production server 只跑 container,環境單純、攻擊面小。
3. 每台 server 設定獨立
tbd-teleagent-120 是這台機器的設定,tbd-teleagent-121 是另一台的設定,不同機器的 credentials、env var 完全隔離,改一台不影響另一台。
4. 部署歷史完整可追溯
config repo 的每一筆 commit 都是一次「宣告這台 server 應該跑什麼版本」的記錄,附帶時間、作者。需要 rollback 只要 revert commit 就好。
# 兩種方式的核心差異對比
| 傳統部署 | GitOps / Config Repo | |
|---|---|---|
| 部署觸發 | CI 主動 push(推式) | Server 偵測 Git 變動拉取(拉式) |
| Source of Truth | CI pipeline | Git config repo |
| Server 需要 | 完整開發環境 + source code | 只需要 Docker |
| 密鑰管理 | 混在 app repo | 獨立 config repo |
| 多台 server | 各自 SSH 手動更新 | 各自有 config repo,獨立管理 |
| 部署記錄 | 無 | Git commit history |
| Rollback | 手動重跑舊版 CI | Revert config repo commit |
# 這個專案目前的狀態:半手動 GitOps
目前的流程走到這裡就停了:
CI push image 到 ECR(帶 tag)
│
✋ 手動去 config repo 改 docker-compose.yml 裡的 tag
│
▼
SSH 進 server,手動 docker-compose up -d
這就是為什麼「推了 code 但沒更新」——CI 那段是自動的,但 config repo 更新和 server 重啟這兩步是手動的,很容易忘。
# 完整 GitOps 需要什麼?
要把「半手動」補完,需要在 CI push image 之後,自動完成這兩件事:
# 1. 自動更新 config repo 的 image tag
ArgoCD Image Updater(Kubernetes 環境)
- 監聽 ECR,偵測到新 image tag
- 自動更新 Git repo 裡的 manifest
- ArgoCD 偵測到 Git 有變動,自動 sync 到 cluster
Renovate / Dependabot(非 Kubernetes 也能用)
- 掃描
docker-compose.yml裡的 image tag - 發 PR 更新 tag,merge 後自動觸發部署
自己寫 CI script(最輕量)
# GitHub Actions,在 CI 最後一步
- name: Update config repo
run: |
git clone https://github.com/org/tbd-teleagent-120
cd tbd-teleagent-120/teleagent-backend
sed -i "s|image: .*|image: 123456.ecr.aws/teleagent:$<!--swig1-->|" docker-compose.yml
git commit -am "ci: bump teleagent to $<!--swig2-->"
git push
# 2. 自動重啟 server 上的服務
Watchtower(最簡單,適合小專案)
- 一個 Docker container,持續監聽 registry 有沒有新 image
- 偵測到新版本自動
docker pull+ 重啟 - 缺點:不是從 Git 驅動,是直接監聽 registry,跟 GitOps 精神有點偏差
⚠️ 注意:Watchtower 目前處於 unmaintained 狀態(2025 年社群反映維護停滯),小專案用還好,正式環境要謹慎。
Portainer Webhooks
- config repo 更新後,透過 webhook 通知 Portainer 重新 pull + 重啟
- 比 Watchtower 更可控,可以指定更新哪個 stack
SSH + 簡單 script(夠用就好)
#!/bin/bash
# deploy.sh,被 CI 或 webhook 觸發
cd /srv/tbd-teleagent-120/teleagent-backend
git pull
docker-compose pull
docker-compose up -d
# 完整自動化流程(目標狀態)
開發者 git push
│
▼
GitHub Actions
├─ 跑測試
├─ build image
├─ push image 到 ECR(tag: git SHA 或語意版本)
└─ 更新 config repo 的 image tag(自動 commit)
│
▼
Config Repo 有新 commit
│
▼ (Webhook / Portainer / ArgoCD 偵測到)
▼
Server
├─ docker pull 新 image
└─ docker-compose up -d
│
▼
✅ 部署完成,全程不需要人工介入
# 小結
| 場景 | 建議 |
|---|---|
| 個人小專案、一台 server | 傳統部署就夠,簡單直接 |
| 多台 server、需要密鑰隔離 | Config Repo 模式 |
| 要完全自動化 + 部署歷史 | Config Repo + ArgoCD Image Updater 或自訂 CI script |
| Kubernetes 環境 | ArgoCD + Image Updater 是標配 |
GitOps 不是銀彈,是一種設計哲學:把「系統應該長什麼樣子」的宣告放進 Git,讓工具負責讓現實跟宣告一致。
最後更新:2026-03-11
