亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

發布時間:2020-10-04 20:00:28 來源:網絡 閱讀:144 作者:阿里系統軟件技術 欄目:云計算

作者 | 聲東? 阿里云售后技術專家

導讀:不知道大家有沒有意識到一個現實:大部分時候,我們已經不像以前一樣,通過命令行,或者可視窗口來使用一個系統了。

前言

現在我們上微博、或者網購,操作的其實不是眼前這臺設備,而是一個又一個集群。通常,這樣的集群擁有成百上千個節點,每個節點是一臺物理機或虛擬機。集群一般遠離用戶,坐落在數據中心。為了讓這些節點互相協作,對外提供一致且高效的服務,集群需要操作系統。Kubernetes 就是這樣的操作系統。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

比較 Kubernetes 和單機操作系統,Kubernetes 相當于內核,它負責集群軟硬件資源管理,并對外提供統一的入口,用戶可以通過這個入口來使用集群,和集群溝通。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

而運行在集群之上的程序,與普通程序有很大的不同。這樣的程序,是“關在籠子里”的程序。它們從被制作,到被部署,再到被使用,都不尋常。我們只有深挖根源,才能理解其本質。

“關在籠子里”的程序

代碼

我們使用 go 語言寫了一個簡單的 web 服務器程序 app.go,這個程序監聽在 2580 這個端口。通過 http 協議訪問這個服務的根路徑,服務會返回 "This is a small app for kubernetes..." 字符串。

package main
import (
        "github.com/gorilla/mux"
        "log"
        "net/http"
)
func about(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("This is a small app for kubernetes...\n"))
}
func main() {
        r := mux.NewRouter()
        r.HandleFunc("/", about)
        log.Fatal(http.ListenAndServe("0.0.0.0:2580", r))
}

使用 go build 命令編譯這個程序,產生 app 可執行文件。這是一個普通的可執行文件,它在操作系統里運行,會依賴系統里的庫文件。

# ldd app
linux-vdso.so.1 => (0x00007ffd1f7a3000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f554fd4a000)
libc.so.6 => /lib64/libc.so.6 (0x00007f554f97d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f554ff66000)

“籠子”

為了讓這個程序不依賴于操作系統自身的庫文件,我們需要制作容器鏡像,即隔離的運行環境。Dockerfile 是制作容器鏡像的“菜譜”。我們的菜譜就只有兩個步驟,下載一個 centos 的基礎鏡像,把 app 這個可執行文件放到鏡像中 /usr/local/bin 目錄中去。

FROM centos
ADD app /usr/local/bin

地址

制作好的鏡像存再本地,我們需要把這個鏡像上傳到鏡像倉庫里去。這里的鏡像倉庫,相當于應用商店。我們使用阿里云的鏡像倉庫,上傳之后鏡像地址是:

registry.cn-hangzhou.aliyuncs.com/kube-easy/app:latest

鏡像地址可以拆分成四個部分:倉庫地址/命名空間/鏡像名稱:鏡像版本。顯然,鏡像上邊的鏡像,在阿里云杭州鏡像倉庫,使用的命名空間是 kube-easy,鏡像名:版本是 app:latest。至此,我們有了一個可以在 Kubernetes 集群上運行的、“關在籠子里”的小程序。

得其門而入

入口

Kubernetes 作為操作系統,和普通的操作系統一樣,有 API 的概念。有了 API,集群就有了入口;有了 API,我們使用集群,才能得其門而入。Kubernetes 的 API 被實現為運行在集群節點上的組件 API Server。這個組件是典型的 web 服務器程序,通過對外暴露 http(s) 接口來提供服務。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

這里我們創建一個阿里云 Kubernetes 集群。登錄集群管理頁面,我們可以看到 API Server 的公網入口。

API Server 內網連接端點: https://xx.xxx.xxx.xxx:6443

雙向數字證書驗證

阿里云 Kubernetes 集群 API Server 組件,使用基于 CA 簽名的雙向數字證書認證來保證客戶端與 api server 之間的安全通信。這句話很繞口,對于初學者不太好理解,我們來深入解釋一下。

從概念上來講,數字證書是用來驗證網絡通信參與者的一個文件。這和學校頒發給學生的畢業證書類似。在學校和學生之間,學校是可信第三方 CA,而學生是通信參與者。如果社會普遍信任一個學校的聲譽的話,那么這個學校頒發的畢業證書,也會得到社會認可。參與者證書和 CA 證書可以類比畢業證和學校的辦學許可證。

這里我們有兩類參與者,CA 和普通參與者;與此對應,我們有兩種證書,CA 證書和參與者證書;另外我們還有兩種關系,證書簽發關系以及信任關系。這兩種關系至關重要。

我們先看簽發關系。如下圖,我們有兩張 CA 證書,三個參與者證書。

其中最上邊的 CA 證書,簽發了兩張證書,一張是中間的 CA 證書,另一張是右邊的參與者證書;中間的 CA 證書,簽發了下邊兩張參與者證書。這六張證書以簽發關系為聯系,形成了樹狀的證書簽發關系圖。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

然而,證書以及簽發關系本身,并不能保證可信的通信可以在參與者之間進行。以上圖為例,假設最右邊的參與者是一個網站,最左邊的參與者是一個瀏覽器,瀏覽器相信網站的數據,不是因為網站有證書,也不是因為網站的證書是 CA 簽發的,而是因為瀏覽器相信最上邊的 CA,也就是信任關系。

理解了 CA(證書),參與者(證書),簽發關系,以及信任關系之后,我們回過頭來看“基于 CA 簽名的雙向數字證書認證”。客戶端和 API Server 作為通信的普通參與者,各有一張證書。而這兩張證書,都是由 CA 簽發,我們簡單稱它們為集群 CA 和客戶端 CA。客戶端信任集群 CA,所以它信任擁有集群 CA 簽發證書的 API Server;反過來 API Server 需要信任客戶端 CA,它才愿意與客戶端通信。

阿里云 Kubernetes 集群,集群 CA 證書,和客戶端 CA 證書,實現上其實是一張證書,所以我們有這樣的關系圖。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

KubeConfig 文件

登錄集群管理控制臺,我們可以拿到 KubeConfig 文件。這個文件包括了客戶端證書,集群 CA 證書,以及其他。證書使用 base64 編碼,所以我們可以使用 base64 工具解碼證書,并使用 openssl 查看證書文本。

  • 首先,客戶端證書的簽發者 CN 是集群 id c0256a3b8e4b948bb9c21e66b0e1d9a72,而證書本身的 CN 是子賬號 252771643302762862;
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 787224 (0xc0318)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: O=c0256a3b8e4b948bb9c21e66b0e1d9a72, OU=default, CN=c0256a3b8e4b948bb9c21e66b0e1d9a72
        Validity
            Not Before: Nov 29 06:03:00 2018 GMT
            Not After : Nov 28 06:08:39 2021 GMT
        Subject: O=system:users, OU=, CN=252771643302762862
  • 其次,只有在 API Server 信任客戶端 CA 證書的情況下,上邊的客戶端證書才能通過 API Server 的驗證。kube-apiserver 進程通過 client-ca-file 這個參數指定其信任的客戶端 CA 證書,其指定的證書是 /etc/kubernetes/pki/apiserver-ca.crt。這個文件實際上包含了兩張客戶端 CA 證書,其中一張和集群管控有關系,這里不做解釋,另外一張如下,它的 CN 與客戶端證書的簽發者 CN 一致;
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 787224 (0xc0318)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: O=c0256a3b8e4b948bb9c21e66b0e1d9a72, OU=default, CN=c0256a3b8e4b948bb9c21e66b0e1d9a72
        Validity
            Not Before: Nov 29 06:03:00 2018 GMT
            Not After : Nov 28 06:08:39 2021 GMT
        Subject: O=system:users, OU=, CN=252771643302762862
  • 再次,API Server 使用的證書,由 kube-apiserver 的參數 tls-cert-file 決定,這個參數指向證書 /etc/kubernetes/pki/apiserver.crt。這個證書的 CN 是 kube-apiserver,簽發者是 c0256a3b8e4b948bb9c21e66b0e1d9a72,即集群 CA 證書;
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 2184578451551960857 (0x1e512e86fcba3f19)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: O=c0256a3b8e4b948bb9c21e66b0e1d9a72, OU=default, CN=c0256a3b8e4b948bb9c21e66b0e1d9a72
        Validity
            Not Before: Nov 29 03:59:00 2018 GMT
            Not After : Nov 29 04:14:23 2019 GMT
        Subject: CN=kube-apiserver
  • 最后,客戶端需要驗證上邊這張 API Server 的證書,因而 KubeConfig 文件里包含了其簽發者,即集群 CA 證書。對比集群 CA 證書和客戶端 CA 證書,發現兩張證書完全一樣,這符合我們的預期。
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 786974 (0xc021e)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=CN, ST=ZheJiang, L=HangZhou, O=Alibaba, OU=ACS, CN=root
        Validity
            Not Before: Nov 29 03:59:00 2018 GMT
            Not After : Nov 24 04:04:00 2038 GMT
        Subject: O=c0256a3b8e4b948bb9c21e66b0e1d9a72, OU=default, CN=c0256a3b8e4b948bb9c21e66b0e1d9a72

訪問

理解了原理之后,我們可以做一個簡單的測試:以證書作為參數,使用 curl 訪問 api server,并得到預期結果。

# curl --cert ./client.crt --cacert ./ca.crt --key ./client.key https://xx.xx.xx.xxx:6443/api/
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "192.168.0.222:6443"
    }
  ]
}

擇優而居

兩種節點,一種任務

如開始所講,Kubernetes 是管理集群多個節點的操作系統。這些節點在集群中的角色,卻不必完全一樣。Kubernetes 集群有兩種節點:master 節點和 worker 節點。

這種角色的區分,實際上就是一種分工:master 負責整個集群的管理,其上運行的以集群管理組件為主,這些組件包括實現集群入口的 api server;而 worker 節點主要負責承載普通任務。

在 Kubernetes 集群中,任務被定義為 pod 這個概念。pod 是集群可承載任務的原子單元,pod 被翻譯成容器組,其實是意譯,因為一個 pod 實際上封裝了多個容器化的應用。原則上來講,被封裝在一個 pod 里邊的容器,應該是存在相當程度的耦合關系。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

擇優而居

調度算法需要解決的問題,是替 pod 選擇一個舒適的“居所”,讓 pod 所定義的任務可以在這個節點上順利地完成。

為了實現“擇優而居”的目標,Kubernetes 集群調度算法采用了兩步走的策略:

  • 第一步,從所有節點中排除不滿足條件的節點,即預選;
  • 第二步,給剩余的節點打分,最后得分高者勝出,即優選。

下面我們使用文章開始的時候制作的鏡像,創建一個 pod,并通過日志來具體分析一下,這個 pod 怎么樣被調度到某一個集群節點。

Pod 配置

首先,我們創建 pod 的配置文件,配置文件格式是 json。這個配置文件有三個地方比較關鍵,分別是鏡像地址,命令以及容器的端口。

{
    "apiVersion": "v1",
    "kind": "Pod",
    "metadata": {
        "name": "app"
    },
    "spec": {
        "containers": [
            {
                "name": "app",
                "image": "registry.cn-hangzhou.aliyuncs.com/kube-easy/app:latest",
                "command": [
                    "app"
                ],
                "ports": [
                    {
                        "containerPort": 2580
                    }
                ]
            }
        ]
    }
}

日志級別

集群調度算法被實現為運行在 master 節點上的系統組件,這一點和 api server 類似。其對應的進程名是 kube-scheduler。kube-scheduler 支持多個級別的日志輸出,但社區并沒有提供詳細的日志級別說明文檔。查看調度算法對節點進行篩選、打分的過程,我們需要把日志級別提高到 10,即加入參數 --v=10。

kube-scheduler --address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=true --v=10

創建 Pod

使用 curl,以證書和 pod 配置文件等作為參數,通過 POST 請求訪問 api server 的接口,我們可以在集群里創建對應的 pod。

# curl -X POST -H 'Content-Type: application/json;charset=utf-8' --cert ./client.crt --cacert ./ca.crt --key ./client.key https://47.110.197.238:6443/api/v1/namespaces/default/pods -d@app.json

預選

預選是 Kubernetes 調度的第一步,這一步要做的事情,是根據預先定義的規則,把不符合條件的節點過濾掉。不同版本的 Kubernetes 所實現的預選規則有很大的不同,但基本的趨勢,是預選規則會越來越豐富。

比較常見的兩個預選規則是 PodFitsResourcesPred 和 PodFitsHostPortsPred。前一個規則用來判斷,一個節點上的剩余資源,是不是能夠滿足 pod 的需求;而后一個規則,檢查一個節點上某一個端口是不是已經被其他 pod 所使用了。

下圖是調度算法在處理測試 pod 的時候,輸出的預選規則的日志。這段日志記錄了預選規則 CheckVolumeBindingPred?的執行情況。某些類型的存儲卷(PV),只能掛載到一個節點上,這個規則可以過濾掉不滿足 pod 對 PV 需求的節點。

從 app 的編排文件里可以看到,pod 對存儲卷并沒有什么需求,所以這個條件并沒有過濾掉節點。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

優選

調度算法的第二個階段是優選階段。這個階段,kube-scheduler 會根據節點可用資源及其他一些規則,給剩余節點打分。

目前,CPU 和內存是調度算法考量的兩種主要資源,但考量的方式并不是簡單的,剩余 CPU、內存資源越多,得分就越高。

日志記錄了兩種計算方式:LeastResourceAllocation 和 BalancedResourceAllocation。

  • 前一種方式計算 pod 調度到節點之后,節點剩余 CPU 和內存占總 CPU 和內存的比例,比例越高得分就越高;
  • 第二種方式計算節點上 CPU 和內存使用比例之差的絕對值,絕對值越大,得分越少。

這兩種方式,一種傾向于選出資源使用率較低的節點,第二種希望選出兩種資源使用比例接近的節點。這兩種方式有一些矛盾,最終依靠一定的權重來平衡這兩個因素。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

除了資源之外,優選算法會考慮其他一些因素,比如 pod 與節點的親和性,或者如果一個服務有多個相同 pod 組成的情況下,多個 pod 在不同節點上的分散程度,這是保證高可用的一種策略。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

得分

最后,調度算法會給所有的得分項乘以它們的權重,然后求和得到每個節點最終的得分。因為測試集群使用的是默認調度算法,而默認調度算法把日志中出現的得分項所對應的權重,都設置成了 1,所以如果按日志里有記錄得分項來計算,最終三個節點的得分應該是 29,28 和 29。

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

之所以會出現日志輸出的得分和我們自己計算的得分不符的情況,是因為日志并沒有輸出所有的得分項,猜測漏掉的策略應該是 NodePreferAvoidPodsPriority,這個策略的權重是 10000,每個節點得分 10,所以才得出最終日志輸出的結果。

結束語

在本文中,我們以一個簡單的容器化 web 程序為例,著重分析了客戶端怎么樣通過 Kubernetes 集群 API Server 認證,以及容器應用怎么樣被分派到合適節點這兩件事情。

在分析過程中,我們棄用了一些便利的工具,比如 kubectl,或者控制臺。我們用了一些更接近底層的小實驗,比如拆解 KubeConfig 文件,再比如分析調度器日志來分析認證和調度算法的運作原理。希望這些對大家進一步理解 Kubernetes 集群有所幫助。

架構師成長系列直播

從認證到調度,K8s 集群上運行的小程序到底經歷了什么?

“阿里巴巴云原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦云原生流行技術趨勢、云原生大規模的落地實踐,做最懂云原生開發者的技術圈。”

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

浦北县| 清丰县| 开原市| 芦山县| 凯里市| 福泉市| 南平市| 邮箱| 绥宁县| 台安县| 棋牌| 东辽县| 泸水县| 广宗县| 遂川县| 双牌县| 南丹县| 汉阴县| 城固县| 洮南市| 勐海县| 孟村| 区。| 呼伦贝尔市| 佛坪县| 稻城县| 盐亭县| 恩施市| 鹤山市| 云和县| 深泽县| 马关县| 汝城县| 互助| 桐庐县| 铁岭县| 无极县| 封丘县| 临夏县| 德兴市| 武功县|