深入剖析Kubernetes學習筆記:深入理解鏡像(09)


容器就從一個開發者手里的小工具,一躍成為了雲計算領域的絕對主角;而能夠定義容器組織和管理規范的“容器編排”技術,則當仁不讓地坐上了容器技術領域的“頭把交椅”。

一、首先,Kubernetes 項目要解決的問題是什么?

1、全局架構

我們可以看到,Kubernetes 項目的架構,跟它的原型項目 Borg 非常類似,都由 Master 和 Node 兩種節點組成,而這兩種角色分別對應着控制節點和計算節點。

其中,控制節點,即 Master 節點,由三個緊密協作的獨立組件組合而成,
它們分別是負責 API 服務的 kube-apiserver、負責調度的 kube-scheduler,以及負責容器編排的 kube-controller-manager。
整個集群的持久化數據,則由 kube-apiserver 處理后保存在 Etcd 中。

而計算節點上最核心的部分,則是一個叫作 kubelet 的組件。

2、kubelet 的組件

1、在 Kubernetes 項目中,kubelet 主要負責同容器運行時(比如 Docker 項目)打交道。

而這個交互所依賴的,是一個稱作 CRI(Container Runtime Interface)的遠程調用接口,
這個接口定義了容器運行時的各項核心操作,比如:啟動一個容器需要的所有參數。

這也是為何,Kubernetes項目並不關心你部署的是什么容器運行時、使用的什么技術實現,只要你的這個容器運行時能夠運行標准的容器鏡像,
它就可以通過實現 CRI 接入到 Kubernetes 項目當中。

2、kubelet 還通過 gRPC 協議同一個叫作 Device Plugin 的插件進行交互

而具體的容器運行時,比如 Docker 項目,則一般通過 OCI 這個容器運行時規范同底層的 Linux 操作系統進行交互,
即:把 CRI 請求翻譯成對 Linux 操作系統的調用(操作 Linux Namespace 和 Cgroups 等)。

此外,kubelet 還通過 gRPC 協議同一個叫作 Device Plugin 的插件進行交互。這個插件,是 Kubernetes 項目用來管理 GPU 等宿主機物理設備的主要組件,也是基於 Kubernetes 項目進行機器學習訓練、高性能作業支持等工作必須關注的功能。

3、kubelet 的另一個重要功能,則是調用網絡插件和存儲插件為容器配置網絡和持久化存儲

這兩個插件與 kubelet 進行交互的接口,分別是 CNI(Container Networking Interface)和 CSI(Container Storage Interface)。

實際上,kubelet 這個奇怪的名字,來自於 Borg 項目里的同源組件 Borglet。不過,如果你瀏覽過 Borg 論文的話,
就會發現,這個命名方式可能是 kubelet 組件與 Borglet 組件的唯一相似之處。
因為 Borg 項目,並不支持我們這里所講的容器技術,而只是簡單地使用了 Linux Cgroups 對進程進行限制。

這就意味着,像 Docker 這樣的“容器鏡像”在 Borg 中是不存在的,Borglet 組件也自然不需要像 kubelet 這樣考慮如何同 Docker 進行交互、如何對容器鏡像進行管理的問題,也不需要支持 CRI、CNI、CSI 等諸多容器技術接口。

可以說,kubelet 完全就是為了實現 Kubernetes 項目對容器的管理能力而重新實現的一個組件,與 Borg 之間並沒有直接的傳承關系。

二、那么,Borg 對於 Kubernetes 項目的指導作用又體現在哪里呢?

答案是,Master 節點。

雖然在 Master 節點的實現細節上 Borg 項目與 Kubernetes 項目不盡相同,但它們的出發點卻高度一致,即:如何編排、管理、調度用戶提交的作業?

所以,Borg 項目完全可以把 Docker 鏡像看做是一種新的應用打包方式。這樣,Borg 團隊過去在大規模作業管理與編排上的經驗就可以直接“套”在 Kubernetes 項目上了。

這些經驗最主要的表現就是,從一開始,

1、Kubernetes 項目就沒有像同時期的各種“容器雲”項目那樣,把 Docker 作為整個架構的核心,而僅僅把它作為最底層的一個容器運行時實現。

所以,Kubernetes 項目最主要的設計思想是,從更宏觀的角度,以統一的方式來定義任務之間的各種關系,並且為將來支持更多種類的關系留有余地。

Kubernetes 項目的做法是給 Pod 綁定一個 Service 服務,而 Service 服務聲明的 IP 地址等信息是“終生不變”的。這個Service 服務的主要作用,就是作為 Pod 的代理入口(Portal),從而代替 Pod 對外暴露一個固定的網絡地址。

這樣,對於 Web 應用的 Pod 來說,它需要關心的就是數據庫 Pod 的 Service 信息。不難想象,Service 后端真正代理的 Pod 的 IP 地址、端口等信息的自動更新、維護,則是 Kubernetes 項目的職責。

像這樣,圍繞着容器和 Pod 不斷向真實的技術場景擴展,我們就能夠摸索出一幅如下所示的 Kubernetes 項目核心功能的“全景圖”。

2、Kubernetes 項目核心功能的“全景圖”。

 

 

 


1、按照這幅圖的線索,我們從容器這個最基礎的概念出發,首先遇到了容器間“緊密協作”關系的難題,

於是就擴展到了 Pod;有了 Pod 之后,

2、我們希望能一次啟動多個應用的實例,

這樣就需要 Deployment 這個 Pod 的多實例管理器;

3、而有了這樣一組相同的 Pod 后,我們又需要通過一個固定的 IP 地址和端口以負載均衡的方式訪問它,

於是就有了 Service。

4、可是,如果現在兩個不同 Pod 之間不僅有“訪問關系”,還要求在發起時加上授權信息。最典型的例子就是 Web 應用對數據庫訪問時需要 Credential(數據庫的用戶名和密碼)信息。那么,在 Kubernetes 中這樣的關系又如何處理呢?

Kubernetes 項目提供了一種叫作 Secret 的對象,它其實是一個保存在 Etcd 里的鍵值對數據。這樣,你把 Credential 信息以 Secret 的方式存在 Etcd 里,Kubernetes 就會在你指定的 Pod(比如,Web 應用的 Pod)啟動時,

自動把 Secret 里的數據以 Volume 的方式掛載到容器里。這樣,這個 Web 應用就可以訪問數據庫了。

3、應用運行的形態是影響“如何容器化這個應用”的第二個重要因素。

為此,Kubernetes 定義了新的、基於 Pod 改進后的對象。比如 Job,用來描述一次性運行的 Pod(比如,大數據任務);再比如 DaemonSet,用來描述每個宿主機上必須且只能運行一個副本的守護進程服務;又比如 CronJob,則用於描述定時任務等等。

如此種種,正是 Kubernetes 項目定義容器間關系和形態的主要方法。

可以看到,Kubernetes 項目並沒有像其他項目那樣,為每一個管理功能創建一個指令,然后在項目中實現其中的邏輯。這種做法,的確可以解決當前的問題,但是在更多的問題來臨之后,往往會力不從心。

相比之下,在 Kubernetes 項目中,我們所推崇的使用方法是:

1、首先,通過一個“編排對象”,比如 Pod、Job、CronJob 等,來描述你試圖管理的應用;
2、然后,再為它定義一些“服務對象”,比如 Service、Secret、Horizontal Pod Autoscaler(自動水平擴展器)等。這些對象,會負責具體的平台級功能。

這種使用方法,就是所謂的“聲明式 API”。這種 API 對應的“編排對象”和“服務對象”,都是 Kubernetes 項目中的 API 對象(API Object)。這就是 Kubernetes 最核心的設計理念,也是接下來我會重點剖析的關鍵技術點。

三、最后,Kubernetes 項目如何啟動一個容器化任務呢?

比如,我現在已經制作好了一個 Nginx 容器鏡像,希望讓平台幫我啟動這個鏡像。並且,我要求平台幫我運行兩個完全相同的 Nginx 副本,以負載均衡的方式共同對外提供服務。

如果是自己 DIY 的話,可能需要啟動兩台虛擬機,分別安裝兩個 Nginx,然后使用 keepalived 為這兩個虛擬機做一個虛擬 IP。

而如果使用 Kubernetes 項目呢?你需要做的則是編寫如下這樣一個 YAML 文件(比如名叫 nginx-deployment.yaml):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

在上面這個 YAML 文件中,我們定義了一個 Deployment 對象,它的主體部分(spec.template 部分)是一個使用 Nginx 鏡像的 Pod,而這個 Pod 的副本數是 2(replicas=2)。

然后執行:

$ kubectl create -f nginx-deployment.yaml

這樣,兩個完全相同的 Nginx 容器副本就被啟動了。

不過,這么看來,做同樣一件事情,Kubernetes 用戶要做的工作也不少嘛。

別急,在后續的講解中,我會陸續介紹 Kubernetes 項目這種“聲明式 API”的種種好處,以及基於它實現的強大的編排能力。

拭目以待吧。

四、經典留言

從微服務架構來講,多個獨立功能內聚的服務帶來了整體的靈活性,但是同時也帶來了部署運維的復雜度提升,
這時Docker配合Devops帶來了不少的便利(輕量、隔離、一致性、CI、CD等)解決了不少問題,再配合compose,看起來一切都很美了,

為什么還需要K8s?可以試着這樣理解么?

1、把微服務理解為人

那么服務治理其實就是人之間的溝通而已,人太多了就需要生存空間和溝通方式的優化,
這就需要集群和編排了。Docker Compose,swarm,可以解決少數人之間的關系,比如把手機號給你,你就可以方便的找到我,但是如果手機號變更的時候就會麻煩,人多了也會麻煩。

2、而k8s是站在上帝視角俯視芸芸眾生后的高度抽象

他看到了大概有哪些類人(組織)以及不同組織有什么樣的特點(Job、CornJob、Autoscaler、StatefulSet、DaemonSet...),
不同組織之間交流可能需要什么(ConfigMap,Secret...),這樣比價緊密的人們在相同pod中,通過Service-不會變更的手機號,來和不同的組織進行溝通,
Deployment、RC則可以幫組人們快速構建組織。Dokcer 后出的swarm mode,有類似的視角抽象(比如Service),不過相對來說並不完善。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM