Telepresence 今年七月在八天內推出兩次重大發行:14 日的 2.30 版,以及 22 日的 2.31 版。兩次發行加起來,是本專案自 2.x 架構誕生以來最大的進展,而它們共享的主題直到事後才變得清晰。多年來 Telepresence 所承諾的每一項功能,都帶有一個但書——當你試著在真實組織中使用時才會發現的限制。你可以附加到任何工作負載(*前提是你允許我們修改它)。你的流量會打通到筆電(*每一 byte 都經由 Kubernetes API server)。你的整個團隊都能使用(*任何能連到 traffic-manager 的人也能使用)。你的開發環境可以重現(*以一篇 wiki 命令說明,既無法被同事執行,也無法被 CI pipeline 執行)。
這兩次發行把這些但書全部拿掉。本篇文章會逐一說明每項改變——不僅是「改了什麼」,還包括「為什麼最後變成這樣」。很少是從白板直接得出:這些設計來自多年遇到的實際問題,以及與社群的長期對話,而這些背景才是真正有趣的決策所在。
如果你還沒接觸過 Telepresence:它是一套 CNCF 工具,能把你的工作站連接到 Kubernetes 叢集的網路,讓你正在開發的服務在本地以 IDE、除錯器、亞秒級重建的方式執行,同時行為如同部署在叢集中,也能接收周遭服務的即時流量。
不需碰觸 Pod 即可附加
自 2.x 架構誕生以來,一直有一件事是確定的:若要接收工作負載的流量,Telepresence 必須修改該工作負載。traffic-agent sidecar 會被注入 Pod,這代表 Pod 模板會被重寫,Pod 也會在 agent 首次抵達時重新啟動。
這個設計有其充分理由,而這些理由至今依然存在。sidecar 是無特權的,它存在於 Pod 自己的安全情境中,可以像其他容器一樣被准入與稽核,且允許管理員嚴格限制開發者的 RBAC,因為叢集端的機制會處理特權工作。對於長期團隊安裝而言,這是穩健的架構,且仍是預設值。
但周遭生態已經改變。在設計 sidecar 時,「Pod spec 改變」不算什麼事。今天這往往會被視為事件:GitOps pipeline 會把任何偏離已提交 manifest 的情況標記,有些甚至會立即還原;准入政策會拒絕在審核後發生變動的 Pod spec;平台團隊擁有的工作負載明確禁止產品開發者修改;有些工作負載重啟成本很高——例如長時間暖機的 JVM、有選舉的 stateful 服務、執行中的 batch worker。在所有這些情境中,sidecar 不只是不便,而是根本無法使用。
2.30 版推出的 node-agent 正是解答。當你附加到工作負載時,traffic-manager 會在目標 Pod 所在節點上建立 node-pinned Job。該 agent 從外部進入 Pod 的網路命名空間,並從該處提供附加服務——提供與 sidecar 相同的流量重導、環境與 volume 存取,但 Pod 本身不會被修改,也不會重新啟動。後續結果隨之而來:
- 附加與分離即時完成。 沒有 rollout 需要等待,也沒有重啟需要排程。分離不會在工作負載留下任何痕跡——drift detection 找不到任何東西,因為從未發生過 drift。
- 可對不屬於你的工作負載運作。 Pod spec 永遠不會被碰觸,因此沒有任何東西會被 admission controller 拒絕,也沒有任何修改會被政策禁止。
- 涵蓋每一份 replica。 traffic-manager 會為每個 replica 建立一個 agent,並在 Pod 增減時調解集合,因此 scaled 工作負載在 intercept 下的行為正確,而非只 intercept 到「幸運」的 replica。
- 多位開發者共用 agent。 兩個人附加到同一個工作負載時,會重用相同的 node-agent,而非堆疊多層機制。
權衡也必須與效益一樣清楚說明:node-agent 以特權 Job 形式執行,因為從外部進入另一個 Pod 的網路命名空間本質上就是特權操作。這沒有任何巧妙技巧可以避開;任何附加到未修改 Pod 的工具,都必須在某處付出這個代價。你能選擇的是特權放在哪裡——放在由 traffic-manager 按需建立的短暫、node-pinned Job,而非放在開發者執行的任何東西裡。agent-modes 指南會說明如何在 sidecar 與 node-agent 之間選擇,因為兩者在不同叢集中都有其適用性。
如果透過 node-level agent 附加到未修改的工作負載聽起來很像 mirrord,那就應該如此——這正是 mirrord 圍繞的核心方法,而且是個好方法。2.30 版讓 Telepresence 同時提供兩種模式。這兩個工具在架構上仍有重大差異——Telepresence 在網路層連接你的整個工作站,mirrord 則在 syscall 層連結單一程序——我們維持一份詳盡且公正的比較,說明何時哪個工具更適合。
traffic-manager 現在知道是誰在呼叫
2.31 是一次安全性發行,而且是遲來的發行。它所處理的不舒服事實是:直到現在,traffic-manager 仍然信任它的呼叫者。任何能連到其 gRPC endpoint 的人,都能建立 session、對其他用戶端的附加執行操作,並路由流量——卻從未證明自己是誰。兩個高嚴重性諮詢 GHSA-j8j4-rw65-56r6 與 GHSA-6j3h-rp73-6rvf 具體描述了這會帶來什麼後果:叢集中任何 Pod 都可以自稱是 traffic-agent 並攔截服務流量,而活躍的用戶端 session 也可能被任何知道其 ID 的人劫持。
工具為什麼會走到這一步?從歷史來看:Telepresence 是在被視為可信任的叢集中成長的開發工具。可達性就是邊界。這個假設早在多年前就不再站得住腳——叢集是多租戶的,工作負載是半受信任的,而「叢集中任何東西都能呼叫任何東西」正是 zero-trust 架構想要消滅的特性。修正必須把身份驗證回溯到原本沒有這個概念的協定,同時不破壞任何現有安裝。這個限制形塑了所有設計。
第一個設計決策:不要發明新的憑證系統。 叢集已經有了一套。用戶端現在會轉送其 kubeconfig 憑證所解析出的 bearer token——可能是 static token、token file,或 exec credential plugin 的輸出——而 traffic-manager 會用 Kubernetes TokenReview 驗證它。用戶端呈現的身份,正是叢集會賦予它的身份;不需要新增任何東西來佈建、輪替或洩漏。traffic-agent 則使用 projected、audience-bound ServiceAccount token 進行驗證,這不僅證明它們是什麼,還能證明它們是哪個 Pod——特別封閉了 impersonate-an-agent 的漏洞。
在驗證之上,還有兩項授權規則,都建立在叢集已經理解的概念上:
- Session 會綁定建立它的身份。 呼叫者無法再對其他用戶端或 agent 的 session 執行操作——無法檢視別人的 intercept、移除別人的附加,或代表它不在其中執行的 Pod 發言。
-
建立 intercept 需要 RBAC——具體來說,呼叫者的 Kubernetes 身份必須在目標命名空間擁有
pods/portforward權限,並透過SubjectAccessReview檢查。這個權限是刻意選擇的:這正是kubectl port-forward已經需要的權限,而 intercept 在能力上就是 port-forward。沒有新的政策語言,也不需要設計 Telepresence 專屬的角色;如果你的叢集 RBAC 已經定義了誰可以對 Pod 轉送流量,那麼現在也定義了誰可以 intercept 它們。
第二個設計決策與 rollout 有關,既是技術觀察,也反映社會學現象:會破壞現有安裝的安全性升級不會被安裝。 它們會被延後、被繞過、被怨懟——而未套用的安全修正無法保護任何人。因此,強制執行是 opt-in,由一個 Helm 值控制,共有三種設定。permissive 是預設值,會驗證每個 token 並記錄每項授權決策,但不會拒絕任何東西:升級對使用者完全沒有改變,而日誌會告訴你強制執行本來會做什麼。enforcing 會開啟拒絕。(disabled 是給真正想要舊行為的安裝。)預期的路徑設計上很平淡:升級、讓用戶端與 agent 機群跟上、觀察 permissive 日誌直到安靜下來,再切換開關。較舊的用戶端在 permissive manager 上仍可運作,而 2.31 用戶端在較舊的 manager 上也能運作——只有最後一步需要整個機群保持最新。
完整細節(包含每種 kubeconfig 憑證類型提供的內容)已收錄於新的authentication 參考文件。
QUIC:把 API server 移出資料路徑
工作站與叢集之間的所有隧道流量,過去都走單一 port-forwarded gRPC 連線。這個設計有一個很大的優點:它在任何地方都能運作。只要你能連到 Kubernetes API server,你就能 port-forward,而只要你能 port-forward,Telepresence 就能運作——不需要 LoadBalancer、不需要開啟埠口、不需要與防火牆協商。
但看看它的代價。port-forward 走 API server 連線,這代表每 byte 的隧道開發流量——服務收到的每一個請求、它對上游發出的每一個呼叫——都會經過叢集的控制平面。API server 是叢集中最關鍵、最容易競爭的元件,它從來不是為了當資料平面而設計的。對單一開發者而言,負載只是雜訊;對跨組織執行 Telepresence 的平台團隊而言,這是可衡量的,而且花在完全錯誤的元件上。
單一連線也傷害開發者。一條 gRPC 連線就是一條 TCP 串流,而把所有流量多工到一條 TCP 串流,等於在規模上買到 TCP 最糟糕的特性:head-of-line blocking。當封包遺失時,TCP 會把後面所有東西都擋住,直到重傳抵達——包括那些只是共用同一個管道、彼此無關的流量。在乾淨的網路中你不會注意到,但在容易遺失封包的環境——飯店 Wi-Fi、VPN concentrator 狀態不佳、壅塞的最後一哩——每條流量都會定期為其他流量的壞運氣付出代價,而隧道會莫名其妙地變得延遲,且難以歸因。
2.31 版的 opt-in QUIC 傳輸同時解決了這兩個問題。用戶端會直接連線到 traffic-manager 暴露的 QUIC endpoint,因此隧道流量完全繞過 API server——控制平面回歸控制平面工作。而因為 QUIC 讓每條串流擁有獨立的遺失恢復,遺失的封包只會讓它所屬的流量停滯。我們的基準測試同時驗證了這兩點:在 1–3% 的 ingress 封包遺失率下,小型請求流量在共用 gRPC 隧道上的尾端延遲,比 QUIC 高出 1.7–1.8 倍——而小型請求的尾端延遲正是互動式開發的感受——而且效能提升不只限於容易遺失封包的網路:在多種基準測試形狀中,直接 QUIC 路徑甚至快了好幾倍。
為什麼是 opt-in?因為讓 gRPC 隧道具有普遍性的特性,正是 QUIC 無法擁有的。QUIC endpoint 必須能以 UDP 服務的形式被存取——需要 LoadBalancer 或 NodePort——這是管理員的決定,並非每個叢集都能提供。因此,traffic-manager 只有在設定 quicTunnel.enabled 時才會暴露 QUIC,用戶端在可達時會自動將新的隧道連線升級到 QUIC,而 gRPC 仍是預設值且永遠可用的備援。telepresence status 會告訴你實際使用的傳輸方式——無需猜測。
你的開發環境現在是一個檔案
Kubernetes 之所以勝出,靠的是單一理念:描述你想要的狀態,讓 controller 去實現它。然而,叢集原生開發的工作站端,至今仍頑固地維持命令式——連接到這個叢集、用這九個旗標 intercept 那個服務、啟動本地伺服器、明天重複一次,並靠一篇兩季前還算準確的 wiki 頁面來 onboarding 新隊友。
2.31 版推出的 telepresence apply -f dev.yaml,把宣告式模型帶到工作站。manifest 描述了可選的連線,以及一組附加——intercept、replace、ingest 或 wiretap——每一個都有自己的旗標,並可選擇在附加啟用時執行的本地命令:你的開發伺服器,會在附加就緒時啟動、在附加拆解時停止。Apply 是冪等的:已經符合 manifest 的東西會被保留,已經 drift 的東西會被重新建立,而 --dry-run 會顯示計畫而不碰觸任何東西。telepresence delete -f 則會把整個狀態拆除。
實際的轉變比功能清單看起來更大。一個團隊的標準開發設定,不再是部落知識,而是變成 repo 中的一個檔案——版本控管、經過審核,而且對新進人員與資深人員都完全相同。「我該怎麼在這個服務上設定開發環境?」變成 telepresence apply -f dev.yaml,而且每台機器上的答案都一樣。
下一步:把叢集知識移進工具
上述功能讓 Telepresence 變得更強大。下一項計畫攻擊的則是另一個問題:第一個小時。
安裝一個真正適合叢集的 traffic-manager,需要回答關於該叢集的問題。它能不能暴露 QUIC endpoint?應該是 LoadBalancer 還是 NodePort?node-agent 能不能通過叢集的准入政策?mutating webhook 能不能建立?API server 能不能連到它?安裝應該是叢集範圍還是命名空間範圍?要涵蓋哪些命名空間?是否已經安裝了某些東西?它是否健康?今天,這些答案散落在參考文件與試錯之中,而這對評估 Telepresence 是否值得採用的人來說,是真正的成本——最熟悉這些問題的人,正是最不需要文件的人。
即將推出的 telepresence setup 命令(計畫在後續版本推出),把這些知識移進工具。它會以唯讀方式探測叢集——安裝權限、QUIC 可行性、node-agent 准入(搭配伺服器端 dry-run canary 來實際測試政策引擎)、webhook 可達性、命名空間規模、現有安裝及其健康狀態,甚至工作站本地網路的路由衝突。然後它只詢問探測後仍未解決的問題,並驗證、寫入或套用完全配置好的 Helm install。值得注意的設計決策:它永遠不會修改工作站,因此可以安全地重複執行,也能安全地唯讀執行;它寫出的 values 檔案是純 Helm values 文件,因此可以直接納入 GitOps 而非繞過它;它同時也能作為現有安裝的 doctor;當你缺乏叢集權限時,它會產生一份給管理員的清單式交接,而不是死胡同。
感謝 OpenAI
如果沒有有資金支持的維護者時間,這一切都不可能發生,而這值得具體說明。像 node-agent 或從頭打造驗證層這樣的機能,需要數月的開發週期:設計、實作、安全審查、文件撰寫,以及漫長的強化尾聲。這種規模的工作無法靠晚上與週末完成——既不可持續,也無法達到安全層所要求的水準。
OpenAI 贊助 Telepresence 專案。 不是針對這些特定功能——沒有任何功能方向的綁定——只是持續支持這個專案本身。這正是讓維護者有空間承接這種規模工作的贊助方式,而這兩次發行正是直接成果。感謝你們。
Telepresence OSS 是 CNCF 專案,採用 Apache 2.0 授權。本篇文章描述的所有內容都是免費的——沒有席次、沒有付費等級、沒有功能閘道。如果你的組織從中獲得價值,最好的回饋方式就是貢獻與贊助,這會直接資助維護與開發。
開始使用
快速入門 大約需要十分鐘。完整的變更清單請參閱發行說明,歡迎在 GitHub Discussions 或 CNCF Slack 的 #telepresence-oss 提出問題與經驗分享。
本文最初發表於 telepresence.io。
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.