導航:首頁 > 源碼編譯 > k8s編譯法

k8s編譯法

發布時間:2024-09-22 02:42:46

1. k8s的Mutating webhook

Admission Webhook 是 api-server 對外提供的一個擴展能力,api-server 作為 kubernetes 的核心,幾乎所有組件都需要跟他打交道,基本可以說掌控了 k8s 的 api-server,你就可以控制 k8s 的行為。

在早期的版本 api-server 並沒有提供 admissionresgistration 的能力(v1.9之前),當我們要對 k8s 進行控制的時候,只能重新編譯 api-server。比如你想阻止某個控制器的行為,或攔截某個控制器的資源修改。admission webhook 就是提供了這樣的能力,比如你希望某個特定 label 標簽的 pod 再創建的時候都注入 sidercar,或者阻止不合規的資源。

Admission Webhook 包涵兩種 CRD: mutatingwebhookconfiguration 和 。

下面是一個 mutatingwebhookconfiguration 的CRD文件:

Admission Webhook 本質是 api-server 的一個 webhook 調用,下面是 api-server 的處理流程:

api-server 通過讀取 mutatingwebhookconfiguration 和 的 CR 文件的目標地址,然後回調用戶自定義的服務。

api-server 發起的請求是一串json數據格式,header需要設置 content-type 為 application/json , 我們看看請求的 body :

返回的結果:

這里的 patch 是用base64編碼的一個json,我們解碼看看,是一個 json patch:

處理函數:

主程序:

基於私鑰生成一個證書簽名請求(Certificate Signing Request,CSR),目標地址的域名為: mutating-test.testing-tools.svc , csr的配置:

創建命令

基於csr創建 CertificateSigningRequest :

認證完成可以查看:

生成證書:

獲取api-server的CA證書:

將這個證書填入 Webhook 的 caBundle。

MutatingAdmissionWebhook作為kubernetes的ApiServer中Admission Controller的一部分,提供了非常靈活的擴展機制,通過配置MutatingWebhookConfiguration對象,理論上可以監聽並修改任何經過ApiServer處理的請求

MutatingWebhookConfiguration是kubernetes的一個官方的資源提供的對象,下面對該對象的欄位做一些簡單的說明:

結合rules.operations和rules.resources的屬性,我們可以知道樣例中的MutatingWebhookConfiguration監聽了集群中nodes資源的status數據向apiServer提交的更新操作(就是我們前面提到的心跳信息),並且將所有的心跳信息發給了名為webhook-oversale-service的Service下的/mutate介面處理,這個介面就是我們自定義的webhook服務提供的。

上圖中的Pod跑著的容器就是我們自定義的webhook服務,一個自定義webhook服務樣例供參考

在生產環境中,kubernetes集群的計算節點上運行著許許多多的Pod,分別跑著各種業務容器,我們通常用Deployment、DeamonSet、StatefulSet等資源對象去控制Pod的增刪改。因此,開發或運維往往需要配置這些資源對象的Containers欄位中業務容器的CPU和內存的資源配額:requests和limit

requests:節點調度pod需要的資源,每次成功調度則將節點的Allocatable屬性值(可分配資源)重新計算,
新的Allocatable值 = 舊的Allocatable值 - 設置的requests值
limit:節點中運行pod能夠獲得的最大資源,當cpu
我們不難發現,當requests欄位設置太大的時候,pod實際使用的資源卻很小,導致計算節點的Allocatable值很快就被消耗完,節點的資源利用率會變得很低。

上圖中最大的藍色框(allocatable)為計算節點可分配資源,橙色框(requests)為用戶配置的requests屬性,紅色框(current)為業務容器實際使用的資源。因此節點的資源利用率為 current / allocatable。而由於requests設置太大,占滿了allocatable,導致新的pod無法被調度到這個節點,就會出現節點實際資源佔用很低,卻因為allocatable太低導致pod無法調度到該節點的現象。
因此我們能否通過動態調整allocatable的值來讓計算節點的可分配資源變得"虛高",騙過k8s的調度器,讓它以為該節點可分配資源很大,讓盡可能多的pod調度到該節點上呢?

上圖通過將allocatable值擴大(fake allcatable),讓更多的pod調度到了改節點,節點的資源利用率 current / allocatable 就變大了。

實現資源超賣的關鍵在於動態修改節點Node對象的allocatable欄位值,而我們看到allocatable欄位屬於Status欄位,顯然不能直接通過kubectl edit命令來直接修改。因為Status欄位和Spec欄位不同,Spec是用戶設置的期望數據,而Status是實際數據(Node節點通過不斷向apiServer發送心跳來更新自己的實時狀態,最終存在etcd中)。那麼我們要怎麼去修改Stauts欄位呢?
首先,要修改k8s中任何資源對象的Status值,k8s官方提供了一套RESTful API: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13
可以通過patch或者put方法來調用k8s的RESTful API,實現Stauts欄位的修改。(這里是通過ApiServer去修改etcd中保存的Status欄位的值)

但是,Node資源對象比較特殊,計算節點會不斷給ApiServer發送心跳(默認每隔10s發一次),將帶有Status欄位的真實信息發送給ApiServer,並更新到etcd中。也就是無論你怎麼通過patch/put方法去修改Node的Status欄位,計算節點都會定時通過發送心跳將真實的Status數據覆蓋你修改的數據,也就是說我們無法通過直接調用RESTful API修改Node對象中的Status數據。

那我們是否可以直接監聽這個計算節點的心跳數據,通過修改心跳數據中的Status欄位中的allocatable值,從而實現資源超賣呢?

答案是肯定的,k8s在ApiServer中就提供了Admission Controller(准入控制器)的機制,其中包括了MutatingAdmissionWebhook,通過這個webhook,所有和集群中所有和ApiSever交互的請求都被發送到一個指定的介面中,我們只要提供一個這樣的介面,就可以獲取到Node往ApiServer發送心跳的Staus數據了。然後將這個數據進行我們的自定義修改,再往後傳給etcd,就能讓etcd以為我們修改過的Status數據就是節點的真實Status,最終實現資源的超賣。

我們都知道,Istio的流量管理、策略、遙測等功能無須應用程序做任何改動,這種無侵入式的方式全部依賴於Sidecar。應用程序發送或者接收的流量都被Sidecar攔截,並由Sidecar進行認證、鑒權、策略執行及遙測數據上報等眾多治理功能。

如圖所示,在Kubernetes中,Sidecar容器與應用容器共存於同一個Pod中,並且共享同一個Network Namespaces,因此Sidecar容器與應用容器共享同一個網路協議棧,這也是Sidecar能夠通過iptables攔截應用進出口流量的根本原因。

Istio的Sidecar模式

在Istio中進行Sidecar注入有兩種方式:一種是通過istioctl命令行工具手動注入;另一種是通Istio Sidecar Injector自動注入。

這兩種方式的最終目的都是在應用Pod中注入init容器及istio-proxy容器這兩個Sidecar容器。如下所示,通過部署Istio的sleep應用,Sidecar是通過sidecar-injector自動注入的,查看注入的Sidecar容器:

Sidecar Injector是Istio中實現自動注入Sidecar的組件,它是以Kubernetes准入控制器Admission Controller的形式運行的。Admission Controller的基本工作原理是攔截Kube-apiserver的請求,在對象持久化之前、認證鑒權之後進行攔截。Admission Controller有兩種:一種是內置的,另一種是用戶自定義的。Kubernetes允許用戶以Webhook的方式自定義准入控制器,Sidecar Injector就是這樣一種特殊的MutatingAdmissionWebhook。

如圖所示,Sidecar Injector只在創建Pod時進行Sidecar容器注入,在Pod的創建請求到達Kube-apiserver後,首先進行認證鑒權,然後在准入控制階段,Kube-apiserver以REST的方式同步調用Sidecar Injector Webhook服務進行init與istio-proxy容器的注入,最後將Pod對象持久化存儲到etcd中。

Sidecar Injector可以通過MutatingWebhookConfiguration API動態配置生效,Istio中的MutatingWebhook配置如下:

從以上配置可知,Sidecar Injector只對標簽匹配「istio-injection: enabled」的命名空間下的Pod資源對象的創建生效。Webhook服務的訪問路徑為「/inject」,地址及訪問憑證等都在clientConfig欄位下進行配置。

Istio Sidecar Injector組件是由sidecar-injector進程實現的,本書在之後將二者視為同一概念。Sidecar Injector的實現主要由兩部分組成:

MutatingWebhookConfiguration對象的維護主要指監聽本地證書的變化及Kubernetes MutatingWebhookConfiguration資源的變化,以檢查CA證書或者CA數據是否有更新,並且在本地CA證書與MutatingWebhookConfiguration中的CA證書不一致時,自動更新MutatingWebhookConfiguration對象。

2. Kubernetes Operator 快速入門教程(Operator 101)

在 Kubernetes 的監控方案中我們經常會使用到一個Promethues Operator的項目,該項目可以讓我們更加方便的去使用 Prometheus,而不需要直接去使用最原始的一些資源對象,比如 Pod、Deployment,隨著 Prometheus Operator 項目的成功,CoreOS 公司開源了一個比較厲害的工具:Operator Framework,該工具可以讓開發人員更加容易的開發 Operator 應用。

在本篇文章中我們會為大家介紹一個簡單示例來演示如何使用 Operator Framework 框架來開發一個 Operator 應用。

Kubernetes Operator

Operator 是由 CoreOS 開發的,用來擴展 Kubernetes API,特定的應用程序控制器,它用來創建、配置和管理復雜的有狀態應用,如資料庫、緩存和監控系統。Operator 基於 Kubernetes 的資源和控制器概念之上構建,但同時又包含了應用程序特定的領域知識。創建Operator 的關鍵是CRD(自定義資源)的設計。

Kubernetes 1.7 版本以來就引入了自定義控制器的概念,該功能可以讓開發人員擴展添加新功能,更新現有的功能,並且可以自動執行一些管理任務,這些自定義的控制器就像 Kubernetes 原生的組件一樣,Operator 直接使用 Kubernetes API進行開發,也就是說他們可以根據這些控制器內部編寫的自定義規則來監控集群、更改 Pods/Services、對正在運行的應用進行擴縮容。

Operator Framework

Operator Framework 同樣也是 CoreOS 開源的一個用於快速開發 Operator 的工具包,該框架包含兩個主要的部分:

Workflow

Operator SDK 提供以下工作流來開發一個新的 Operator:

Demo

我們平時在部署一個簡單的 Webserver 到 Kubernetes 集群中的時候,都需要先編寫一個 Deployment 的控制器,然後創建一個 Service 對象,通過 Pod 的 label 標簽進行關聯,最後通過 Ingress 或者 type=NodePort 類型的 Service 來暴露服務,每次都需要這樣操作,是不是略顯麻煩,我們就可以創建一個自定義的資源對象,通過我們的 CRD 來描述我們要部署的應用信息,比如鏡像、服務埠、環境變數等等,然後創建我們的自定義類型的資源對象的時候,通過控制器去創建對應的 Deployment 和 Service,是不是就方便很多了,相當於我們用一個資源清單去描述了 Deployment 和 Service 要做的兩件事情。

這里我們將創建一個名為 AppService 的 CRD 資源對象,然後定義如下的資源清單進行應用部署:

通過這里的自定義的 AppService 資源對象去創建副本數為2的 Pod,然後通過 nodePort=30002 的埠去暴露服務,接下來我們就來一步一步的實現我們這里的這個簡單的 Operator 應用。

開發環境

環境需求

要開發 Operator 自然 Kubernetes 集群是少不了的,還需要 Golang 的環境,這里的安裝就不多說了,然後還需要一個 Go 語言的依賴管理工具包:dep,由於 Operator SDK 是使用的 dep 該工具包,所以需要我們提前安裝好,可以查看資料:https://github.com/golang/dep,另外一個需要說明的是,由於 dep 去安裝的時候需要去谷歌的網站拉取很多代碼,所以正常情況下的話是會失敗的,需要做什麼工作大家應該清楚吧?要科學。

安裝 operator-sdk

operator sdk 安裝方法非常多,我們可以直接在 github 上面下載需要使用的版本,然後放置到 PATH 環境下面即可,當然也可以將源碼 clone 到本地手動編譯安裝即可,如果你是 Mac,當然還可以使用常用的 brew 工具進行安裝:

我們這里使用的 sdk 版本是v0.7.0,其他安裝方法可以參考文檔:https://github.com/operator-framework/operator-sdk/blob/master/doc/user/install-operator-sdk.md

演示

創建新項目

環境准備好了,接下來就可以使用 operator-sdk 直接創建一個新的項目了,命令格式為: operator-sdk new

按照上面我們預先定義的 CRD 資源清單,我們這里可以這樣創建:

到這里一個全新的 Operator 項目就新建完成了。

項目結構

使用operator-sdk new命令創建新的 Operator 項目後,項目目錄就包含了很多生成的文件夾和文件。

我們主要需要編寫的是 pkg 目錄下面的 api 定義以及對應的 controller 實現。

添加 API

接下來為我們的自定義資源添加一個新的 API,按照上面我們預定義的資源清單文件,在 Operator 相關根目錄下面執行如下命令:

添加完成後,我們可以看到類似於下面的這樣項目結構:

添加控制器

上面我們添加自定義的 API,接下來可以添加對應的自定義 API 的具體實現 Controller,同樣在項目根目錄下面執行如下命令:

這樣整個 Operator 項目的腳手架就已經搭建完成了,接下來就是具體的實現了。

自定義 API

打開源文件pkg/apis/app/v1/appservice_types.go,需要我們根據我們的需求去自定義結構體 AppServiceSpec,我們最上面預定義的資源清單中就有 size、image、ports 這些屬性,所有我們需要用到的屬性都需要在這個結構體中進行定義:

代碼中會涉及到一些包名的導入,由於包名較多,所以我們會使用一些別名進行區分,主要的包含下面幾個:

這里的 resources、envs、ports 的定義都是直接引用的"k8s.io/api/core/v1"中定義的結構體,而且需要注意的是我們這里使用的是ServicePort,而不是像傳統的 Pod 中定義的 ContanerPort,這是因為我們的資源清單中不僅要描述容器的 Port,還要描述 Service 的 Port。

然後一個比較重要的結構體AppServiceStatus用來描述資源的狀態,當然我們可以根據需要去自定義狀態的描述,我這里就偷懶直接使用 Deployment 的狀態了:

定義完成後,在項目根目錄下面執行如下命令:

改命令是用來根據我們自定義的 API 描述來自動生成一些代碼,目錄pkg/apis/app/v1/下面以zz_generated開頭的文件就是自動生成的代碼,裡面的內容並不需要我們去手動編寫。

實現業務邏輯

NewDeploy 方法實現如下:

newService 對應的方法實現如下:

這樣我們就實現了 AppService 這種資源對象的業務邏輯。

調試

如果我們本地有一個可以訪問的 Kubernetes 集群,我們也可以直接進行調試,在本地用戶~/.kube/config文件中配置集群訪問信息,下面的信息表明可以訪問 Kubernetes 集群:

首先,在集群中安裝 CRD 對象:

上面的命令會在本地運行 Operator 應用,通過~/.kube/config去關聯集群信息,現在我們去添加一個 AppService 類型的資源然後觀察本地 Operator 的變化情況,資源清單文件就是我們上面預定義的(deploy/crds/app_v1_appservice_cr.yaml)

直接創建這個資源對象:

我們可以看到我們的應用創建成功了,這個時候查看 Operator 的調試窗口會有如下的信息出現:

然後我們可以去查看集群中是否有符合我們預期的資源出現:

看到了吧,我們定義了兩個副本(size=2),這里就出現了兩個 Pod,還有一個 NodePort=30002 的 Service 對象,我們可以通過該埠去訪問下應用:

如果應用在安裝過程中出現了任何問題,我們都可以通過本地的 Operator 調試窗口找到有用的信息,然後調試修改即可。

清理:

部署

自定義的資源對象現在測試通過了,但是如果我們將本地的operator-sdk up local命令終止掉,我們可以猜想到就沒辦法處理 AppService 資源對象的一些操作了,所以我們需要將我們的業務邏輯實現部署到集群中去。

執行下面的命令構建 Operator 應用打包成 Docker 鏡像:

鏡像構建成功後,推送到 docker hub:

鏡像推送成功後,使用上面的鏡像地址更新 Operator 的資源清單:

現在 Operator 的資源清單文件准備好了,然後創建對應的 RBAC 的對象:

到這里我們的 CRD 和 Operator 實現都已經安裝成功了。

現在我們再來部署我們的 AppService 資源清單文件,現在的業務邏輯就會在上面的opdemo-64db96d575-9vtq6的 Pod 中去處理了。

然後同樣的可以通過 30002 這個 NodePort 埠去訪問應用,到這里應用就部署成功了。

清理

有資源清單文件,直接刪除即可:

開發

Operator SDK 為我們創建了一個快速啟動的代碼和相關配置,如果我們要開始處理相關的邏輯,我們可以在項目中搜索TODO(user)這個注釋來實現我們自己的邏輯,比如在我的 VSCode 環境中,看上去是這樣的:

本篇文章示例代碼地址:https://github.com/cnych/opdemo

參考資料

閱讀全文

與k8s編譯法相關的資料

熱點內容
程序員做外貿可以嗎 瀏覽:736
華邦單片機在線燒錄 瀏覽:166
如何檢測伺服器是否啟動好 瀏覽:286
巫山耐高溫加密人字形網帶 瀏覽:781
怎麼查看全球伺服器排名 瀏覽:845
pythonmysql預處理 瀏覽:696
艾優學安卓密碼忘了怎麼辦 瀏覽:914
單片機的摘要 瀏覽:699
編譯程序比較復雜所以執行率高嗎 瀏覽:855
中文文件夾怎麼改英文文件夾 瀏覽:811
dune源碼編譯 瀏覽:911
雲班課伺服器在哪 瀏覽:874
微信怎麼設不上加密鎖 瀏覽:188
雲伺服器並發評測 瀏覽:416
100g的文件壓縮 瀏覽:100
怎麼把圖片換成pdf 瀏覽:463
java編程習題集 瀏覽:820
linux查看服務http 瀏覽:546
阿里雲研究生伺服器 瀏覽:98
姐姐們的戀愛在哪個APP看 瀏覽:905