一句話結論
老系統不用一次搬完。在它旁邊長出新的,一塊一塊接手;每一步都小,每一步都能回頭。
這是我做的 10 集教學影片《老系統不上天堂也不下地獄》的主線。每集 3 分鐘左右的橫式長片,再剪一支不到 1 分鐘的 Shorts。目標是讓沒寫過程式的高中生也聽得懂,所以每個名詞都先給一個生活比喻,設定檔和指令只短暫出現,讓你知道「它長這樣」就好。
影片已製作完成,上架後會把連結補在這篇文章裡。這篇先把 10 集的重點整理成文字,想直接看結論的人可以當成速查表。
這個系列在解決什麼問題
很多 Kubernetes 教學是從空白專案開始的。但真實的公司裡,最常見的情況是:有一套跑了很多年、每天都在賺錢的系統,程式像一碗打結的義大利麵,沒人敢動,主管卻說要「全部搬上雲端」。
整套打掉重寫聽起來痛快,風險卻很大。新系統還沒寫好之前,老系統不能停,生意每天都要做。這個系列走另一條路:新舊並存,漸進替換。
10 集一覽
| 集 | 主題 | 主比喻 | 一句話重點 |
|---|---|---|---|
| 1 | 絞殺者模式 | 絞殺榕包住老樹 | 在老系統旁邊長出新的,一塊一塊接手 |
| 2 | 把老系統裝進容器 | 貨櫃、搬家 | 容器解決「換一台就壞掉」,但不會幫你修程式 |
| 3 | 為什麼還需要 K8s | 夜市管理員 | Docker 負責裝箱,K8s 負責管一大堆箱子 |
| 4 | Pod 與 Deployment | 豆莢、班長點名 | 壞了不修,直接換新的 |
| 5 | Service | 公司總機 | Pod 會變,總機號碼不變 |
| 6 | Ingress 與新舊分流 | 百貨服務台、金絲雀 | 先讓一成的客人試新版 |
| 7 | ConfigMap 與 Secret | 便利貼、保險箱 | 設定請出程式,而且 Secret 預設沒上鎖 |
| 8 | 共用舊資料庫 | 兩個廚師搶冰箱 | 一份資料,一個主人 |
| 9 | 探針與監控 | 老師點名 | 老系統開機慢,記得加啟動探針 |
| 10 | 零信任 | 每間教室都要刷卡 | 進了大門,每一間還是要驗身分 |
全系列固定用同一組比喻,避免前後打架:容器是貨櫃、Pod 是豆莢、Deployment 是班長、Service 是總機、Ingress 是服務台、K8s 是夜市管理員。
第 1 集:絞殺者模式
熱帶雨林裡有一種樹叫絞殺榕。它的種子落在老樹的樹縫裡,根沿著樹幹往下長到土裡。很多年以後,裡面的老樹可能枯掉,外面的榕樹已經可以自己站著。從頭到尾,那個位置一直都有一棵樹。這個比喻出自 Martin Fowler 的〈Strangler Fig〉。
套到系統上分四步:
- 先把老系統裡的功能分清楚,分不清楚的先不要動。
- 在大門口放一個服務台(閘道),一開始把所有人都帶到老系統。
- 挑一個最安全的功能先換,例如查報表,因為它只看資料、不改資料。先帶一小部分客人過去,出問題就帶回來。
- 新的穩定了,就把老系統裡的那個功能關掉,再換下一個。
取捨:這一招適合老系統很大、不能停機、又一直要出新功能的情況。如果功能的界線還畫不出來,就先在老系統裡整理程式,不然只是把一碗打結的麵搬到新的碗裡。
第 2 集:把老系統裝進容器
「在我的電腦明明可以跑啊!」程式不是自己一個人在跑,它需要特定版本的語言、一堆工具和系統設定。容器把程式和它需要的東西全部裝進同一個箱子,就像貨櫃,放上哪艘船、哪輛卡車,裡面都一模一樣。
FROM php:5.6-apache
COPY ./app /var/www/html
CMD ["apache2-foreground"]
老系統裝箱時,先照原本的環境裝,能跑再說。換成最新、最小的環境,常常少了它需要的工具而起不來。
容器不會幫你做的三件事:
- 修程式。原本的錯誤和慢的地方,裝進去以後一樣在。
- 保管資料。容器隨時可能被刪掉換新的,寫在裡面的檔案會跟著消失。
- 處理寫死的設定。資料庫位置和密碼寫在程式裡,每換一個環境就要重新打包。
第 3 集:為什麼還需要 Kubernetes
容器只有一個,人還顧得來。變成一百個、分散在十台主機,就需要一位不睡覺的管理員。你不用告訴它每一步怎麼做,只要交一張願望清單:這個程式我要三份,隨時都要有三份。它會一直巡邏比對,少一份就補。這張清單叫做期望狀態。
K8s 幫你做四件事:自動補位、自動分配主機、不斷線更新、放大縮小。
取捨:K8s 本身就是一套很大的系統,要學、要維護。如果你只有幾個容器、一台主機就夠用,或者把主機升級一下就撐得住,那就還不需要它。另外,管理員只會照清單辦事,程式本身有問題,它只會很認真地一直幫你重開。
第 4 集:Pod 與 Deployment
老系統的主機有名字,壞了就修,大家把它當寵物照顧。K8s 的規則相反:壞了不修,直接換一個新的。
Pod 是 K8s 管的最小單位,可以想成包住容器的豆莢。它用完就丟,隨時可能被關掉再重新長一個,連位址都不一樣。Deployment 像班長,手上有名單,一直點名,少一個就補一個。
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 3
selector: ...
template:
containers:
- image: shop:1.0
常用指令:kubectl get pods、kubectl scale、kubectl rollout undo。
老系統最容易踩的三個坑:把檔案存在自己身上、把登入狀態記在自己的記憶體裡、用固定位址找別人。解法是同一個方向:重要的東西不要放在 Pod 身上。暫時改不了的話,可以先只開一個 Pod、把儲存空間掛在外面,但這是過渡,不是終點。
第 5 集:Service
員工常常換座位,分機一直變,所以你只打總機。Service 就是總機:它有固定的名字和位址,後面接著一群 Pod。總機靠標籤認人。
新舊並存時有兩個實際問題:
- 裡面的新程式找外面的老系統:幫老系統也設一個總機,後面接的是舊主機的位址。哪天老系統也搬進來了,只要改總機後面接誰,新程式一行都不用改。
- 外面的老系統找裡面的新程式:最簡單的是 NodePort,在每台主機上開一個同樣號碼的對外窗口。
取捨:NodePort 的號碼預設只能用 30000 到 32767,一個服務佔一個,而且每台主機都要對外開這個窗口。它適合過渡和測試,正式對外的入口交給下一集的 Ingress。站內有一篇 Kubernetes Ingress 練習 可以接著動手做。
第 6 集:Ingress 與新舊分流
這一集把第 1 集的服務台做出來。Ingress 是對外的入口,看網址後面的路徑決定帶你去哪個 Service。要注意:Ingress 只是一張規則表,真正站在門口帶路的是 Ingress Controller,只寫規則、沒有人站崗,不會有任何效果。
兩招分流:
| 做法 | 怎麼分 | 用途 |
|---|---|---|
| 照路徑分 | /report 去新服務,其他照舊去老系統 | 一塊一塊換 |
| 照比例分 | 同一個功能,十個客人裡一個去新版 | 一點一點試 |
照比例分叫金絲雀發布。用 ingress-nginx 的話,幫新版再寫一份規則,加上兩行註記:
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10"
三個代價:比例是每一次連線隨機抽的,同一位客人可能忽新忽舊;能隨時切回去的前提是新舊版本的資料彼此相容;分流出去卻沒人看數字,等於沒試。
第 7 集:ConfigMap 與 Secret
原則是程式歸程式、設定歸設定:同一個映像檔,到不同環境只換設定。ConfigMap 像貼在冰箱上的便利貼,放不怕人看的東西;Secret 像保險箱,放密碼和金鑰。
交給程式有兩種方式,差別要記得:
| 方式 | 設定改了以後 |
|---|---|
| 環境變數 | 要重新啟動容器才會生效 |
| 檔案 | 內容通常會自動更新,但程式要自己會重新讀 |
很多人不知道的事:Secret 裡那串看不懂的字是 Base64,它只是換一種寫法,不是加密,任何人拿到都能轉回原本的密碼。要讓它真的安全,至少做三件事:打開儲存加密、限制誰能讀、更講究的話交給專門保管密碼的系統。可以先從限制誰能讀開始。
第 8 集:新舊系統共用同一個資料庫
這是整個搬家過程最難的一關。讓新程式直接連進老系統的資料庫,一開始很快,後來會搶資源、互相蓋掉資料、誰都不敢改欄位。程式是分開了,卻還是綁在一起,這種狀況叫分散式單體。
原則是一份資料只能有一個主人,分三步走:
- 新程式只看、不改。幫它準備專用的副本,用變更資料擷取(CDC)讀資料庫的日誌,把每一筆變動抄到副本裡。
- 講好資料歸誰管。歸新程式的話,老系統改成來問新程式,不再自己改。
- 分家。等所有人都不再直接碰那幾張表,新程式才把資料搬進自己的資料庫。
老資料庫可以先不搬進 K8s,用第 5 集的做法幫它設一個總機就好。
代價:副本會慢一點,對報表沒差,對餘額、庫存就要小心;不要讓程式同時寫兩個資料庫,寫完第一個、第二個失敗,兩邊就對不起來了。
第 9 集:探針與監控
老系統搬上去以後一整晚都在重開,問題通常不在老系統,而是你沒告訴 K8s:它開機很慢,請等一下。
| 探針 | 問的問題 | 沒通過會怎樣 |
|---|---|---|
| 存活探針 | 你還活著嗎? | 關掉重開 |
| 就緒探針 | 你準備好接客人了嗎? | 先不把客人轉給它,但不會關掉 |
| 啟動探針 | 你開機開完了嗎? | 開完之前,前兩種都不會開始 |
老系統最需要第三種:
startupProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
failureThreshold: 30
每 10 秒問一次,最多容許失敗 30 次,等於最多給它 300 秒,也就是 5 分鐘開機。
兩個坑:檢查得太敏感會誤殺只是忙了一下的程式,放得太寬則真的卡死時要等很久;把資料庫的健康算在自己頭上,資料庫一斷線,所有程式一起說還沒好,整個網站同時停擺。
探針只能回答好或不好,想知道有多好要看數字。Prometheus 像抄表員,Grafana 把數字畫成儀表板。新舊並存時,把兩個版本的數字擺在一起比,新版錯誤變多就把客人帶回去。延伸閱讀:深入探索 Prometheus 與 Kubernetes 監控系統。
第 10 集:零信任
老系統的安全觀念像城堡,進了城門裡面隨便走。零信任有三個原則:永遠不預設信任、只給最小的權限、假設壞人已經進來了。
搬進 K8s 以後有一個很多人不知道的預設值:所有 Pod 之間預設是全部互通的。一個不重要的小程式被攻破,壞人就能直接連到資料庫,這叫橫向移動。
三道鎖:
- NetworkPolicy:先貼一張「預設誰都不准連進來」的規定,再一條一條開放。
- RBAC:依照角色給權限,不要把最大的管理員權限到處發。用
kubectl auth can-i可以檢查。 - 雙向 TLS:程式之間講話也要互相驗身分、全程加密,通常交給服務網格處理。
kind: NetworkPolicy
spec:
podSelector: {}
policyTypes:
- Ingress
這裡的 Ingress 是「連進來」的意思,和第 6 集的服務台不是同一件事。另外,K8s 的網路元件必須支援 NetworkPolicy,不支援的話規定照樣貼得上去,卻一點效果都沒有。
取捨:鎖越多越安全,也越麻煩,規則寫錯自己人也進不來。老系統可以先收回過大的權限,再把資料庫的門禁設好,最後才考慮程式之間的加密。
建議的觀看順序
| 你的情況 | 從哪裡開始 |
|---|---|
| 完全沒碰過容器 | 照順序從第 1 集看 |
| 會 Docker,沒碰過 K8s | 第 1 集,再跳第 3 集 |
| 已經在用 K8s,正要搬老系統 | 第 1、5、6、8 集 |
| 老系統搬上去一直重開 | 第 9 集 |
| 被資安稽核追著跑 | 第 7、10 集 |
這個系列怎麼做出來的
- 每一集的講稿都先用 NotebookLM 對照指定資料來源逐句查核,再請另一個模型審稿,主要來源是 Kubernetes 官方文件、ingress-nginx 文件與幾本架構電子書。
- 片中的購物網站是教學情境示意,不代表特定公司。
- 插畫為 AI 生成,圖示取自 SVG Repo,背景音樂是 Kevin MacLeod 的 “Inspired”(CC BY 3.0)。
站內延伸閱讀
- Docker Compose healthcheck 實戰:等到健康才啟動
- Kubernetes Ingress 練習
- 10 種必學的 Kubernetes 設計模式
- 深入探索 Prometheus 與 Kubernetes 監控系統
- 2024 年企業數位安全趨勢:零信任架構與數位化風險管理
(本文依 2026-11-15 完成的影片講稿整理;片中的設定檔為簡化示意,實際欄位以 Kubernetes 與 ingress-nginx 官方文件為準。)
