Kubernetes架構原來這么簡單
什么是 Kubernetes

Kubernetes 也稱為 K8s,是用于自動部署、擴縮和管理容器化應用程序的開源系統。Kubernetes 是一個可移植、可擴展的開源平臺,用于管理容器化的工作負載和服務,可促進聲明式配置和自動化。Kubernetes 擁有一個龐大且快速增長的生態,其服務、支持和工具的使用范圍相當廣泛。Kubernetes 這個名字源于希臘語,意為“舵手”或“飛行員”。k8s 這個縮寫是因為 k 和 s 之間有八個字符的關系。Google 在 2014 年開源了 Kubernetes 項目。Kubernetes 建立在 Google 大規模運行生產工作負載十幾年經驗的基礎上, 結合了社區中最優秀的想法和實踐。
時光回溯
我們來了解一下為何 Kubernetes 能夠裨益四方

傳統部署時代:早期,各個組織是在物理服務器上運行應用程序。由于無法限制在物理服務器中運行的應用程序資源使用,因此會導致資源分配問題。例如,如果在同一臺物理服務器上運行多個應用程序, 則可能會出現一個應用程序占用大部分資源的情況,而導致其他應用程序的性能下降。一種解決方案是將每個應用程序都運行在不同的物理服務器上, 但是當某個應用程序資源利用率不高時,剩余資源無法被分配給其他應用程序, 而且維護許多物理服務器的成本很高。
虛擬化部署時代:因此,虛擬化技術被引入了。虛擬化技術允許你在單個物理服務器的 CPU 上運行多臺虛擬機(VM)。虛擬化能使應用程序在不同 VM 之間被彼此隔離,且能提供一定程度的安全性, 因為一個應用程序的信息不能被另一應用程序隨意訪問。虛擬化技術能夠更好地利用物理服務器的資源,并且因為可輕松地添加或更新應用程序, 而因此可以具有更高的可擴縮性,以及降低硬件成本等等的好處。通過虛擬化,你可以將一組物理資源呈現為可丟棄的虛擬機集群。每個 VM 是一臺完整的計算機,在虛擬化硬件之上運行所有組件,包括其自己的操作系統。
容器部署時代:容器類似于 VM,但是更寬松的隔離特性,使容器之間可以共享操作系統(OS)。因此,容器比起 VM 被認為是更輕量級的。且與 VM 類似,每個容器都具有自己的文件系統、CPU、內存、進程空間等。由于它們與基礎架構分離,因此可以跨云和 OS 發行版本進行移植。容器因具有許多優勢而變得流行起來,例如:
- 敏捷應用程序的創建和部署:與使用 VM 鏡像相比,提高了容器鏡像創建的簡便性和效率。
- 持續開發、集成和部署:通過快速簡單的回滾(由于鏡像不可變性), 提供可靠且頻繁的容器鏡像構建和部署。
- 關注開發與運維的分離:在構建、發布時創建應用程序容器鏡像,而不是在部署時, 從而將應用程序與基礎架構分離。
- 可觀察性:不僅可以顯示 OS 級別的信息和指標,還可以顯示應用程序的運行狀況和其他指標信號。
- 跨開發、測試和生產的環境一致性:在筆記本計算機上也可以和在云中運行一樣的應用程序。
- 跨云和操作系統發行版本的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、 Google Kubernetes Engine 和其他任何地方運行。
- 以應用程序為中心的管理:提高抽象級別,從在虛擬硬件上運行 OS 到使用邏輯資源在 OS 上運行應用程序。
- 松散耦合、分布式、彈性、解放的微服務:應用程序被分解成較小的獨立部分, 并且可以動態部署和管理 - 而不是在一臺大型單機上整體運行。
- 資源隔離:可預測的應用程序性能。
- 資源利用:高效率和高密度。
為什么需要 Kubernetes,它能做什么
容器是打包和運行應用程序的好方式。在生產環境中, 你需要管理運行著應用程序的容器,并確保服務不會下線。例如,如果一個容器發生故障,則你需要啟動另一個容器。如果此行為交由給系統處理,是不是會更容易一些?這就是 Kubernetes 要來做的事情!Kubernetes 為你提供了一個可彈性運行分布式系統的框架。Kubernetes 會滿足你的擴展要求、故障轉移你的應用、提供部署模式等。例如,Kubernetes 可以輕松管理系統的 Canary (金絲雀) 部署。Kubernetes 為你提供:
- 服務發現和負載均衡:Kubernetes 可以使用 DNS 名稱或自己的 IP 地址來暴露容器,為多個容器提供一個統一訪問入口(內部IP地址和一個DNS名稱),并且負載均衡關聯的所有容器,使得用戶無需考慮容器IP問題。
- 存儲編排:支持外掛存儲并對外掛存儲資源進行編排,掛載外部存儲系統,無論是來自本地存儲,公有云(如:AWS),還是網絡存儲(如:NFS、Glusterfs、Ceph)都作為集群資源的一部分使用,極大提高存儲使用靈活性。
- 自動部署和回滾:K8S采用滾動策略更新應用,一個更新一個Pod,而不是同時刪除所有的Pod,如果更新過程中出現問題,將回滾更改,確保升級不收影響業務。
- 自動完成資源計算:Kubernetes 提供許多節點組成的集群,在這個集群上運行容器化的任務。你告訴 Kubernetes 每個容器需要多少 CPU 和內存 (RAM)。Kubernetes 可以將這些容器按實際情況調度到你的節點上,以最佳方式利用你的資源。
- 自我修復:在節點故障時重新啟動失敗的容器,替換和重新部署,保證預期的副本數量;殺死健康檢查失敗的容器,并且在未準備好之前不會處理客戶端請求,確保線上服務不中斷。
- 集中化配置管理和密鑰管理:管理機密數據和應用程序配置,而不需要把敏感數據暴露在鏡像里,提高敏感數據安全性,并可以將一些常用的配置存儲在K8S中,方便應用程序使用。
- 任務批量處理運行:提供一次性任務,定時任務,滿足批量數據處理和分析的場景。
Kubernetes 組件
K8S 是屬于主從架構(Master-Slave 架構),即有 Master 節點負責集群的調度、管理和運維,Slave 節點是集群中的運算工作負載節點。主節點一般被稱為 Master 節點,master節點上有 apiserver、controller-manager、scheduler 以及使用 etcd 做k8s集群存儲;而從節點則被稱為 Worker Node 節點,node節點上有 kubelet、kube-proxy、容器引擎(比如docker)。

Master組件
Kube-apiserver
kube-apiserver 是 Kubernetes 最重要的核心組件之一,主要提供以下的功能。
- 提供集群管理的 REST API 接口,包括認證授權、數據校驗以及集群狀態變更等。
- 提供其他模塊之間的數據交互和通信的樞紐(其他模塊通過 API Server 查詢或修改數據,只有 API Server 才直接操作 etcd)。
API Server 負責接收 K8S 所有請求(來自 UI 界面或者 CLI 命令行工具), 然后根據用戶的具體請求,去通知其他組件干活。可以說 API Server 是 K8S 集群架構的大腦,是所有資源對象的操作入口。
Kube-controller-manager
執行并管理各種控制器,是 K8S 集群中處理常規任務的后臺線程,是 K8S 集群里所有資源對象的自動化控制中心。在 K8S 集群中,一個資源對應一個控制器,而 Controller manager 就是負責管理這些控制器的。由一系列控制器組成,通過 API Server 監控整個集群的狀態,并確保集群處于預期的工作狀態,比如當某個 Node 意外宕機時,Controller Manager 會及時發現并執行自動化修復流程,確保集群始終處于預期的工作狀態。這些控制器主要包括:
- Node Controller(節點控制器):負責在節點出現故障時發現和響應。
- Replication Controller(副本控制器):負責保證集群中一個 RC(資源對象 Replication Controller)所關聯的 Pod 副本數始終保持預設值。可以理解成確保集群中有且僅有 N 個 Pod 實例,N 是 RC 中定義的 Pod 副本數量。
- Endpoints Controller(端點控制器):填充端點對象(即連接 Services 和 Pods),負責監聽 Service 和對應的 Pod 副本的變化。可以理解端點是一個服務暴露出來的訪問點,如果需要訪問一個服務,則必須知道它的 endpoint。
- Service Account & Token Controllers(服務帳戶和令牌控制器):為新的命名空間創建默認帳戶和 API 訪問令牌。
- ResourceQuota Controller(資源配額控制器):確保指定的資源對象在任何時候都不會超量占用系統物理資源。
- Namespace Controller(命名空間控制器):管理 namespace 的生命周期。
- Service Controller(服務控制器):屬于 K8S 集群與外部的云平臺之間的一個接口控制器
Kube-scheduler
負責整個集群資源調度,根據調度算法為新創建的 Pod 選擇一個合適的 Node 節點。當用戶要部署服務時,Scheduler 會根據調度算法選擇最合適的 Node 節點來部署 Pod。調度算法:
- 預選策略(predicate)
- 優選策略(priorities)
API Server 接收到請求創建一批 Pod ,API Server 會讓 Controller-manager 按照所預設的模板去創建 Pod,Controller-manager 會通過 API Server 去找 Scheduler 為新創建的 Pod 選擇最適合的 Node 節點。比如運行這個 Pod 需要 2C4G 的資源,Scheduler 會通過預選策略過濾掉不滿足策略的 Node 節點。Node 節點中還剩多少資源是通過匯報給 API Server 存儲在 etcd 里,API Server 會調用一個方法找到 etcd 里所有 Node 節點的剩余資源,再對比 Pod 所需要的資源,如果某個 Node 節點的資源不足或者不滿足 預選策略的條件則無法通過預選。預選階段篩選出的節點,在優選階段會根據優選策略為通過預選的 Node 節點進行打分排名, 選擇得分最高的 Node。例如,資源越富裕、負載越小的 Node 可能具有越高的排名。
Etcd存儲
集群數據庫,保存整個集群的狀態 etcd 作為服務發現系統,有以下的特點:
- 簡單:安裝配置簡單,而且提供了HTTP API進行交互,使用也很簡單
- 安全:支持SSI證書驗證
- 快速:單實例支持每秒2k+讀操作
- 可靠:采用rat算法,實現分布式系統數據的可用性和一致性
etcd 目前默認使用2379端口提供HTTP API服務, 2380端口和peer通信(這兩個端口已經被IANA官方預留給etcd)。即etcd默認使用2379端口對外為客戶端提供通訊,使用端口2380來進行服務器間內部通訊。etcd 在生產環境中一般推薦集群方式部署。由于etcd 的leader選舉機制,要求至少為3臺或以上的奇數臺。
Node 組件
Kubelet
真正運行容器的組件,管理pod的聲明周期,每個 Node 上都會啟動一個 kubelet 服務進程。該進程用于處理 Master 下發到本節點的任務,管理 Pod 及 Pod 中的容器。每個 kubelet 進程都會在 API Server 上注冊節點自身的信息,定期向 Master 匯報節點資源的使用情況,并通過 cAdvisor 監控容器和節點資源。
Kube-Proxy
在 K8S 集群中微服務的負載均衡是由 Kube-proxy 實現的。Kube-proxy 是 K8S 集群內部的負載均衡器。它是一個分布式代理服務器,在 K8S 的每個節點上都會運行一個 Kube-proxy 組件。在每個 Node 節點上實現 Pod 網絡代理,負責維護網絡規則和四層負載均衡工作。負責寫入規則至iptables、ipvs實現服務映射訪問的,轉發請求并管理負載均衡的進程。Kube-apiserver 通過監控 Kube-Proxy 進行對 Kubernetes Service 的更新和端點的維護。
容器運行時(Container Runtime)
真正運行應用的載體 ,當 kubernetes 把 pod 調度到節點上,節點上的 kubelet會指示 docker 啟動特定的容器。接著,kubelet 會通過 docker 持續地收集容器的信息, 然后提交到主節點上。docker 會如往常一樣拉取容器鏡像、啟動或停止容器。不同點僅僅在于這是由自動化系統控制而非管理員在每個節點上手動操作的。Kubernetes 支持許多容器運行環境,例如 containerd、 docker、CRI-O 以及 Kubernetes CRI (容器運行環境接口) 等。
Kubernetes核心對象
Kubernetes 中的所有內容都被抽象為“資源”,如 Pod、Service、Node 等都是資源。“對象”就是“資源”的實例,是持久化的實體。Kubernetes 支持多種不同的方式來創建和管理 Kubernetes 對象,比如:
- 采用kubectl的命令方式
- yaml文件方式
Pod
Pod是 Kubernetes 創建或部署的最小/最簡單的基本單位,一個 Pod 由一個或多個容器組成,Pod 中容器共享網絡、存儲和計算資源。使用 yaml 定義一個簡單的 nginx 服務,它包含一個鏡像為 nginx 的容器:(nginx-pod.yaml):
apiVersion: v1 kind: Pod metadata: name: nginx labels: app: nginx spec:
containers: - name: nginx image: nginx ports: - containerPort: 80使用 Kubectl 工具將這個 Pod 創建到 Kubernetes 集群中:
kubectl apply -f nginx-pod.yamlPod 在 Kubernetes 集群中被創建的基本流程如下所示:

1、用戶提交創建POD請求
2、API Server 處理用戶請求,存儲Pod數據到Etcd
3、Schedule通過和 API Server的監聽機制,查看到新的pod,嘗試為Pod綁定Node
4、過濾主機:調度器用一組規則過濾掉不符合要求的主機,比如Pod指定了所需要的資源,那么就要過濾掉資源不夠的主機
5、主機打分:對第一步篩選出的符合要求的主機進行打分,在此階段,調度器會考慮一些整體優化策略,比如把一個Replication Controller的副本分布到不同的主機上,使用最低負載的主機等
6、選擇主機:選擇得分最高的主機,進行binding操作,結果存儲到Etcd中
7、kubelet根據調度結果執行Pod創建操作:綁定成功后,會啟動container, Docker run, scheduler會調用API Server的API在etcd中創建一個bound pod對象,描述在一個工作節點上綁定運行的所有pod信息。運行在每個工作節點上的kubelet也會定期與etcd同步bound pod信息,一旦發現應該在該工作節點上運行的bound pod對象沒有更新,則調用Docker API創建并啟動pod內的容器
8、POD創建完成
Namespace
Namespace(命名空間)是對一組資源和對象的抽象集合,比如可以用來將系統內部的對象劃分為不同的項目組或用戶組。常見的 Pods、Services、Deployments 等都是屬于某一個 Namespace 的(默認是 default),比如上面我們的 Nginx Pod 沒有指定 namespace,則默認就在 default 命名空間下面,而 Node, PersistentVolumes 等資源則不屬于任何 Namespace,是全局的。
Label
給某個資源對象定義一個 Label,就相當于給它打了一個標簽;隨后可以通過標簽選擇器(Label selector)查詢和篩選擁有某些 Label 的資源對象。
Deployment
Deployment 是來管理 Pod 的資源對象。Deployment 確保任意時間都有指定數量的 Pod“副本”在運行。如果為某個 Pod 創建了 Deployment 并且指定 3 個副本,它會創建 3 個 Pod,并且持續監控它們。如果某個 Pod 不響應,那么 Deployment 會替換它,始終保持總數為 3。如果之前不響應的 Pod 恢復了,現在就有 4 個 Pod 了,那么 Deployment 會將其中一個終止保持總數為 3。如果在運行中將副本總數改為 5,Deployment 會立刻啟動 2 個新 Pod,保證總數為 5。持回滾和滾動升級。當創建 Deployment 時,需要指定兩個東西:
- Pod 模板:用來創建 Pod 副本的模板
- Label 標簽:Deployment 需要監控的 Pod 的標簽。
Service
在K8S的集群里,雖然每個Pod會被分配一個單獨的IP地址,但由于Pod是有生命周期的(它們可以被創建,而且銷毀之后不會再啟動),隨時可能會因為業務的變更,導致這個 IP 地址也會隨著 Pod 的銷毀而消失。而Service 就是用來解決這個問題的核心概念。Service 是應用服務的抽象,通過 Labels 為應用提供負載均衡和服務發現。匹配 Labels 的 Pod IP 和端口列表組成 Endpoints,由 kube-proxy 負責將服務 IP 負載均衡到這些 Endpoints 上。每個 Service 都會自動分配一個 cluster IP(僅在集群內部可訪問的虛擬地址)和 DNS 名,其他容器可以通過該地址或 DNS 來訪問服務,而不需要了解后端容器的運行。
K8S各組件工作流程

1、運維人員向kube-apiserver發出指令(我想干什么,我期望事情是什么狀態)
2、api響應命令,通過一系列認證授權,把pod數據存儲到etcd,創建deployment資源并初始化。(期望狀態)
3、controller通過list-watch機制,監測發現新的deployment,將該資源加入到內部工作隊列,發現該資源沒有關聯的pod和replicaset,啟用deployment controller創建replicaset資源,再啟用replicaset controller創建pod。
4、所有controller被創建完成后.將deployment,replicaset,pod資源更新存儲到etcd。
5、scheduler通過list-watch機制,監測發現新的pod,經過主機過濾、主機打分規則,將pod綁定(binding)到合適的主機。6、將綁定結果存儲到etcd。
7、kubelet每隔 20s(可以自定義)向apiserver通過NodeName 獲取自身Node上所要運行的pod清單.通過與自己的內部緩存進行比較,新增加pod。
8、kubelet創建pod。
9、kube-proxy為新創建的pod注冊動態DNS到CoreOS。給pod的service添加iptables/ipvs規則,用于服務發現和負載均衡。
10、controller通過control loop(控制循環)將當前pod狀態與用戶所期望的狀態做對比,如果當前狀態與用戶期望狀態不同,則controller會將pod修改為用戶期望狀態,實在不行會將此pod刪掉,然后重新創建pod。
























