iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
0

本文同步刊登於個人技術部落格,有興趣關注更多 Kubernetes、DevOps 相關資源的讀者,請務必追蹤從零開始的軟體工程師之旅,喜歡的話幫我按讚分享、歡迎留言、或是許願想要看的文章。

如果有技術問題也可透過粉絲專頁 討論,技術方面諮詢免錢、需要動手做另計 XD。

曬貓


Borg, Omega and Kubernetes

這是原文完整版本。好讀版請見 Borg Omega and Kubernetes 前世今生摘要

完整英文原文請見 Borg, Omega, and Kubernetes - Lessons learned from three containermanagement systems over a decade


前車之鑑 (Things to avoid)

Google 在開發這些系統時,學到一些最好別做的事情,我們提供這些資訊,所以其他人可以避免重複的錯誤,而把犯錯的成本放在新的錯誤上。

不要使用容器管理系統管理 Port number

Borg 上所有容器都使用宿主機器的 IP,

  • Borg 在分配時便指派給每個容器各自的 port number。每個容器移動到新機器時會取得一個新的 port number,有時在本機重啟也會拿到新的。
  • 這點表示既存的網路服務 (例如 DNS) Google 都必須自行改動並使用自維護的版本;
  • 服務的客戶端並不能主動獲得服務的 port number 資訊,需要被動告知;
  • port number 也不能放在 URLs 中,還需要額外的轉址機制;
  • 所有基於 IP 運作的工具都需要改成使用 IP:Port。

有鑑於此,Kubernetes 上每個 Pod 分配一個 IP,讓

  • 應用的身分符合網路身分 (IP address),
  • 讓現成的應用更容易在 Kubernetes 上執行,應用可以直接使用靜態的常規 port number (例如 HTTP 流量使用 80 port),
  • 現有的工具也可以直接使用,例如網段切分 (network segmentation)、帶寬節流 (bandwidth throttling) 與控制。
  • 所有的公有雲都提供每個 Pod 一個 IP 的網路基底,
  • 在實體機器 (bare metal),也可以使用軟體定義網路 (Software defined network) 的 overlay 網路,或是設定 L3 路由來配置機器上的 Pod IPs。

不要幫容器編號,使用 label 控制容器

容器建構變得方便後,使用者會產生大量容器,很快就需要一個群組管理的方法。

Borg 提供 job 給一組相同的 tasks (task 作為容器的名稱),一個 job 是一組向量集合 (compact vector) 可以指向一個或多個 tasks,將 task 從 0 開始遞增編號,

  • 這個做法很直接也很方便,
  • 但等稍後需要重啟容器時,Google 就後悔這個固定的設計,例如其中一個 task 死了需要重啟刀另外一台機器,原本的 task 向量的相同位置,現在需要做兩倍工作:找到新的副本,然後指向舊的副本以免需要除錯。
  • 當向量集合中的 task 離開後,這個向量上就有很多空洞,這讓 Borg 上層的管理系統分配,跨級群的 job 時變得很困難。
  • 這也造成 Borg 的 job 升級語法中出現許多危險且不可預期的交互 (當滾動升級時依照 index 順序重啟 task),而應用仰賴 task index (例如應用使用 index 執行資料級的 sharding 或 paritioning):如果應用使用 task index 來做 sharding,Borg 重啟時會移除鄰近的 tasks,導致資料不可用。
  • Borg 也沒有好方法來增加來自應用的 metadata 到 task 上,例如角色 (e.g. 前端網頁)、或是滾動升級的狀態 (e.g. canary),工程師只好將 metadata 編碼,壓在 jobs 的名稱上,再使用正規表達式 (regular expression) 解碼。

Kubernetes 直接使用 label 來辨識容器群,label 是鍵值資料對 (key-value pair),包含可以辨識應用的資料,

  • 一個 Pod 可能有 role=frontend 與 state=production 表示 Pod 是屬於 production 環境的前端網頁。
  • label 可以動態增加,並使用自動化工具更改,個團隊可以自行維護一組各自的 label。
  • 使用 label-selector 來取得一組物件 (e.g. stage==production && role==frontend)。
  • 各組物件可以重複,一個物件也可以屬於多個物件組,
  • 所以 label 也比靜態的物件清單更有彈性。
  • 由於物件組都是動態查詢時產生的,任何時候都可以增加新的物件組。
  • label-selector 是 Kubernetes 的群組機制,並藉此分界管理維運,又可以同時處理多個實體。

雖然有些使用情形,事先明確知道一組內有哪些 task 很有用 (例如靜態腳色指派、工作 partitioning 或 sharding),合理的 label 也能產生一樣的效果,只是應用 (或是其他外部管理系統) 就需要負責提供 labeling。label 與 label-selector 為雙邊提供最適的做法。

注意 Pod 的所有權

Borg 上 task 依賴 job,不會獨自存在,產生 job 時產生 tasks,這些 tasks 永遠連結特定的 job,刪除 job 同時刪除 tasks。這點很方便,但有一個缺陷,這個單一的群組機制,需要應對所有使用需求。例如 一個 job 需要儲存參數,提供給服務或是提供給應用,但不會一起提供,使用者就需要開發取代方案來協助處理 (e.g. DaemonSet 將 Pod 複製到所有節點上)

Kubernetes 中 Pod 的生命週期管理元件,例如 replication controller,使用 label selector 決定那些 Pod 要負責管理,

  • 所以會有一個以上的 controller 認為他們都對某個 Pod 有管轄權,這樣的衝突需要透過明確設定避免的。
  • 由於 label 的彈性也有許多優點,例如將 controller 與 Pod 解藕,表示再也不會有以往的孤兒 Pod (orphan) 或是認領的 Pod (adopt)。
  • 考慮附載均衡服務,透過 label selector 選擇流量的端點,如果一個 Pod 行為有異,這個 Pod 只要移除對應的 label,Kubernetes service load balancer 就可以避免流量,輕易的被隔離開來,
  • 但 Pod 本身還會存在,提供原地除錯。
  • 同時,管理 Pod 的 replication controller 會增加一個 Pod 來取代行為有異的 Pod。

不要暴露 raw state

Borg、Omega、Kubernetes 的關鍵不同點是 API 的架構設計。

  • Borgmaster 是一個集中單一的 (monolithic) 元件,可見所有的 API 行為,包含級群管理邏輯,例如 job 與 task 的狀態機制,並且使用基於 Paxos 算法的分散式儲存庫。
  • Omega 除了儲存庫以外,沒有集中式的元件,儲存庫只儲存被動的狀態資訊,提供樂觀的平行控制 (optimistic concurrenty control):
  • 所有邏輯與語法都推送到儲存庫的客戶端,
  • 所以所有客戶端都可以讀取 Omega 的所有邏輯。
  • 實務中 Omega 的元件都使用相同的客戶端程式庫,負責打包/解包資料結構、資料重送、並確保語法的一致性。

Kubernetes 選擇中間,

  • 類似 Omega 元件化架構的架構,確保全域的常數、政策控管、資料轉型,來提供彈性與擴容性。
  • Kubernetes 確保所有的儲存庫存取都透過 API server,API server 隱藏儲存庫的實作、負責物件的驗證、除錯、版本控制。
  • 如同 Omega,Kubernetes 提供多種不同的客戶端 (特別給是開源的環境),
  • 但是集中化的 API server,仍能確保相同的語法、恆量、與政策控管。

明日小結:Borg Omega and Kubernete,其他困難的開放問題


上一篇
Day 5 - Borg Omega and Kubernetes,協調管理只是開始,而不是終點 (Orchestration is the beginning, not the end)
下一篇
Day 7 - Borg Omega and Kubernetes,其他困難的開放問題
系列文
Kubernetes X DevOps X 從零開始導入工具 X 需求分析*從底層開始研究到懷疑人生的體悟*30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言