零基礎入門│帶你理解Kubernetes
條分縷析帶你充分理解Kubernetes的各個細節與部分:它是什麼,它如何解決容器編排問題,它包含哪些你必須掌握的關鍵物件,以及如何快速上手部署使用Kubernetes。
容器的好處不勝列舉:一致的執行時環境、節省磁碟空間、低開銷、良好的隔離性,等等。瞭解完這些優勢,您以及您的同事可能都開始躍躍欲試要把應用程式打包到容器中並準備執行它。然後突然之間或許您會發現,容器執行起來之後有一些問題也接踵而來,您需要一種方法來管理所有正在執行的容器及其生命週期:它們如何相互連線,它們應該執行在什麼硬體之上,它們如何獲取資料儲存,容器因各種原因停止執行的話您該如何處理錯誤······
這就是Kubernetes大顯身手的地方了。
在本文中,我們將瞭解Kubernetes是什麼,它如何解決容器編排問題,它背後是由哪些理論支撐,如何將該理論直接與實際操作繫結,最終幫助您充分理解Kubernetes的各個細節與部分。
Kubernetes: 歷史
Kubernetes,也被稱為k8s(k... 8個字母...和s)或kube,是希臘語中的單詞,意為州長、舵手或船長。拿真正的航海的情景來理解,大型船舶裝載著大量現實生活的容器,而船長或舵手則是負責船舶的人。因此,在資訊科技的語境下,Kubernetes就是Docker容器的船長、編排者。
Kubernetes最初是谷歌公司在內部使用的,基於谷歌執行容器15年的經驗,Kubernetes於2014年開始作為Google的開源專案提供給社群。四年過去,Kubernetes飛速發展,下載及使用量驚人,被大量的中小型企業使用者用於開發或生產環境,並已成為業界公認的容器編排管理的標準框架。
Kubernetes的發展勢頭
Kubernetes的增長態勢驚人,在GitHub上擁有超過40,000顆星,在2018年擁有超過60,000個commit,並且比GitHub上的任何其他專案都有更多的pull request和issue。其增長背後的部分原因是其不凡的可擴充套件性和強大的設計模式,這些我們將在後文中進一步解讀。您可以在此連結瞭解一些大型軟體公司的Kubernetes應用案例:
Kubernetes提供的服務
讓我們來看看是什麼功能及特性讓Kubernetes吸引到業界的如此關注。
Kubernetes的核心是以容器為中心的管理環境。它代表使用者的工作負載來編排計算、網路和儲存基礎架構。這提供了平臺即服務(PaaS)的簡單性和基礎架構即服務(IaaS)的靈活性,並實現了跨基礎架構提供商的可移植性。Kubernetes不僅僅是一個編排系統。實際上,它讓使用者不再需要“編排”。“編排”的技術定義是“執行定義的工作流程”:首先執行A,然後執行B,然後執行C。而有了Kubernetes之後,Kubernetes由一組獨立的、可組合的控制流程組成,這些流程可將當前狀態持續推向所需狀態。而你是如何從A進行到C的,在此無關緊要。而且,使用者也不再需要集中控制,整個系統也變得更易於使用、功能更強大、可擴充套件性更佳。
Kubernetes的基本概念
要使用Kubernetes,您可以使用Kubernetes API物件來描述叢集的所需狀態:您想要執行的應用程式或服務,它們使用的容器映象、副本數量,您希望提供的網路和磁碟資源等等。您可以通過使用Kubernetes API——kubectl(通常通過命令列介面)建立物件來設定所需的狀態。您還可以直接使用Kubernetes API與叢集互動,並設定或修改所需的狀態。
設定完所需狀態後,Kubernetes控制面板會讓叢集的當前狀態與所需狀態相匹配。為此,Kubernetes會自動執行各種任務,例如啟動或重新啟動容器、擴充套件給定應用程式的副本數量等等。
基本的Kubernetes物件包括: - 節點 - Pod - 服務 - 卷 - 名稱空間
此外,Kubernetes包含許多稱為controller的高階抽象。controller基於基本物件構建,並提供其他功能和便利的特性。它們包括:
- ReplicaSet
- Deployment
- StatefulSet
- DaemonSet
- Job
下文中我們會逐個介紹這些概念,然後再嘗試一些動手練習。
節 點
節點( Node)是Kubernetes中的worker machine,以前稱為minion。節點可以是虛擬機器(VM)或物理機(具體取決於叢集)。每個節點都包含執行pod所需的服務,並由主元件管理。你可以這樣理解節點:節點對於pod就像是Hypervisor對於虛擬機器。
Pod
Pod是Kubernetes的基本構建塊,它是您建立或部署的Kubernetes物件模型中最小和最簡單的單元。一個Pod代表著一個部署單元:Kubernetes中的單個應用程式例項,可能包含單個容器或少量緊密組合並共享資源的容器。
Docker是Kubernetes Pod中最常用的容器執行時,但Pods也支援其他容器執行時。
Kubernetes叢集中的Pod主要以兩種方式使用:第一種是執行單個容器的Pod 。“one-container-per-Pod”模式是最常見的Kubernetes用例; 在這種情況下,您可以將Pod視為單個容器的打包,由Kubernetes而非容器來管理 Pods。第二種是執行多個需要協同工作的容器的Pod。一個Pod可能包含了一個應用程式,這個應用程式是由多個緊密耦合並且需要共享資源的容器組成的。這些共存的容器可能形成一個單一的內聚服務單元——一個容器負責從共享卷將檔案公開,而另一個單獨的“sidecar”容器負責重新整理或更新這些檔案。該Pod 將這些容器和儲存資源一起封裝為一個可管理的實體。
Pod為其組成容器提供兩種共享資源:網路和儲存。
網路:每個Pod都分配了一個唯一的IP地址。一個Pod中的所有容器都共享網路名稱空間,包括IP地址和網路埠。Pod內的容器可以使用localhost相互通訊。當Pod內的容器與Pod外的實體通訊時,它們必須協調如何使用共享網路資源(例如埠)。
儲存:Pod可以指定一組共享儲存卷。Pod中的所有容器都可以訪問共享卷,允許這些容器共享資料。如果需要重新啟動其中一個容器,卷還可以讓Pod中的持久資料一直儲存著。
服 務
Kubernetes Pods不是不變的,它們被建立又被殺死後並不會重生。即使每個Pod都有自己的IP地址,你也不能完全指望它會隨著時間推移卻永不改變。這會產生一個問題,如果一組Pods(比如說後端)為Kubernetes叢集中的另一組Pods(比如說前端)提供了功能,那些前端pod如何能夠與後端pod保持可靠的通訊?
這就是服務發揮作用的地方。
Kubernetes服務定義了一個邏輯集Pods和訪問它們的策略(有時稱為微服務),通常由Label Selector確定。
例如,如果你有一個帶有3個Pod的後端應用程式,那些pod是可替代的,前端並不關心它們使用哪個後端。雖然Pods組成後端集的實際情況可能會發生變化,但前端客戶端不應該知道這一點,也不需要跟蹤後端列表本身。該Service抽象可實現這種分離。
對那些處於同樣的Kubernetes叢集中的應用,Kubernetes提供了一個簡單的Endpoints API,每當服務中的一套Pods改變時,API就會相應地更新。對於叢集外的應用程式,Kubernetes提供基於虛擬IP的橋接器,Services可將其重定向到後端Pods。
卷
容器中的磁碟檔案是不是永久的,這會給執行在容器中的應用程式帶來一些問題。首先,當容器崩潰時,它將由Kubernetes重新啟動,但檔案會丟失,因為容器總是以乾淨狀態啟動的。其次,當在一個pod中執行多個容器時,通常需要在這些容器之間共享檔案。Kubernetes Volume就是來解決這兩個問題的。
從本質上講,卷只是一個目錄,可能包含一些資料,在Pod中,它可以訪問容器。該目錄是如何形成的、支援它的介質是什麼以及它的內容,是由所使用的特定卷型別決定的。
Kubernetes卷具有明確的生命週期,與建立它的Pod的生命週期相同。總而言之,一個卷超過了在Pod中執行的任何容器,並且在容器重啟時保留了資料。通常,當一個Pod不再存在時,卷也將不復存在。Kubernetes支援多種型別的卷,並且Pod可以同時使用任意數量的卷。
名稱空間
Kubernetes支援由同一物理叢集支援的多個虛擬叢集。這些虛擬叢集稱為名稱空間。
名稱空間提供了名稱範圍。在一個名稱空間內,每個資源名稱都需要是唯一的,不過跨名稱空間時就沒有這種要求了。
沒有必要只是為了分離略有不同的資源而使用多個名稱空間,比如說同一軟體的不同版本:可以用標籤來區分同一名稱空間內的不同資源。
ReplicaSet
ReplicaSet確保一次執行指定數量的pod副本。換句話說,ReplicaSet確保pod或同類pod組始終可用。但是,Deployment是一個更高級別的概念,它可以管理ReplicaSets,併為Pods提供宣告性更新以及許多其他有用的功能。因此,除非您需要自定義更新編排或根本不需要更新,否則我建議您使用Deployments而不是直接使用ReplicaSets。
這實際上意味著您可能永遠不需要直接操縱ReplicaSet物件,而是可以使用Deployment作為替代。
Deployment
Deployment controller為Pods和ReplicaSets提供宣告性更新。
您在Deployment物件中描述了所需狀態,Deployment controller就將以受控速率將現階段實際狀態更改為所需狀態。您可以定義Deployments來建立新的ReplicaSets,或刪除現有的Deployments並使用新的Deployments來使用所有資源。
StatefulSets
StatefulSet用於管理有狀態應用程式,它管理一組Pods的部署和擴充套件,並提供有關這些Pod 的排序和唯一性的保證。
StatefulSet的執行模式和controller相同。您可以在StatefulSet物件中定義所需的狀態,StatefulSet controller就會進行各種必要的更新以從當前狀態到達更新為所需狀態。和Deployment類似,StatefulSet管理那些基於相同容器規範的Pods。與Deployment不同的是,StatefulSet為每個Pods保留一個粘性身份。這些Pods是根據相同的規範建立的,但不可互換:每個都有一個永久的識別符號,不論如何重新排程,這個標識都保持不變。
DaemonSet
DaemonSet確保所有(或某些)節點執行Pod的副本。隨著節點新增到群集中,Pod會隨之新增。當將節點從叢集中刪除後,Pods就成為了垃圾。此時,刪除一個DaemonSet就將清理它所建立的Pods。
DaemonSet的一些典型用途有:
- 在每個節點上執行叢集儲存daemon,例如glusterd、ceph。
- 在每個節點上執行日誌收集daemon,例如fluentd或logstash。
- 在每個節點上執行節點監控daemon,例如Prometheus Node Exporter或collectd。
Job
job建立一個或多個pod,並確保在需要的時候成功終止指定數量的pod。Pods成功完成後,job會追蹤順利完成的情況。當達到指定數量時,job本身的任務就完成了。刪除Job將清除它所建立的Pods。
一個簡單的例子是建立一個Job物件,以便可靠地執行一個物件Pod。如果第一個Pod失敗或被刪除(例如由於節點硬體故障或節點重啟),那麼該Job物件將啟動一個新Pod。
實際操作中的挑戰
現在您已經瞭解了Kubernetes中的關鍵物件及概念了,很明顯,想要玩轉Kubernetes需要了解大量的資訊。當你嘗試使用Kubernetes時,可能會遇到如下挑戰:
- 如何在不同的基礎架構中一致地部署?
- 如何跨多個叢集(和名稱空間)實現和管理訪問控制?
- 如何與中央身份驗證系統整合?
- 如何分割槽叢集以更有效地使用資源?
- 如何管理多租戶、多個專用和共享叢集?
- 如何建立高可用叢集?
- 如何跨叢集/名稱空間實施安全策略?
- 如何良好地進行監控,以確保有足夠的可見性來檢測和解決問題?
- 如何跟上Kubernetes快速發展的步伐?
這就是Rancher可以幫助您的地方。Rancher是一個100%開源的容器管理平臺,用於在生產中執行Kubernetes。通過Rancher,你可以:
- 擁有易於使用的kubernetes配置和部署介面;
- 跨多個叢集和雲的基礎架構管理;
- 自動部署最新的kubernetes版本;
- 工作負載、RBAC、政策和專案管理;
- 24x7企業級支援。
Rancher可以成為一個單一控制點,而您可以在多種、多個基礎架構上執行多個Kubernetes叢集:
上手Rancher和Kubernetes
現在讓我們看看如何在Rancher的幫助下輕鬆使用前文描述的Kubernetes物件。首先,您需要一個Rancher例項。按照本指南,在幾分鐘之內即可啟動一個Rancher例項並使用它建立一個Kubernetes叢集:
啟動集群后,您應該在Rancher中看到Kubernetes叢集的資源:
要從第一個Kubernetes物件——節點開始,請單擊頂部選單上的Nodes。你應該可以組成了你的Kubernetes叢集的Nodes的整體情況:
在那裡,您還可以看到已從Kubernetes叢集部署到每個節點的pod的數量。這些pod由Kubernetes和Rancher內部系統使用。通常情況下你不需要處理那些。
下面讓我們繼續Pod的例子。要做到這一點,轉到Kubernetes叢集的Default專案,然後進入Workloads選項卡。下面讓我們部署一個工作負載。點選Deploy並將Name和Docker image設定為nginx,剩下的一切都使用預設值,然後點選Launch。
建立後,Workloads選項卡會顯示nginx工作負載。
如果單擊nginx工作負載,您將會看到Rancher實際建立了一個Deployment,就像Kubernetes推薦的那樣用來管理ReplicaSet,您還將看到該ReplicaSet建立的Pod:
現在你有一個Deployment,它將確保我們所需的狀態在叢集中正確顯示。現在,點選Scale附近+號,將此Workload擴容到3。一旦你這樣做,你應該能立即看到另外2個Pods被創建出來,另外還多了2個ReplicaSet來縮放事件。使用Pod右側選單,嘗試刪除其中一個pod,並注意ReplicaSet是如何重新建立它以匹配所需狀態的。
現在,您的應用程式已啟動並執行,並且已經擴充套件到3個例項。下一個問題是,您如何訪問它?在這裡,我們將嘗試使用下一個Kubernetes物件——服務。為了暴露我們的nginx工作負載,我們需要先編輯它,從Workload右側選單中選擇Edit。您將看到Deploy Workload頁面,且已填好了您的nginx工作負載的詳細資訊:
請注意,現在您有3個pod在Scalable Deployment旁邊,但是當您啟動時,預設值為1。這是因為你的擴充套件工作剛完成不久。
現在單擊Add Port,並按如下所示填充值:
將Publish the container port值設定為80;
Protocol仍為TCP;
將As a值設定為Layer-4 Load Balancer;
將On listening port值設定為80。
然後自信地點選Upgrade吧!這將在您的雲提供商中建立一個外部負載均衡器,並將流量引至您的Kubernetes叢集內的nginx Pods中。要對此進行測試,請再次訪問nginx工作負載概述頁面,現在您應該看到Endpoints旁的80/tcp連結:
如果點選80/tcp,它會導向您剛剛建立的負載均衡器的外部IP,並且向您展示一個預設的nginx頁面,確認一切都按預期正常工作。
至此,你已經搞定了上半篇文章中介紹的大多數Kubernetes物件。你可以在Rancher中好好玩玩卷和名稱空間,相信您一定能很快掌握如何通過Rancher更簡單快捷地使用它們。至於StatefulSet、DaemonSet和Job,它們和Deployments非常類似,你同樣可以在Workloads選項卡中通過選擇Workload type來建立它們。
結 語
讓我們回顧一下你在上面的動手練習中所做的一切。你已經建立了我們描述的大多數Kubernetes物件:
1、最開始,你在Rancher中建立了kubernetes叢集;
2、然後你瀏覽了叢集的Nodes;
3、你創造了一個Workload;
4、你已經看到了一個Workload實際上建立了3個獨立的Kubernetes物件:一個Deployment管理著 ReplicaSet,同時按需保持著所需數量的Pods正常執行;
5、在那之後你擴充套件了你的Deployment數量,並觀察它是如何改變了ReplicaSet並相應地擴充套件Pods的數量的;
6、最後你建立了一個Load Balancer型別的Service型別,用於平衡Pods之間的客戶端請求。
所有這些都可以通過Rancher輕鬆完成,您只需進行一些點選的操作,無需在本地安裝任何軟體來複制身份驗證配置或在終端中執行命令列。您只需一個瀏覽器,玩轉Kubernetes唾手可得。