之前寫(xiě)過(guò)一篇 k8s(kubernetes)簡(jiǎn)介 同名的文章,但是剛開(kāi)始不會(huì)使用簡(jiǎn)書(shū)的編輯器,現(xiàn)在重新研究了一下,把之前的文章更新了一下。
k8s(kubernetes)簡(jiǎn)介
kubernetes能做什么
傳統(tǒng)部署時(shí)代:
早期,各個(gè)組織機(jī)構(gòu)在物理服務(wù)器上運(yùn)行應(yīng)用程序。無(wú)法為物理服務(wù)器中的應(yīng)用程序定義資源邊界,這會(huì)導(dǎo)致資源分配問(wèn)題。 例如,如果在物理服務(wù)器上運(yùn)行多個(gè)應(yīng)用程序,則可能會(huì)出現(xiàn)一個(gè)應(yīng)用程序占用大部分資源的情況,結(jié)果可能導(dǎo)致其他應(yīng)用程序的性能下降。 一種解決方案是在不同的物理服務(wù)器上運(yùn)行每個(gè)應(yīng)用程序,但是這樣會(huì)造成資源利用不足,而且不易擴(kuò)展, 同時(shí)物理服務(wù)器的運(yùn)維成本很高。
虛擬化部署時(shí)代:
作為解決方案,引入了虛擬化。虛擬化技術(shù)允許你在單個(gè)物理服務(wù)器的 CPU 上運(yùn)行多個(gè)虛擬機(jī)(VM)。 虛擬化允許應(yīng)用程序在 VM 之間隔離,并提供一定程度的安全,因?yàn)橐粋€(gè)應(yīng)用程序的信息不能被另一應(yīng)用程序隨意訪(fǎng)問(wèn)。
虛擬化技術(shù)能夠更好地利用物理服務(wù)器上的資源,并且因?yàn)榭奢p松地添加或更新應(yīng)用程序而可以實(shí)現(xiàn)更好的可伸縮性,降低硬件成本。
每個(gè) VM 是一臺(tái)完整的計(jì)算機(jī),在虛擬化硬件之上運(yùn)行所有組件,包括其自己的操作系統(tǒng)。所以,VM本身會(huì)占用大量的硬件資源。
容器部署時(shí)代:
容器類(lèi)似于 VM,但是它們具有被放寬的隔離屬性,可以在應(yīng)用程序之間共享操作系統(tǒng)(OS)。 因此,容器技術(shù)更加輕量級(jí)。容器與 VM 類(lèi)似,具有自己的文件系統(tǒng)、CPU、內(nèi)存、進(jìn)程空間等。 由于它們與基礎(chǔ)架構(gòu)分離,因此可以跨云和跨系統(tǒng)發(fā)行版本進(jìn)行移植。相比于VM,容器本身所需要的硬件資源小得多。
kubernetes部署時(shí)代:
容器是打包和運(yùn)行應(yīng)用程序的很好方式。在生產(chǎn)環(huán)境中,你只需要管理運(yùn)行應(yīng)用程序的容器,并確保不會(huì)停機(jī)。 例如,如果一個(gè)容器發(fā)生故障,則需要啟動(dòng)另一個(gè)容器。如果把容器的啟停交給軟件處理,會(huì)不會(huì)更容易?這就是 kubernetes 解決的問(wèn)題!
kubernetes 提供以下功能:
-
服務(wù)發(fā)現(xiàn)和負(fù)載均衡
kubernetes 可以使用 DNS 名稱(chēng)或自己的 IP 地址公開(kāi)容器,如果進(jìn)入容器的流量很大, kubernetes 可以負(fù)載均衡并分配網(wǎng)絡(luò)流量。
-
存儲(chǔ)編排
kubernetes 允許你自動(dòng)掛載你選擇的存儲(chǔ)系統(tǒng),例如本地存儲(chǔ)、網(wǎng)絡(luò)存儲(chǔ)。
-
自動(dòng)部署和回滾
你可以使用 kubernetes 描述已部署容器的所需狀態(tài),它可以以受控的速率將實(shí)際狀態(tài)更改為期望狀態(tài)。例如,你可以自動(dòng)化 kubernetes 來(lái)為你的部署創(chuàng)建新容器, 刪除現(xiàn)有容器并將它們的所有資源用于新容器。
-
自動(dòng)完成資源配置
kubernetes 允許你指定每個(gè)容器所需 CPU 和內(nèi)存(RAM)。 當(dāng)容器指定了資源請(qǐng)求時(shí),kubernetes 可以做出更好的決策來(lái)管理容器的資源。
-
自我修復(fù)
kubernetes 能重新啟動(dòng)失敗的容器、替換容器、殺死不響應(yīng)的容器。
-
密鑰與配置管理
kubernetes 允許你存儲(chǔ)和管理敏感信息,例如密碼和 ssh 密鑰。 你可以在不重建容器鏡像的情況下更新密鑰和應(yīng)用程序配置。
k8s集群架構(gòu)以及組成

控制平面(Control Plane)
控制平面對(duì)集群做出全局決策(比如調(diào)度),以及檢測(cè)和響應(yīng)集群事件(例如,當(dāng)容器數(shù)量不足時(shí),啟動(dòng)新的容器)。
控制平面可以在集群中的任何節(jié)點(diǎn)上運(yùn)行。 但是,為了簡(jiǎn)單起見(jiàn),控制平面通常在單獨(dú)的計(jì)算機(jī)上運(yùn)行,并且不會(huì)在此計(jì)算機(jī)上運(yùn)行用戶(hù)容器。
apiserver
apiserver公開(kāi)了 kubernetes的核心接口。kubernetes的所有組件都要通過(guò)apiserver才能與其他組件進(jìn)行通信。例如:當(dāng)調(diào)度器scheduler將任務(wù)發(fā)給工作節(jié)點(diǎn)時(shí),不直接與節(jié)點(diǎn)通信,而是將計(jì)劃告訴apiserver,再由apiserver將任務(wù)發(fā)送給工作節(jié)點(diǎn)。
apiserver 設(shè)計(jì)上考慮了水平伸縮,也就是說(shuō),它可通過(guò)部署多個(gè)實(shí)例進(jìn)行伸縮。 你可以運(yùn)行apiserver 的多個(gè)實(shí)例,并在這些實(shí)例之間平衡流量。
etcd
etcd 是兼具一致性和高可用性的鍵值數(shù)據(jù)庫(kù),可以作為保存 kubernetes 所有集群數(shù)據(jù)的后臺(tái)數(shù)據(jù)庫(kù),etcd保存了kubernetes的所有狀態(tài)信息。
scheduler
scheduler負(fù)責(zé)調(diào)度新創(chuàng)建的pods,選擇節(jié)點(diǎn)讓 pod在上面運(yùn)行。
調(diào)度決策考慮的因素包括資源需求、硬件/軟件/策略約束、親和性和反親和性、數(shù)據(jù)位置、工作負(fù)載間的干擾和時(shí)限等。
controller-manager
controller-manager包括:
節(jié)點(diǎn)控制器(Node Controller): 負(fù)責(zé)在節(jié)點(diǎn)出現(xiàn)故障時(shí)進(jìn)行通知和響應(yīng)
任務(wù)控制器(Job controller): 管理 job對(duì)象,然后創(chuàng)建 pods 來(lái)運(yùn)行這些job直至完成
端點(diǎn)控制器(Endpoints Controller): 填充端點(diǎn)(Endpoints)對(duì)象(即加入 Service 的 Pod)
服務(wù)帳戶(hù)和令牌控制器(Service Account & Token Controllers): 為新的命名空間創(chuàng)建默認(rèn)帳戶(hù)和 API 訪(fǎng)問(wèn)令牌
Node 組件
node組件在每個(gè)節(jié)點(diǎn)上運(yùn)行,包括控制平面節(jié)點(diǎn),維護(hù)運(yùn)行的 pod并提供 kubernetes 運(yùn)行環(huán)境。
kubelet
在每個(gè)節(jié)點(diǎn)上運(yùn)行,保證容器都運(yùn)行在pod中。
kubelet 接收 PodSpecs(pod的運(yùn)行參數(shù)),確保這些 PodSpecs 中描述的容器處于運(yùn)行狀態(tài)且健康。 kubelet 不會(huì)管理不是由 kubernetes 創(chuàng)建的容器。
kube-proxy
kube-proxy是集群中每個(gè)節(jié)點(diǎn)上運(yùn)行的網(wǎng)絡(luò)代理,實(shí)現(xiàn) kubernetes中service概念的一部分。
kube-proxy 維護(hù)節(jié)點(diǎn)上的網(wǎng)絡(luò)規(guī)則。這些網(wǎng)絡(luò)規(guī)則允許從集群內(nèi)部或外部的網(wǎng)絡(luò)會(huì)話(huà)與pod進(jìn)行網(wǎng)絡(luò)通信。
如果操作系統(tǒng)提供了數(shù)據(jù)包過(guò)濾層并可用的話(huà),kube-proxy 會(huì)通過(guò)它來(lái)實(shí)現(xiàn)網(wǎng)絡(luò)規(guī)則。否則, kube-proxy 僅轉(zhuǎn)發(fā)流量本身。
容器運(yùn)行環(huán)境(Container Runtime)
容器運(yùn)行環(huán)境是負(fù)責(zé)運(yùn)行容器的軟件,如docker。
kubernetes 支持多個(gè)容器運(yùn)行環(huán)境: Docker、 containerd、CRI-O 以及任何實(shí)現(xiàn) kubernetes CRI (容器運(yùn)行環(huán)境接口)的軟件。
k8s高可用架構(gòu)
堆疊(Stacked) etcd 拓?fù)?/h2>
堆疊(Stacked) HA(High Availability )集群是一種這樣的拓?fù)?/a>,其中 etcd 分布式數(shù)據(jù)存儲(chǔ)集群堆疊在控制平面節(jié)點(diǎn)上,作為控制平面的一個(gè)組件運(yùn)行。
每個(gè)控制平面節(jié)點(diǎn)運(yùn)行 kube-apiserver,kube-scheduler 和 kube-controller-manager 實(shí)例。
kube-apiserver 使用負(fù)載均衡器暴露給工作節(jié)點(diǎn)。
每個(gè)控制平面節(jié)點(diǎn)創(chuàng)建一個(gè)本地 etcd 成員(member),這個(gè) etcd 成員只與該節(jié)點(diǎn)的 kube-apiserver 通信。這同樣適用于本地 kube-controller-manager 和 kube-scheduler 實(shí)例。
這種拓?fù)鋵⒖刂破矫婧?etcd 成員耦合在同一節(jié)點(diǎn)上。相對(duì)使用外部 etcd 集群,設(shè)置起來(lái)更簡(jiǎn)單,而且更易于副本管理。
然而,堆疊集群存在耦合失敗的風(fēng)險(xiǎn)。如果一個(gè)節(jié)點(diǎn)發(fā)生故障,則 etcd 成員和控制平面實(shí)例都將丟失,因此,應(yīng)該為 HA 集群運(yùn)行至少三個(gè)堆疊的控制平面節(jié)點(diǎn)。
這是 kubeadm 中的默認(rèn)拓?fù)?。?dāng)使用 kubeadm init 和 kubeadm join --control-plane 時(shí),在控制平面節(jié)點(diǎn)上會(huì)自動(dòng)創(chuàng)建本地 etcd 成員。

外部 etcd 拓?fù)?/h2>
具有外部 etcd 的 HA 集群是一種這樣的拓?fù)?/a>,其中 etcd 分布式數(shù)據(jù)存儲(chǔ)集群在獨(dú)立于控制平面節(jié)點(diǎn)的其他節(jié)點(diǎn)上運(yùn)行。
就像堆疊的 etcd 拓?fù)湟粯?,外?etcd 拓?fù)渲械拿總€(gè)控制平面節(jié)點(diǎn)都運(yùn)行 kube-apiserver,kube-scheduler 和 kube-controller-manager 實(shí)例。同樣, kube-apiserver 使用負(fù)載均衡器暴露給工作節(jié)點(diǎn)。但是,etcd 成員在不同的主機(jī)上運(yùn)行,每個(gè) etcd 主機(jī)與每個(gè)控制平面節(jié)點(diǎn)的 kube-apiserver 通信。
這種拓?fù)浣Y(jié)構(gòu)解耦了控制平面和 etcd 成員。因此,失去控制平面實(shí)例或者 etcd 成員的影響較小,并且不會(huì)像堆疊的 HA 拓?fù)淠菢佑绊懠喝哂唷?/p>
但是,此拓?fù)湫枰獌杀队诙询B HA 拓?fù)涞闹鳈C(jī)數(shù)量。
具有此拓?fù)涞?HA 集群至少需要三個(gè)用于控制平面節(jié)點(diǎn)的主機(jī)和三個(gè)用于 etcd 節(jié)點(diǎn)的主機(jī)。

etcd集群中的數(shù)據(jù)一致性
1、etcd是什么
etcd是一個(gè)鍵值存儲(chǔ)系統(tǒng),集群中的每一個(gè)成員都保持著全量的數(shù)據(jù)。
2、數(shù)據(jù)一致性--etcd集群選舉
etcd集群中的角色分為L(zhǎng)eader, Follower, Candidate。同一時(shí)間只存在一個(gè)Leader,Leader處理所有來(lái)自客戶(hù)端寫(xiě)(讀可由Follower處理)操作。
當(dāng)Follower在一定時(shí)間內(nèi)沒(méi)有收到來(lái)自主節(jié)點(diǎn)的心跳,會(huì)將自己角色改變?yōu)镃andidate(自封為候選人),并發(fā)起一次選主投票;當(dāng)收到包括自己在內(nèi)超過(guò)半數(shù)節(jié)點(diǎn)贊成后,選舉成功;當(dāng)收到票數(shù)不足半數(shù)選舉失敗。若本輪未選出主節(jié)點(diǎn),將進(jìn)行下一輪選舉。為了避免陷入選主失敗循環(huán),每個(gè)節(jié)點(diǎn)未收到心跳發(fā)起選舉的時(shí)間是一定范圍內(nèi)的隨機(jī)值,這樣能夠避免2個(gè)節(jié)點(diǎn)同時(shí)發(fā)起選主。Candidate節(jié)點(diǎn)收到來(lái)自主節(jié)點(diǎn)的信息后,會(huì)立即終止選舉過(guò)程,進(jìn)入Follower角色。
在選主邏輯中,為了保障數(shù)據(jù)是最新的,對(duì)能夠成為主的節(jié)點(diǎn)加以限制,確保選出的節(jié)點(diǎn)以已經(jīng)包含了集群已經(jīng)提交的所有日志。如果新選出的主節(jié)點(diǎn)已經(jīng)包含了集群所有提交的日志,那就不需要從和其他節(jié)點(diǎn)比對(duì)數(shù)據(jù)了。簡(jiǎn)化了流程,縮短了集群恢復(fù)服務(wù)的時(shí)間。這里存在一個(gè)問(wèn)題,加以這樣限制之后,還能否選出主呢?答案是:只要仍然有超過(guò)半數(shù)節(jié)點(diǎn)存活,這樣的主一定能夠選出。因?yàn)橐呀?jīng)提交的日志必然被集群中超過(guò)半數(shù)節(jié)點(diǎn)持久化。
3、數(shù)據(jù)一致性--節(jié)點(diǎn)數(shù)量
etcd使用RAFT協(xié)議保證各個(gè)節(jié)點(diǎn)之間的狀態(tài)一致。根據(jù)RAFT算法原理,節(jié)點(diǎn)數(shù)目越多,會(huì)降低集群的寫(xiě)性能。這是因?yàn)槊恳淮螌?xiě)操作,需要集群中大多數(shù)節(jié)點(diǎn)將日志落盤(pán)成功后,Leader節(jié)點(diǎn)才能將修改內(nèi)部狀態(tài)機(jī),并返回將結(jié)果返回給客戶(hù)端。
也就是說(shuō)在等同配置下,節(jié)點(diǎn)數(shù)越少,集群性能越好。顯然,只部署1個(gè)節(jié)點(diǎn)是沒(méi)什么意義的。通常,按照需求將集群節(jié)點(diǎn)部署為3,5,7,9個(gè)節(jié)點(diǎn)。
4、數(shù)據(jù)一致性--數(shù)據(jù)讀寫(xiě)
為了保證數(shù)據(jù)的強(qiáng)一致性,etcd 集群中所有的數(shù)據(jù)流向都是一個(gè)方向,從 Leader (主節(jié)點(diǎn))流向Follower,也就是所有 Follower 的數(shù)據(jù)必須與 Leader 保持一致,如果不一致會(huì)被覆蓋。
讀取: 由于集群所有節(jié)點(diǎn)數(shù)據(jù)是強(qiáng)一致性的,讀取可以從集群中隨便哪個(gè)節(jié)點(diǎn)進(jìn)行讀取數(shù)據(jù)
寫(xiě)入: etcd 集群有 leader,如果寫(xiě)入往 leader 寫(xiě)入,可以直接寫(xiě)入,然后Leader節(jié)點(diǎn)會(huì)把寫(xiě)入分發(fā)給所有 Follower。如果往 follower 寫(xiě)入,請(qǐng)求會(huì)路由到Leader,然后Leader節(jié)點(diǎn)會(huì)把寫(xiě)入分發(fā)給所有 Follower。
5、etcd讀寫(xiě)性能
按照官網(wǎng)給出的資料,在2CPU,1.8G內(nèi)存,SSD磁盤(pán)這樣的配置下,單節(jié)點(diǎn)的寫(xiě)性能可以達(dá)到16K QPS,,而先寫(xiě)后讀也能達(dá)到12K QPS。這個(gè)性能還是相當(dāng)可觀(guān)的。