擴展和補充 Kubernetes(評論和視頻報告)

擴展和補充 Kubernetes(評論和視頻報告)

8月XNUMX日 會議 聖徒 HighLoad++ 2019作為「DevOps 和營運」部分的一部分,給出了一份「擴展和補充 Kubernetes」的報告,Flant 公司的三名員工參與了該報告的創建。 在其中,我們討論了許多我們想要擴展和補充 Kubernetes 功能的情況,但我們沒有找到現成的簡單解決方案。 我們以開源專案的形式提供了必要的解決方案,本次演講也是專門針對它們的。

按照傳統,我們很高興向您展示 報告影片 (50 分鐘,比文章豐富得多)和文本形式的主要摘要。 去!

K8s 中的核心和附加功能

Kubernetes 正在改變產業和早已建立的管理方法:

  • 感謝他 抽象,我們不再使用設定配置或執行命令(Chef、Ansible...)等概念進行操作,而是使用容器、服務等分組。
  • 我們可以在不考慮細微差別的情況下準備申請 具體站點,它將在其上啟動:裸機、提供者之一的雲端等。
  • 有了 K8s,您變得前所未有的方便 最佳實踐 關於組織基礎設施:擴展技術、自我修復、容錯等。

然而,當然,一切並不是那麼順利:Kubernetes也帶來了自己的新挑戰。

Kubernetes 沒有 是一個解決所有用戶所有問題的組合。 核心 Kubernetes 只負責一組最低限度的必要功能,這些功能存在於 簇:

擴展和補充 Kubernetes(評論和視頻報告)

Kubernetes 核心定義了一組基本原語,用於對容器進行分組、管理流量等。 我們在中更詳細地討論了它們 2年前的報告.

擴展和補充 Kubernetes(評論和視頻報告)

另一方面,K8s 提供了擴展可用功能的絕佳機會,這有助於關閉其他功能 - 具體的 ——用戶需求。 Kubernetes 的新增是叢集管理員的責任,他們必須安裝和配置一切必要的東西,以使叢集「處於正確的狀態」[以解決他們的特定問題]。 這些都是什麼樣的補充呢? 讓我們來看一些例子。

附加元件範例

安裝 Kubernetes 後,我們可能會感到驚訝,節點內和節點之間的 Pod 互動所必需的網路無法自行運作。 Kubernetes 核心不保證必要的連接;相反,它決定網絡 接口 (CNI)對於第三方附加元件。 我們必須安裝這些附加元件之一,它將負責網路配置。

擴展和補充 Kubernetes(評論和視頻報告)

一個很接近的例子是資料儲存解決方案(本機磁碟、網路區塊設備、Ceph...)。 最初它們位於核心,但隨著出現 CSI 情況會發生與已經描述的類似的情況:介面位於 Kubernetes 中,其實作位於第三方模組中。

其他範例包括:

  • 入口-控制器 (請參閱他們的評論 我們最近的文章).
  • 證書經理:

    擴展和補充 Kubernetes(評論和視頻報告)

  • 運營商 是一整類附加元件(其中包括提到的憑證管理員),它們定義原語和控制器。 他們的工作邏輯僅受我們想像的限制,並允許我們將現成的基礎設施元件(例如 DBMS)轉換為原語,這比使用一組容器及其設定更容易使用。 已經編寫了大量的運算符 - 即使其中許多尚未準備好用於生產,但這只是時間問題:

    擴展和補充 Kubernetes(評論和視頻報告)

  • 指標 - Kubernetes 如何將介面(Metrics API)與實作(第三方附加元件,如 Prometheus 適配器、Datadog 叢集代理...)分離的另一個例子。
  • 監測與統計,在實踐中不僅需要 普羅米修斯和格拉法納,還有 kube-state-metrics、node-exporter 等。

這不是完整的添加清單...例如,在 Flant 公司,我們目前安裝 29 補充 (所有這些總共創建了 249 個 Kubernetes 物件)。 簡而言之,如果沒有添加,我們就無法看到叢集的生命週期。

自動化

Operator 旨在自動化我們每天遇到的日常操作。 以下是現實生活中的範例,編寫運算子將是一個很好的解決方案:

  1. 有一個私有(即需要登入)註冊表,其中包含應用程式的映像。 假設每個 pod 都分配有一個特殊的秘密,允許在註冊表中進行身份驗證。 我們的任務是確保在命名空間中找到這個秘密,以便 Pod 可以下載映像。 可能有很多應用程式(每個應用程式都需要一個秘密),並且定期更新秘密本身很有用,因此消除了手動佈置秘密的選項。 這就是操作員發揮作用的地方:我們創建一個控制器,它將等待命名空間出現,並根據此事件為命名空間添加一個秘密。
  2. 預設情況下,禁止從 pod 存取網際網路。 但有時可能需要:存取權限機制簡單地工作是合乎邏輯的,不需要特定的技能,例如,透過命名空間中存在某個標籤。 運營商可以如何幫助我們? 建立一個控制器,等待標籤出現在命名空間中,並新增適當的 Internet 存取策略。
  3. 類似的情況:假設我們需要添加某個 污點,如果它有類似的標籤(帶有某種前綴)。 操作員的動作是顯而易見的...

在任何集群中,必須解決日常任務,並且 正確地 這可以使用運算子來完成。

總結所有描述的故事,我們得出的結論是 為了在 Kubernetes 中舒適地工作,您需要: A) 安裝附加元件, b) 發展經營者 (用於解決日常管理任務)。

如何為 Kubernetes 撰寫聲明?

一般來說,該方案很簡單:

擴展和補充 Kubernetes(評論和視頻報告)

……但事實證明:

  • Kubernetes API 是一個相當重要的東西,需要花費大量時間才能掌握;
  • 程式設計也不適合所有人(選擇 Go 語言作為首選語言是因為它有一個特殊的框架 - 營運商SDK);
  • 框架本身的情況類似。

底線: 編寫一個控制器 (操作員)必須 花費大量資源 研究材料。 這對於「大型」營運商來說是合理的——例如,對於 MySQL DBMS。 但是,如果我們還記得上面描述的示例(揭開秘密、將Pod 訪問互聯網......),我們也希望正確執行這些示例,那麼我們就會明白,所付出的努力將超過我們現在需要的結果:

擴展和補充 Kubernetes(評論和視頻報告)

一般來說,會出現一個兩難的困境:花費大量資源並找到合適的工具來編寫語句,或以老式的方式(但速度很快)進行編寫。 為了解決這個問題 - 在這些極端之間找到折衷方案 - 我們創建了自己的專案: 外殼操作符 (另見他的 最近的公告 在輪轂上).

Shell 運算符

他如何工作? 該叢集有一個 pod,其中包含帶有 shell 操作符的 Go 二進位。 他旁邊有一套 掛鉤 (有關它們的更多詳細資訊 - 請參閱下文)。 shell 運算子本身訂閱了某些 事件 在 Kubernetes API 中,一旦發生就會啟動對應的鉤子。

shell 操作符如何知道要針對哪些事件呼叫哪些鉤子? 這些資訊由鉤子本身傳送到 shell 操作符,而且它們做得非常簡單。

鉤子是 Bash 腳本或任何其他接受單一參數的可執行文件 --config 並以 JSON 回應。 後者確定它感興趣的對像以及應該回應哪些事件(對於這些對象):

擴展和補充 Kubernetes(評論和視頻報告)

我將說明我們範例之一的 shell 運算子的實作 - 分解用於使用應用程式映像存取私有註冊表的秘密。 它由兩個階段組成。

練習:1.寫一個hook

首先,在hook中我們將處理 --config,表明我們對命名空間感興趣,特別是它們的創建時刻:

[[ $1 == "--config" ]] ; then
  cat << EOF
{
  "onKubernetesEvent": [
    {
      "kind": "namespace",
      "event": ["add"]
    }
  ]
}
EOF
…

邏輯會是什麼樣的呢? 也很簡單:

…
else
  createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
  kubectl create -n ${createdNamespace} -f - << EOF
Kind: Secret
...
EOF
fi

第一步是找出創建了哪個命名空間,第二步是使用以下命令創建它 kubectl 此名稱空間的秘密。

練習:2. 組裝影像

剩下的就是將創建的鉤子傳遞給 shell 操作符 - 如何做到這一點? shell-operator 本身就是一個 Docker 映像,所以我們的任務是將鉤子新增到該映像中的特殊目錄:

FROM flant/shell-operator:v1.0.0-beta.1
ADD my-handler.sh /hooks

剩下的就是組裝它並推動它:

$ docker build -t registry.example.com/my-operator:v1 .
$ docker push registry.example.com/my-operator:v1

最後一步是將映像部署到叢集。 為此,我們要寫 部署:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-operator
spec:
  template:
    spec:
      containers:
      - name: my-operator
        image: registry.example.com/my-operator:v1 # 1
      serviceAccountName: my-operator              # 2

有兩點要注意:

  1. 新創建的圖像的指示;
  2. 這是一個系統元件(至少)需要訂閱 Kubernetes 中的事件並向命名空間分配機密的權限,因此我們為該鉤子建立一個 ServiceAccount(和一組規則)。

結果——我們解決了問題 親戚們 對於 Kubernetes,以建立分解秘密的操作符的方式。

其他 shell 操作符功能

要限制鉤子將使用的所選類型的對象, 它們可以被過濾,根據某些標籤進行選擇(或使用 matchExpressions):

"onKubernetesEvent": [
  {
    "selector": {
      "matchLabels": {
        "foo": "bar",
       },
       "matchExpressions": [
         {
           "key": "allow",
           "operation": "In",
           "values": ["wan", "warehouse"],
         },
       ],
     }
     …
  }
]

假如 重複資料刪除機制,它 - 使用 jq 過濾器 - 允許您將大型 JSON 物件轉換為小型對象,其中僅保留我們想要監視更改的參數。

當呼叫鉤子時,shell 操作符會傳遞它 對象資料,可用於任何需要。

觸發鉤子的事件不限於 Kubernetes 事件:shell-operator 提供支持 按時間調用鉤子 (類似於傳統調度程式中的 crontab),以及特殊事件 啟動時。 所有這些事件都可以組合併分配給同一個鉤子。

shell 運算子的另外兩個功能:

  1. 有用 非同步地。 由於接收到 Kubernetes 事件(例如正在建立的物件),叢集中可能會發生其他事件(例如正在刪除相同物件),而鉤子需要考慮到這一點。 如果鉤子執行時出錯,那麼預設情況下它將是 記起 直到成功完成(可以更改此行為)。
  2. 它出口 指標 對於 Prometheus,您可以透過它來了解 shell 運算元是否正常運作,找出每個鉤子的錯誤數和目前佇列大小。

總結報告的這一部分:

擴展和補充 Kubernetes(評論和視頻報告)

安裝附加元件

為了舒適地使用 Kubernetes,也提到需要安裝附加元件。 我將用我們公司現在的做法為例來向您介紹這一點。

我們開始使用具有多個叢集的 Kubernetes,唯一新增的是 Ingress。 它需要在每個叢集中進行不同的安裝,我們為不同的環境做了幾種YAML配置:裸機、AWS…

由於叢集越多,配置也就越多。 此外,我們也改進了這些配置本身,因此它們變得非常異質:

擴展和補充 Kubernetes(評論和視頻報告)

為了讓一切井井有條,我們從一個腳本開始(install-ingress.sh),它將我們將部署到的叢集類型作為參數,產生必要的 YAML 配置並將其推廣到 Kubernetes。

簡而言之,我們的進一步路徑以及與之相關的推理如下:

  • 要使用 YAML 配置,需要一個模板引擎(在第一階段,這是簡單的 sed);
  • 隨著叢集數量的增加,自動更新的需求來了(最早的解決方案是將腳本放在Git中,使用cron更新並運行);
  • Prometheus 需要類似的腳本(install-prometheus.sh),然而,值得注意的是,它需要更多的輸入資料及其儲存(以一種好的方式 - 集中式和叢集中),並且可以自動產生一些資料(密碼):

    擴展和補充 Kubernetes(評論和視頻報告)

  • 向越來越多的叢集推出錯誤的風險不斷增加,因此我們意識到安裝程式 (即兩個腳本:Ingress 和 Prometheus) 需要暫存(Git 中的多個分支,幾個 cron 來在相應的穩定或測試叢集中更新它們);
  • с kubectl apply 它變得很難使用,因為它不是聲明性的,只能創建對象,但不能決定它們的狀態/刪除它們;
  • 我們缺少一些當時根本沒有實現的功能:
    • 完全控制叢集更新的結果,
    • 根據可以從叢集取得的資料(發現)自動確定一些參數(安裝腳本的輸入),
    • 它以不斷發現的形式邏輯發展。

我們在其他項目的框架內實施了所有這些累積的經驗 - 插件操作符.

附加操作符

它基於已經提到的 shell 運算子。 整個系統如下圖所示:

以下內容被加入到 shell-operator 掛鉤中:

  • 值儲存,
  • 舵圖,
  • 組件 監控值存儲 並且 - 如果發生任何變化 - 要求 Helm 重新滾動圖表。

擴展和補充 Kubernetes(評論和視頻報告)

因此,我們可以對 Kubernetes 中的事件做出反應,啟動一個鉤子,透過這個鉤子我們可以對儲存進行更改,之後圖表將被重新下載。 在結果圖中,我們將一組鉤子和圖表分離成一個組件,我們稱之為 模組:

擴展和補充 Kubernetes(評論和視頻報告)

可以有很多模組,我們為它們添加全域鉤子、全域值儲存以及監視該全域儲存的元件。

現在,當 Kubernetes 中發生某些情況時,我們可以使用全域鉤子對其做出反應並更改全域儲存中的某些內容。 此變更將被注意到,並將導致叢集中的所有模組被推出:

擴展和補充 Kubernetes(評論和視頻報告)

此方案符合安裝上述附加元件的所有要求:

  • Helm 負責模板化和聲明性。
  • 自動更新的問題是使用全域鉤子解決的,該鉤子按計劃進入註冊表,如果在那裡看到新的系統映像,則將其推出(即「自身」)。
  • 在叢集中儲存設定是透過使用 配置映射表,其中包含儲存的主要資料(在啟動時它們被載入到儲存中)。
  • 使用鉤子解決了密碼產生、發現和持續發現的問題。
  • 分段是透過標籤實現的,Docker 開箱即用地支援標籤。
  • 使用指標來監控結果,透過這些指標我們可以了解狀態。

整個系統在 Go 中以單一二進位的形式實現,稱為 addon-operator。 這使得圖表看起來更簡單:

擴展和補充 Kubernetes(評論和視頻報告)

此圖中的主要組件是一組模組 (下面以灰色突出顯示)。 現在我們可以花一點力氣為所需的附加元件編寫一個模組,並確保它將安裝在每個叢集中,將被更新並回應叢集中所需的事件。

「植物」用途 插件操作符 在 70 多個 Kubernetes 叢集上。 目前狀態 - 阿爾法版本。 現在我們正在準備發布測試版的文檔,但目前在儲存庫中 可用的例子,在此基礎上您可以創建自己的插件。

我在哪裡可以獲得 addon-operator 的模組? 發布我們的庫是我們的下一階段;我們計劃在夏天進行。

影片和幻燈片

表演影片(約 50 分鐘):

報告介紹:

聚苯乙烯

我們部落格上的其他報導:

您可能也對以下出版物感興趣:

來源: www.habr.com

添加評論