Files
CFDivePlatform/docs/analysis/2026-10-29-k8s-local-simulation-todo.md
T
a620906209 7bd96ef092
Run Tests / test (pull_request) Successful in 36s
docs(analysis): 新增 K8s 本機模擬待辦記錄
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-29 12:57:13 +08:00

133 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CFDivePlatform K8s 本機模擬待辦
> 記錄日期:2026-10-29
> 狀態:**僅記錄,尚未規劃、尚未動工**(Hank 指示「先記待辦」)。
> 範圍:在本機以 Docker Desktop Kubernetes 模擬部署,驗證 manifest 與流程;`docker-compose.yml` 維持本地開發用,不更動。
> 實作原則:涉及行為或部署流程變更,先走 OpenSpec(`/opsx:propose`);本文的決策與清單是規劃輸入,不是 spec。
> 搭配閱讀:`docs/analysis/2026-10-14-project-review-todo.md`(M6、M8 與本項有相依)。
---
## 已做的決策(2026-10-29 討論)
| 項目 | 決策 | 理由 |
|---|---|---|
| 模擬環境 | Docker Desktop 內建 Kubernetes,**Kubeadm(單節點)模式** | 目的是驗證 manifest 與部署流程,不需要多節點;設定最簡單 |
| 與 Compose 的關係 | Compose 照舊作為本地開發環境,K8s 另放獨立目錄(暫定 `k8s/`) | 兩邊互不影響,避免動到現有 `deploy.yml` |
| image | 沿用現有 `Dockerfile` 的 `app`、`web` 兩個 target | 與正式環境的 compose(不含 `compose.override.yml`)同一種形態,落差最小 |
| 隔離 | 每個專案一個 namespace | 另一個 .NET 專案會一起模擬 |
| 上機器的時機 | 本機模擬驗證完成後,再決定實際叢集 | VPS 資源不足,見下節 |
## 為什麼不直接在現有 VPS 上裝 K3s
2026-10-29 實測:2 核、1.9GB RAM(可用約 770MB)、磁碟剩 9.2GB(72%),且已跑 13 個容器(含 Gitea、Gitea runner、Nginx Proxy Manager)。
K3s 單節點自身約需 0.5–1GB,會讓 OOM 風險落在現有正式站與 CI。若之後要上實體叢集,建議另租至少 2 核 4GB、40GB 磁碟的機器。
---
## 總覽
| # | 項目 | 依賴 | 是否走 OpenSpec |
|---|------|------|----------------|
| K1 | 決定 Ingress controller | — | 否(決策) |
| K2 | 盤點 CFDive 的 K8s 資源清單 | — | 否(盤點) |
| K3 | 撰寫 CFDive manifest(`k8s/`) | K1、K2 | 是 |
| K4 | 本機部署與驗證 | K3 | 是(含驗證項目) |
| K5 | 另一個 .NET 專案納入同一叢集 | K1、K4 | 另案(該專案的 repo) |
| K6 | 上傳檔案切 S3/R2 | 外部帳號 | 是(既有暫緩項目) |
| K7 | 上實體叢集前的差距清單 | K4 | 否(文件) |
---
## K1 決定 Ingress controller
**現況**
Docker Desktop 沒有內建 Ingress。K3s 預設是 Traefik;原本考慮的 ingress-nginx,**據我所知 Kubernetes 社群已宣布它在 2026 年 3 月退役,此點為記憶,尚未查證**。
**待辦**
- [ ] 查證 ingress-nginx 目前的維護狀態(官方公告)
- [ ] 在 Traefik 與 Gateway API 實作之間決定(暫定傾向 Traefik:與 K3s 預設一致,之後搬 K3s 的 manifest 改動最少)
- [ ] 確認 Reverb(WebSocket)在所選 Ingress 上的路由與逾時設定
## K2 盤點 CFDive 的 K8s 資源清單
**現況(依 `docker-compose.yml` 服務名稱,2026-10-29 核對)**
`app`、`nginx`、`frontend`、`db`、`scheduler`、`queue-worker`、`redis`、`reverb`。volumes 為 `mysql-data`、`redis-data`、`storage-app-public`。
**暫定對應(未驗證)**
- `app`、`nginx`、`frontend`、`queue-worker`、`reverb`:各一個 Deployment+必要的 Service
- `scheduler`:Deployment,**副本固定 1**(多副本會讓排程重複執行)
- migration/cache/swagger:目前在 `deploy.yml`,需改為 Job(或 initContainer)
- `.env`:拆成 ConfigMap(非機密)與 Secret(機密);`env_file:` 在 K8s 沒有對等物
- `db`、`redis`:本機模擬時先決定放叢集內,或沿用 Compose 容器經 `host.docker.internal` 連線
**待辦**
- [ ] 逐一核對各服務的 port、healthcheck、啟動指令、依賴順序
- [ ] 決定 MySQL/Redis 放叢集內還是沿用 Compose(叢集內較貼近正式環境,Compose 較省事)
- [ ] 注意 `tests/bootstrap.php` 的覆蓋清單:擴大環境變數注入範圍時需同步檢查(見專案記憶中 `env_file` 事件)
## K3 撰寫 CFDive manifest
**待辦**
- [ ] 目錄結構(`k8s/` 下用 Kustomize 或純 YAML,擇一)
- [ ] 各 Deployment 的探針(readiness/liveness)對應現有 healthcheck
- [ ] 加上 `requests`/`limits`,總量抓接近目標機器(例如 4GB 節點),避免本機資源充裕而漏掉 OOM 問題
- [ ] Secret 結構與正式環境相同,本機只用假值
- [ ] 環境值用正式設定:`APP_ENV=production`、`APP_DEBUG=false`、MySQL `8.0`、Redis `alpine`
- [ ] 不帶入 `compose.override.yml` 的 bind mount
## K4 本機部署與驗證
**待辦**
- [ ] Docker Desktop 啟用 Kubernetes(Kubeadm 模式),確認 `kubectl` 指向正確 context
- [ ] 本機 build `app`、`web`、`frontend` image,`imagePullPolicy` 設為 `IfNotPresent`(或 `Never`)
- [ ] 驗證:登入、預約、評價主流程;Reverb 即時訊息(WebSocket 經 Ingress);queue job 實際被消化;scheduler 只有一個實例
- [ ] 驗證:migration Job 失敗時的行為(不應讓新版本 Pod 起來)
- [ ] 驗證:滾動更新與回滾(`kubectl rollout`)
- [ ] 記錄與 Compose 行為不一致之處
## K5 另一個 .NET 專案納入同一叢集
**注意事項(屬該專案 repo,這裡只記備忘)**
- ASP.NET Core(.NET 8 以後)官方 image 預設非 root、監聽 8080,Service 的 `targetPort` 要對
- 巢狀設定以環境變數覆蓋時用雙底線,例如 `ConnectionStrings__Default`
- 需自行提供健康檢查端點供探針使用
- EF migration 用 Job,不要在應用啟動時跑
- 多副本時需處理 Data Protection 金鑰共用,否則副本間 cookie/antiforgery 互相無法解密
**待辦**
- [ ] 兩個專案用不同 namespace 與 hostname(例如 `cfdive.localhost`、`other.localhost`),共用同一個 Ingress controller
## K6 上傳檔案切 S3/R2
**現況**
`storage:migrate-to-s3` 指令與 `FILESYSTEM_DISK` 設定已完成(PR #55、#56),但 R2/S3 帳號尚未申請,VPS 仍是 `FILESYSTEM_DISK=local`,上傳檔案存在具名 volume `storage-app-public`。
多副本時 ReadWriteMany 儲存是最大阻礙;**本機 hostpath 單機無法代表這個問題**,所以這項要在上實體叢集前完成。
**待辦**
- [ ] 取得 S3 相容服務帳號後,另開 OpenSpec change 接續(不要回頭改已歸檔的 `cloud-ready-s3-storage`)
## K7 上實體叢集前的差距清單
本機模擬**無法**驗證的項目,上實體叢集後需另外確認:
| 項目 | 原因 |
|---|---|
| 多節點調度、節點故障 | Kubeadm 模式為單節點 |
| 檔案儲存的 ReadWriteMany | 本機 hostpath 僅單機 |
| TLS/憑證、真實網域 | 本機用 `*.localhost`,無 Let's Encrypt |
| 真實流量與資源競爭 | 本機資源充裕 |
| Gitea Actions 到叢集的部署流程 | 需等有目標叢集;另需 image registry(目前 image 在 VPS 上 build,是否有 registry 未確認) |
**待辦**
- [ ] 確認 VPS 現行部署是否有 image registry;沒有的話,上叢集前要決定放哪裡
- [ ] 決定實體叢集(另租 K3s 機器,或雲端託管)
---
## 開放問題
- 本機機器規格(Docker Desktop 分配給 WSL2 的記憶體)未確認;兩個專案加 MySQL/Redis 同時跑,建議 8GB 以上
- Kubeadm 模式下本機 image 是否可直接被 Pod 使用,依記憶判斷為可,**尚未在實際版本驗證**
- Ingress 最終選哪個(K1)