Docker叢集管理工具 - Kubernetes 部署記錄 (運維小結)

散盡浮華發表於2016-06-11

 

一.  Kubernetes 介紹

Kubernetes是一個全新的基於容器技術的分散式架構領先方案, 它是Google在2014年6月開源的一個容器叢集管理系統,使用Go語言開發,Kubernetes也叫K8S。K8S是Google內部一個叫Borg的容器叢集管理系統衍生出來的,Borg已經在Google大規模生產執行十年之久。K8S主要用於自動化部署、擴充套件和管理容器應用,提供了資源排程、部署管理、服務發現、擴容縮容、監控等一整套功能。2015年7月,Kubernetes v1.0正式釋出,截止到2017年9月29日最新穩定版本是v1.8。Kubernetes目標是讓部署容器化應用簡單高效。

Kubernetes最初源於谷歌內部的Borg,提供了面向應用的容器叢集部署和管理系統。Kubernetes 的目標旨在消除編排物理/虛擬計算,網路和儲存基礎設施的負擔,並使應用程式運營商和開發人員完全將重點放在以容器為中心的原語上進行自助運營。Kubernetes 也提供穩定、相容的基礎(平臺),用於構建定製化的workflows 和更高階的自動化任務。

Kubernetes 具備完善的叢集管理能力,包括多層次的安全防護和准入機制、多租戶應用支撐能力、透明的服務註冊和服務發現機制、內建負載均衡器、故障發現和自我修復能力、服務滾動升級和線上擴容、可擴充套件的資源自動排程機制、多粒度的資源配額管理能力。Kubernetes 還提供完善的管理工具,涵蓋開發、部署測試、運維監控等各個環節。

二.  Kubernetes主要功能

Kubernetes是開源容器叢集管理系統,是基於Docker構建一個容器的排程服務,提供資源排程、均衡容災、服務註冊、動態擴縮容等功能套件。Kubernetes提供應用部署、維護、 擴充套件機制等功能,利用Kubernetes能方便地管理跨機器執行容器化的應用,其主要功能如下:

資料卷: Pod中容器之間共享資料,可以使用資料卷。

應用程式健康檢查: 容器內服務可能程式堵塞無法處理請求,可以設定監控檢查策略保證應用健壯性。

複製應用程式例項: 控制器維護著Pod副本數量,保證一個Pod或一組同類的Pod數量始終可用。

彈性伸縮: 根據設定的指標(CPU利用率)自動縮放Pod副本數。

服務發現: 使用環境變數或DNS服務外掛保證容器中程式發現Pod入口訪問地址。

負載均衡: 一組Pod副本分配一個私有的叢集IP地址,負載均衡轉發請求到後端容器。在叢集內部其他Pod可通過這個ClusterIP訪問應用。

滾動更新: 更新服務不中斷,一次更新一個Pod,而不是同時刪除整個服務。

服務編排: 通過檔案描述部署服務,使得應用程式部署變得更高效。

資源監控: Node節點元件整合cAdvisor資源收集工具,可通過Heapster彙總整個叢集節點資源資料,然後儲存到InfluxDB時序資料庫,再由Grafana展示。

提供認證和授權: 支援屬性訪問控制(ABAC)、角色訪問控制(RBAC)認證授權策略。

除此之外, Kubernetes主要功能還體現在:
-  使用Docker對應用程式包裝(package)、例項化(instantiate)、執行(run)。
-  將多臺Docker主機抽象為一個資源,以叢集的方式執行、管理跨機器的容器,包括任務排程、資源管理、彈性伸縮、滾動升級等功能。
-  使用編排系統(YAML File)快速構建容器叢集,提供負載均衡,解決容器直接關聯及通訊問題
-  解決Docker跨機器容器之間的通訊問題
-  自動管理和修復容器,簡單說,比如建立一個叢集,裡面有十個容器,如果某個容器異常關閉,那麼,會嘗試重啟或重新分配容器,始終保證會有十個容器在執行,反而殺死多餘的。Kubernetes的自我修復機制使得容器叢集總是執行在使用者期望的狀態. 當前Kubernetes支援GCE、vShpere、CoreOS、OpenShift。

三.  Kubernetes架構和元件

Kubernetes架設圖

kubernetes主要由以下幾個核心元件組成:
etcd: 叢集的主資料庫,儲存了整個叢集的狀態; etcd負責節點間的服務發現和配置共享。etcd分散式鍵值儲存系統, 用於保持叢集狀態,比如Pod、Service等物件資訊。
kube-apiserver: 提供了資源操作的唯一入口,並提供認證、授權、訪問控制、API註冊和發現等機制;這是kubernetes API,作為叢集的統一入口,各元件協調者,以HTTPAPI提供介面服務,所有物件資源的增刪改查和監聽操作都交給APIServer處理後再提交給Etcd儲存。
kube-controller-manager: 負責維護叢集的狀態,比如故障檢測、自動擴充套件、滾動更新等;它用來執行整個系統中的後臺任務,包括節點狀態狀況、Pod個數、Pods和Service的關聯等, 一個資源對應一個控制器,而ControllerManager就是負責管理這些控制器的。
kube-scheduler: 資源排程,按照預定的排程策略將Pod排程到相應的機器上;它負責節點資源管理,接受來自kube-apiserver建立Pods任務,並分配到某個節點。它會根據排程演算法為新建立的Pod選擇一個Node節點。
kubectl: 客戶端命令列工具,將接受的命令格式化後傳送給kube-apiserver,作為整個系統的操作入口。
kubelet: 負責維護容器的生命週期,負責管理pods和它們上面的容器,images映象、volumes、etc。同時也負責Volume(CVI)和網路(CNI)的管理;kubelet執行在每個計算節點上,作為agent,接受分配該節點的Pods任務及管理容器,週期性獲取容器狀態,反饋給kube-apiserver; kubelet是Master在Node節點上的Agent,管理本機執行容器的生命週期,比如建立容器、Pod掛載資料卷、下載secret、獲取容器和節點狀態等工作。kubelet將每個Pod轉換成一組容器。
container runtime: 負責映象管理以及Pod和容器的真正執行(CRI);
kube-proxy: 負責為Service提供cluster內部的服務發現和負載均衡;它執行在每個計算節點上,負責Pod網路代理。定時從etcd獲取到service資訊來做相應的策略。它在Node節點上實現Pod網路代理,維護網路規則和四層負載均衡工作。
docker或rocket(rkt): 執行容器。

除了上面的幾個核心組建, 還有一些常用外掛(Add-ons):
kube-dns: 負責為整個叢集提供DNS服務;
Ingress Controller: 為服務提供外網入口;
Heapster: 提供資源監控;
Dashboard: 提供GUI;
Federation: 提供跨可用區的叢集;
Fluentd-elasticsearch: 提供叢集日誌採集、儲存與查詢;

其中:
master元件包括: kube-apiserver, kube-controller-manager, kube-scheduler;
Node元件包括: kubelet, kube-proxy, docker或rocket(rkt);
第三方服務:etcd

Kubernetes Master控制元件,排程管理整個系統(叢集),包含如下元件:
Kubernetes API Server: 作為Kubernetes系統入口,其封裝了核心物件的增刪改查操作,以RESTful API介面方式提供給外部客戶和內部元件呼叫,維護的REST物件持久化到Etcd中儲存。
Kubernetes Scheduler: 為新建立的Pod進行節點(node)選擇(即分配機器),負責叢集的資源排程。元件抽離,可以方便替換成其他排程器。
Kubernetes Controller: 負責執行各種控制器,目前已經提供了很多控制器來保證Kubernetes的正常執行。
Replication Controller: 管理維護Replication Controller,關聯Replication Controller和Pod,保證Replication Controller定義的副本數量與實際執行Pod數量一致。
Node Controller: 管理維護Node,定期檢查Node的健康狀態,標識出(失效|未失效)的Node節點。
Namespace Controller: 管理維護Namespace,定期清理無效的Namespace,包括Namesapce下的API物件,比如Pod、Service等。
Service Controller: 管理維護Service,提供負載以及服務代理。
EndPoints Controller: 管理維護Endpoints,關聯Service和Pod,建立Endpoints為Service的後端,當Pod發生變化時,實時更新Endpoints。
Service Account Controller: 管理維護Service Account,為每個Namespace建立預設的Service Account,同時為Service Account建立Service Account Secret。
Persistent Volume Controller: 管理維護Persistent Volume和Persistent Volume Claim,為新的Persistent Volume Claim分配Persistent Volume進行繫結,為釋放的Persistent Volume執行清理回收。
Daemon Set Controller: 管理維護Daemon Set,負責建立Daemon Pod,保證指定的Node上正常的執行Daemon Pod。
Deployment Controller: 管理維護Deployment,關聯Deployment和Replication Controller,保證執行指定數量的Pod。當Deployment更新時,控制實現Replication Controller和 Pod的更新。
Job Controller: 管理維護Job,為Jod建立一次性任務Pod,保證完成Job指定完成的任務數目
Pod Autoscaler Controller: 實現Pod的自動伸縮,定時獲取監控資料,進行策略匹配,當滿足條件時執行Pod的伸縮動作。

Kubernetes Node執行節點,執行管理業務容器,包含如下元件:
Kubelet: 負責管控容器,Kubelet會從Kubernetes API Server接收Pod的建立請求,啟動和停止容器,監控容器執行狀態並彙報給Kubernetes API Server。
Kubernetes Proxy: 負責為Pod建立代理服務,Kubernetes Proxy會從Kubernetes API Server獲取所有的Service資訊,並根據Service的資訊建立代理服務,實現Service到Pod的請求路由和轉發,從而實現Kubernetes層級的虛擬轉發網路。
Docker:  Node上需要執行容器服務

Kubernetes的分層設計理念
Kubernetes設計理念和功能類似Linux的分層架構,如下圖:

核心層:Kubernetes最核心的功能,對外提供API構建高層的應用,對內提供外掛式應用執行環境;
應用層:部署(無狀態應用、有狀態應用、批處理任務、叢集應用等)和路由(服務發現、DNS解析等);
管理層:系統度量(如基礎設施、容器和網路的度量),自動化(如自動擴充套件、動態Provision等)以及策略管理(RBAC、Quota、PSP、NetworkPolicy等);
介面層:kubectl命令列工具、客戶端SDK以及叢集聯邦;
生態系統:在介面層之上的龐大容器叢集管理排程的生態系統,可以劃分為兩個範疇:    
-  Kubernetes外部:日誌、監控、配置管理、CI、CD、Workflow、FaaS、OTS應用、ChatOps等;    
-  Kubernetes內部:CRI、CNI、CVI、映象倉庫、Cloud Provider、叢集自身的配置和管理等;

Kubelet流程圖:

根據上圖可知Kubelet是Kubernetes叢集中每個Minion和Master API Server的連線點,Kubelet執行在每個Minion上,是Master API Server和Minion之間的橋樑,
接收Master API Server分配給它的commands和work,與永續性鍵值儲存etcd、file、server和http進行互動,讀取配置資訊。Kubelet的主要工作是管理Pod和容
器的生命週期,其包括Docker Client、Root Directory、Pod Workers、Etcd Client、Cadvisor Client以及Health Checker元件,具體工作如下:
-  通過Worker給Pod非同步執行特定的Action;
-  設定容器的環境變數;
給容器繫結Volume;
-  給容器繫結Port;
根據指定的Pod執行一個單一容器;
殺死容器;
給指定的Pod建立network 容器;
-  刪除Pod的所有容器;
同步Pod的狀態;
-  從Cadvisor獲取container info、 pod info、root info、machine info;
檢測Pod的容器健康狀態資訊;
-  在容器中執行命令;

四.  Kubernetes基本物件概念

Kubernetes中的大部分概念Node、Pod、Replication Controller、Service等都可以看作一種“資源物件”,幾乎所有的資源物件都可以通過kubectl工具(API呼叫)執行增、刪、改、查等操作並將其儲存在etcd中持久化儲存。從這個角度來看,kubernetes其實是一個高度自動化的資源控制系統,通過跟蹤對比etcd庫裡儲存的“資源期望狀態”與當前環境中的“實際資源狀態”的差異來實現自動控制和自動糾錯的高階功能。

基本物件:
Pod: Pod是最小部署單元,一個Pod有一個或多個容器組成,Pod中容器共享儲存和網路,在同一臺Docker主機上執行; Pod 中的容器會作為一個整體被Master排程到一個Node上執行。
Service : Service一個應用服務抽象,定義了Pod邏輯集合和訪問這個Pod集合的策略。Service代理Pod集合對外表現是為一個訪問入口,分配一個叢集IP地址,來自這個IP的請求將負載均衡轉發後端Pod中的容器。Service通過LableSelector選擇一組Pod提供服務。
Volume: 資料卷,共享Pod中容器使用的資料。
Namespace: 名稱空間將物件邏輯上分配到不同Namespace,可以是不同的專案、使用者等區分管理,並設定控制策略,從而實現多租戶。名稱空間也稱為虛擬叢集。
Lable: 標籤用於區分物件(比如Pod、Service),鍵/值對存在;每個物件可以有多個標籤,通過標籤關聯物件。

基於基本物件更高層次抽象:  
ReplicaSet: 下一代ReplicationController。確保任何給定時間指定的Pod副本數量,並提供宣告式更新等功能。RC與RS唯一區別就是lableselector支援不同,RS支援新的基於集合的標籤,RC僅支援基於等式的標籤。
Deployment: Deployment是一個更高層次的API物件,它管理ReplicaSets和Pod,並提供宣告式更新等功能。官方建議使用Deployment管理ReplicaSets,而不是直接使用ReplicaSets,這就意味著可能永遠不需要直接操作ReplicaSet物件。
StatefulSet: StatefulSet適合永續性的應用程式,有唯一的網路識別符號(IP),持久儲存,有序的部署、擴充套件、刪除和滾動更新。
DaemonSet: DaemonSet確保所有(或一些)節點執行同一個Pod。當節點加入Kubernetes叢集中,Pod會被排程到該節點上執行,當節點從叢集中移除時,DaemonSet的Pod會被刪除。刪除DaemonSet會清理它所有建立的Pod。
Job: 一次性任務,執行完成後Pod銷燬,不再重新啟動新容器。還可以任務定時執行。Kubernetes中的Job 用於執行結束就刪除的應用。

kubernetes概念說明

API物件是K8s叢集中的管理操作單元。K8s叢集系統每支援一項新功能,引入一項新技術,一定會新引入對應的API物件,支援對該功能的管理操作。例如副本集Replica Set對應的API物件是RS。

Kubernetes中所有的配置都是通過API物件的spec去設定的,也就是使用者通過配置系統的理想狀態來改變系統,這是k8s重要設計理念之一,即所有的操作都是宣告式 (Declarative) 的而不是命令式(Imperative)的。宣告式操作在分散式系統中好處是穩定,不怕丟操作或執行多次,例如設定副本數為3的操作執行多次也還是一個結果, 而給副本數加1的操作就不是宣告式的, 執行多次結果就錯了。

Cluster
Cluster 是計算、儲存和網路資源的集合,Kubernetes 利用這些資源執行各種基於容器的應用

Master
kubernetes叢集的管理節點,負責管理叢集,提供叢集的資源資料訪問入口。擁有Etcd儲存服務(可選),執行Api Server程式,Controller Manager服務程式及Scheduler服務程式,關聯工作節點Node。Kubernetes API server提供HTTP Rest介面的關鍵服務程式,是Kubernetes裡所有資源的增、刪、改、查等操作的唯一入口。也是叢集控制的入口程式;Kubernetes Controller Manager是Kubernetes所有資源物件的自動化控制中心;Kubernetes Schedule是負責資源排程(Pod排程)的程式.

Node
Node是Kubernetes叢集架構中執行Pod的服務節點(亦叫agent或minion)。Node是Kubernetes叢集操作的單元,用來承載被分配Pod的執行,是Pod執行的宿主機。關聯Master管理節點,擁有名稱和IP、系統資源資訊。執行docker eninge服務,守護程式kunelet及負載均衡器kube-proxy. 每個Node節點都執行著以下一組關鍵程式: 
kubelet:負責對Pod對於的容器的建立、啟停等任務
kube-proxy:實現Kubernetes Service的通訊與負載均衡機制的重要元件
Docker Engine(Docker):Docker引擎,負責本機容器的建立和管理工作

Node節點可以在執行期間動態增加到Kubernetes叢集中,預設情況下,kubelet會想master註冊自己,這也是Kubernetes推薦的Node管理方式,kubelet程式會定時向Master彙報自身情報,如作業系統、Docker版本、CPU和記憶體,以及有哪些Pod在執行等等,這樣Master可以獲知每個Node節點的資源使用情況,冰實現高效均衡的資源排程策略。、

Pod
執行於Node節點上,若干相關容器的組合。Pod內包含的容器執行在同一宿主機上,使用相同的網路名稱空間、IP地址和埠,能夠通過localhost進行通。Pod是Kurbernetes進行建立、排程和管理的最小單位,它提供了比容器更高層次的抽象,使得部署和管理更加靈活。一個Pod可以包含一個容器或者多個相關容器。

Pod其實有兩種型別:普通Pod和靜態Pod,後者比較特殊,它並不存在Kubernetes的etcd儲存中,而是存放在某個具體的Node上的一個具體檔案中,並且只在此Node上啟動。普通Pod一旦被建立,就會被放入etcd儲存中,隨後會被Kubernetes Master排程到摸個具體的Node上進行繫結,隨後該Pod被對應的Node上的kubelet程式例項化成一組相關的Docker容器並啟動起來。在預設情況下,當Pod裡的某個容器停止時,Kubernetes會自動檢測到這個問起並且重啟這個Pod(重啟Pod裡的所有容器),如果Pod所在的Node當機,則會將這個Node上的所有Pod重新排程到其他節點上。

Pod是在K8s叢集中執行部署應用或服務的最小單元,它是可以支援多容器的。Pod的設計理念是支援多個容器在一個Pod中共享網路地址和檔案系統,可以通過程式間通訊和檔案共享這種簡單高效的方式組合完成服務.比如你執行一個作業系統發行版的軟體倉庫,一個Nginx容器用來發布軟體,另一個容器專門用來從源倉庫做同步,這兩個容器的映象不太可能是一個團隊開發的,但是他們一塊兒工作才能提供一個微服務;這種情況下,不同的團隊各自開發構建自己的容器映象,在部署的時候組合成一個微服務對外提供服務.

Kubernetes 引入 Pod 主要基於下面兩個目的:
- 可管理性
有些容器天生就是需要緊密聯絡, 一起工作。Pod 提供了比容器更高層次的抽象,將它們封裝到一個部署單元中。Kubernetes 以 Pod 為最小單位進行排程、擴充套件、共享資源、管理生命週期。

- 通訊和資源共享
Pod 中的所有容器使用同一個網路 namespace,即相同的 IP 地址和 Port 空間。它們可以直接用 localhost 通訊。同樣的,這些容器可以共享儲存,當 Kubernetes 掛載 volume 到 Pod,本質上是將 volume 掛載到 Pod 中的每一個容器。

File Puller 會定期從外部的 Content Manager 中拉取最新的檔案,將其存放在共享的 volume 中。Web Server 從 volume 讀取檔案,響應 Consumer 的請求。這兩個容器是緊密協作的,它們一起為 Consumer 提供最新的資料;同時它們也通過 volume 共享資料。所以放到一個 Pod 是合適的。

Controller
Kubernetes 通常不會直接建立 Pod,而是通過 Controller 來管理 Pod 的。Controller 中定義了 Pod 的部署特性,比如有幾個副本,在什麼樣的 Node 上執行等。為了滿足不同的業務場景, Kubernetes 提供了多種 Controller,包括 Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等

Replication Controller (副本集RC)
Replication Controller用來管理Pod的副本,保證叢集中存在指定數量的Pod副本。叢集中副本的數量大於指定數量,則會停止指定數量之外的多餘容器數量,反之,則會啟動少於指定數量個數的容器,保證數量不變。Replication Controller是實現彈性伸縮、動態擴容和滾動升級的核心。

通過監控執行中的Pod來保證叢集中執行指定數目的Pod副本。少於指定數目,RC就會啟動執行新的Pod副本;多於指定數目,RC就會殺死多餘的Pod副本 (這是k8s早期技術概念)

Replica Set (副本集RS)
RS是新一代RC,提供同樣的高可用能力,區別主要在於RS後來居上,能支援更多種類的匹配模式。副本集物件一般不單獨使用,而是作為Deployment的理想狀態引數使用. Replica Set 實現了 Pod 的多副本管理。使用 Deployment 時會自動建立 ReplicaSet,也就是說 Deployment 是通過 ReplicaSet 來管理 Pod 的多個副本,我們通常不需要直接使用 ReplicaSet。

Deployment (部署)
Deployment 是最常用的 Controller,Deployment 可以管理 Pod 的多個副本,並確保 Pod 按照期望的狀態執行。Deployment是一個比RS應用模式更廣的API物件,支援動態擴充套件。可以建立一個新的服務,更新一個新的服務,也可以是滾動升級一個服務。滾動升級一個服務,實際是建立一個新的RS,然後逐漸將新RS中副本數增加到理想狀態,將舊RS中的副本數減小到0的複合操作 (逐步升級新得副本,剔除舊的副本). 
總結:RC、RS和Deployment只是保證了支撐服務的微服務Pod的數量.

DaemonSet
DaemonSet 用於每個 Node 最多隻執行一個 Pod 副本的場景。正如其名稱所揭示的,DaemonSet 通常用於執行 daemon。

StatefuleSet
StatefuleSet 能夠保證 Pod 的每個副本在整個生命週期中名稱是不變的。而其他 Controller 不提供這個功能,當某個 Pod 發生故障需要刪除並重新啟動時,Pod 的名稱會發生變化。同時 StatefuleSet 會保證副本按照固定的順序啟動、更新或者刪除。

Service

Service定義了Pod邏輯集合和訪問該集合的策略,是真實服務的抽象。Service提供了統一的服務訪問入口以及服務代理和發現機制,關聯多個相同Label的Pod,使用者不需要了解後臺Pod是如何執行。
外部系統訪問Service的問題:
->  首先需要弄明白Kubernetes的三種IP這個問題
      Node IP:Node節點的IP地址
    -  Pod IP: Pod的IP地址
     Cluster IP:Service的IP地址
->   首先,Node IP是Kubernetes叢集中節點的物理網路卡IP地址,所有屬於這個網路的伺服器之間都能通過這個網路直接通訊。這也表明Kubernetes叢集之外的節點訪問Kubernetes叢集之內的某個節點或者TCP/IP服務的時候,必須通過Node IP進行通訊
->  其次,Pod IP是每個Pod的IP地址,他是Docker Engine根據docker0網橋的IP地址段進行分配的,通常是一個虛擬的二層網路。

最後Cluster IP是一個虛擬的IP,但更像是一個偽造的IP網路,原因有以下幾點: 
->  Cluster IP僅僅作用於Kubernetes Service這個物件,並由Kubernetes管理和分配P地址
->  Cluster IP無法被ping,他沒有一個“實體網路物件”來響應
->  Cluster IP只能結合Service Port組成一個具體的通訊埠,單獨的Cluster IP不具備通訊的基礎,並且他們屬於Kubernetes叢集這樣一個封閉的空間。
->  Kubernetes叢集之內,Node IP網、Pod IP網於Cluster IP網之間的通訊,採用的是Kubernetes自己設計的一種程式設計方式的特殊路由規則。

RC、RS和Deployment只是保證了支撐服務的微服務Pod的數量,但是沒有解決如何訪問這些服務的問題。一個Pod只是一個執行服務的例項,隨時可能在一個節點上停止,在另一個節點以一個新的IP啟動一個新的Pod,因此不能以確定的IP和埠號提供服務。要穩定地提供服務需要服務發現和負載均衡能力。服務發現完成的工作,是針對客戶端訪問的服務,找到對應的的後端服務例項。在K8s叢集中,客戶端需要訪問的服務就是Service物件。每個Service會對應一個叢集內部有效的虛擬IP,叢集內部通過虛擬IP訪問一個服務。在K8s叢集中微服務的負載均衡是由Kube-proxy實現的。Kube-proxy是K8s叢集內部的負載均衡器。它是一個分散式代理伺服器,在K8s的每個節點上都有一個;這一設計體現了它的伸縮性優勢,需要訪問服務的節點越多,提供負載均衡能力的Kube-proxy就越多,高可用節點也隨之增多。與之相比,我們平時在伺服器端做個反向代理做負載均衡,還要進一步解決反向代理的負載均衡和高可用問題。

Kubernetes 執行容器(Pod)與訪問容器(Pod)這兩項任務分別由 Controller 和 Service 執行。

Namespace
名字空間為K8s叢集提供虛擬的隔離作用,K8s叢集初始有兩個名字空間,分別是預設名字空間default和系統名字空間kube-system,除此以外,管理員可以可以建立新的名字空間滿足需要。

Label
Kubernetes中任意API物件都是通過Label進行標識,Label的實質是一系列的Key/Value鍵值對,其中key於value由使用者自己指定。Label可以附加在各種資源物件上,如Node、Pod、Service、RC等,一個資源物件可以定義任意數量的Label,同一個Label也可以被新增到任意數量的資源物件上去。Label是Replication Controller和Service執行的基礎,二者通過Label來進行關聯Node上執行的Pod。

我們可以通過給指定的資源物件捆綁一個或者多個不同的Label來實現多維度的資源分組管理功能,以便於靈活、方便的進行資源分配、排程、配置等管理工作。
一些常用的Label如下:
版本標籤:"release":"stable","release":"canary"......
環境標籤:"environment":"dev","environment":"qa","environment":"production"
架構標籤:"tier":"frontend","tier":"backend","tier":"middleware"
分割槽標籤:"partition":"customerA","partition":"customerB"
質量管控標籤:"track":"daily","track":"weekly"

Label相當於我們熟悉的標籤,給某個資源物件定義一個Label就相當於給它大了一個標籤,隨後可以通過Label Selector(標籤選擇器)查詢和篩選擁有某些Label的資源物件,Kubernetes通過這種方式實現了類似SQL的簡單又通用的物件查詢機制。

Label Selector在Kubernetes中重要使用場景如下:
-> kube-Controller程式通過資源物件RC上定義Label Selector來篩選要監控的Pod副本的數量,從而實現副本數量始終符合預期設定的全自動控制流程;
-> kube-proxy程式通過Service的Label Selector來選擇對應的Pod,自動建立起每個Service島對應Pod的請求轉發路由表,從而實現Service的智慧負載均衡;
-> 通過對某些Node定義特定的Label,並且在Pod定義檔案中使用Nodeselector這種標籤排程策略,kuber-scheduler程式可以實現Pod”定向排程“的特性;

======================================================================================
重要概念小結 (細節):

Master:叢集控制管理節點,所有的命令都經由master處理。

Node:是kubernetes叢集的工作負載節點。Master為其分配工作,當某個Node當機時,Master會將其工作負載自動轉移到其他節點。

Node節點可動態增加到kubernetes叢集中,前提是這個節點已經正確安裝、配置和啟動了上述的關鍵程式,預設情況下,kubelet會向Master註冊自己,這也kubernetes推薦的Node管理方式。一旦Node被納入叢集管理範圍,kubelet會定時向Master彙報自身的情況,以及之前有哪些Pod在執行等,這樣Master可以獲知每個Node的資源使用情況,並實現高效均衡的資源排程策略。如果Node沒有按時上報資訊,則會被Master判斷為失聯,Node狀態會被標記為Not Ready,隨後Master會觸發工作負載轉移流程。

Pod是kubernetes最重要也是最基本的概念。每個Pod都會包含一個 “根容器”,還會包含一個或者多個緊密相連的業務容器。

Kubernetes為每個Pod都分配了唯一IP地址, 稱之為PodIP, 一個Pod裡多個容器共享PodIP地址. 要求底層網路支援叢集內任意兩個Pod之間的直接通訊,通常採用虛擬二層網路技術來實現 (Flannel).

Label:是一個key=value的鍵值對,其中key與value由使用者指定, 可以附加到各種資源物件上, 一個資源物件可以定義任意數量的Label。可以通過LabelSelector(標籤選擇器)查詢和篩選資源物件。

RCReplication Controller宣告某個Pod的副本數在任意時刻都符合某個預期值。定義包含如下:
-  Pod期待的副本數(replicas);
-  用於篩選目標Pod的Label Selector;
-  當Pod副本數小於期望時,用於新的建立Pod的模板template;

需要注意
-  通過改變RC裡的Pod副本數量,可以實現Pod的擴容或縮容功能;
-  通過改變RC裡Pod模板中的映象版本,可以實現Pod的滾動升級功能;

Service:“微服務”,kubernetes中的核心。通過分析、識別並建模系統中的所有服務為微服務,最終系統有多個提供不同業務能力而又彼此獨立的微服務單元所組成,服務之間通過TCP/IP進行通訊。每個Pod都會被分配一個單獨的IP地址,而且每個Pod都提供了一個獨立的Endpoint以被客戶端訪問。

客戶端如何訪問?
部署負載均衡器,為Pod開啟對外服務埠,將Pod的Endpoint列表加入轉發列表中,客戶端通過負載均衡器的對外IP+Port來訪問此服務。每個Service都有一個全域性唯一的虛擬ClusterIP,這樣每個服務就變成了具備唯一IP地址的“通訊節點”,服務呼叫就變成了最基礎的TCP網路通訊問題。

Volume:是Pod中能夠被多個容器訪問的共享目錄。定義在Pod之上,被一個Pod裡的多個容器掛載到具體的檔案目錄之下;Volume與Pod生命週期相同。Volume可以讓一個Pod裡的多個容器共享檔案、讓容器的資料寫到宿主機的磁碟上或者寫檔案到 網路儲存中,具體如下圖所示:

在kubernetes1.2的時候,RC就由Replication Controller升級成Replica Set,“下一代RC”。命令相容適用,Replica Set主要被Deployment這個更高層的資源物件所使用,從而形成一套Pod建立、刪除、更新的編排機制。當我們使用Deployment時,無需關心它是如何建立和維護ReplicaSet的,這一切是自動發生的。

Docker: 既然k8s是基於容器的,那麼就不得不提到docker。2013年初,docker橫空出世,孕育著新思想的“容器”,Docker選擇容器作為核心和基礎,以容器為資源分割和排程的基本單位,封裝整個軟體執行時環境,為開發者和系統管理員設計,用於構建、釋出和執行分散式應用的平臺。是一個跨平臺、可移植並且簡單易用的容器解決方案。通過作業系統核心技術(namespaces、cgroups等)為容器提供資源隔離與安全保障。

上圖是一個image的簡單使用。我們可以通過一個dockerfile來build自己的image。可以把image上傳(push)到自己的私有映象倉庫,也可以從私有倉庫pull到本地進行使用。可以單獨使用命令列,直接run container,可以對container進行stop、start、restart操作。也可以對image進行save儲存操作以及載入load操作,大傢俱體可以根據自己的使用,選擇不同的操作即可。

Docker資源隔離技術
Docker選擇容器作為核心和基礎,以容器為資源分割和排程的基本單位,封裝整個軟體執行時環境,為開發者和系統管理員設計,用於構建、釋出和執行分散式應用的平臺。Docker是一個跨平臺、可移植並且簡單易用的容器解決方案, 通過作業系統核心技術(namespaces、cgroups等)為容器提供資源隔離與安全保障。

Docker監控
cAdvisor(Container Advisor)是Google開發的用於分析執行中容器的資源佔用和效能指標的開源工具。cAdvisor是一個執行時的守護程式,負責收集、聚合、處理和輸出執行中容器的資訊。對於每個容器,cAdvisor都有資源隔離引數、資源使用歷史情況以及完整的歷史資源使用和網路統計資訊的柱狀圖。cAdvisor不但可以為使用者提供監控服務,還可以結合其他應用為使用者提供良好的服務移植和定製。包括結合InfluxDB對資料進行儲存,以及結合Grafana提供web控制檯,自定義查詢指標,並進行展示:

etcd: etcd是一個鍵值儲存倉庫,用於配置共享和服務發現。etcd受Zookeeper與doozer啟發而催生的專案。

etcd架構:

etcd儲存
etcd的儲存分為內部儲存和持久化(硬碟)儲存兩部分。記憶體中的儲存除了順序化地記錄所有使用者對節點資料變更的記錄外,還會對使用者資料進行索引、建堆等方便查詢的操作。而持久化則使用WAL進行記錄儲存。在k8s中,所有資料的儲存以及操作記錄都在etcd中進行儲存,所以對於k8s叢集來說,etcd是相當重要的,一旦故障,可能導致整個叢集的癱瘓或者資料丟失。
在WAL體系中,所有的資料在提交之前都會進行日誌記錄。持久化儲存的目錄分為兩個:snap和wal。snapshot相當於資料壓縮,預設會將10000條wal操作記錄merge成snapshot,節省儲存,又保證資料不會丟失。其中:
-   WAL:儲存所有事務的變化記錄
-   Snapshot:用於存放某一時刻etcd所有目錄的資料

etcd核心演算法
etcd的核心演算法是raft演算法,強一致性演算法。具體如下圖所示:

需要注意由於etcd是負責儲存,所以不建議搭建單點叢集,如zookeeper一樣,由於存在選舉策略,所以一般推薦奇數個叢集,如3,5,7。只要叢集半數以上的結點存活,那麼叢集就可以正常執行,否則叢集可能無法正常使用。

五.  Kubernetes 叢集環境部署記錄

Kubernetes (K8s)是docker容器用來編排和管理的工具.

 

通過kubectl向k8s Master發出指令, kubernetes Master主要是提供API Server、Scheduler、Controller元件,接收kubectl的命令,從Node節點獲取Node的資源資訊,併發出排程任務。Node節點提供kubelet、kube-proxy,每個node節點都安裝docker,是實際的執行者。kubernetes不負責網路,所以一般是用flannel或者weave。etcd負責服務發現和node資訊儲存.

kubernetes基本部署步驟
-  node節點安裝docker
-  node節點配置跨主機容器通訊
-  master節點部署etcd、kube-apiserver、kube-controller-manager和kube-scheduler元件
-  node節點部署kubelet、kube-proxy元件

如果minion主機沒有安裝docker,啟動kubelet時會報如下錯誤:
Could not load kubeconfig file /var/lib/kubelet/kubeconfig: stat /var/lib/kubelet/kubeconfig: no such file or directory. Trying auth path instead.
Could not load kubernetes auth path /var/lib/kubelet/kubernetes_auth: stat /var/lib/kubelet/kubernetes_auth: no such file or directory. Continuing with defaults.
No cloud provider specified.

1.  環境準備

ip地址               主機名              節點功能
172.16.60.220       k8s-master01       Master, etcd, registry
172.16.60.221       k8s-node01         Node01
172.16.60.222       k8s-node02         Node02

[root@k8s-master01 ~]# cat /etc/redhat-release 
CentOS Linux release 7.5.1804 (Core) 

設定三個節點的主機名
[root@k8s-master01 ~]# hostnamectl --static set-hostname  k8s-master01
[root@k8s-node01 ~]# hostnamectl --static set-hostname  k8s-node01
[root@k8s-node02 ~]# hostnamectl --static set-hostname  k8s-node02

分別繫結三個節點的hosts 
[root@k8s-master01 ~]# cat /etc/hosts
.........
172.16.60.220    k8s-registry
172.16.60.221    k8s-node01
172.16.60.222    k8s-node02

關閉三臺機器上的防火牆和selinux
[root@k8s-master01 ~]# systemctl disable firewalld.service
[root@k8s-master01 ~]# systemctl stop firewalld.service
[root@k8s-master01 ~]# firewall-cmd --state
not running

[root@k8s-master01 ~]# setenforce 0
[root@k8s-master01 ~]# cat /etc/sysconfig/selinux 
........
SELINUX=disabled

[root@k8s-master01 ~]# getenforce                 
Disabled

2) 部署Mater節點 (172.16.60.220) 

1) 現安裝docker
[root@k8s-master01 ~]# yum install -y docker
 
[root@k8s-master01 ~]# docker --version
Docker version 1.13.1, build 07f3374/1.13.1
 
2) 安裝私有倉庫Registry (實際生產環境下, 私有倉庫Registry可以部署在其他機器上)
[root@k8s-master01 ~]# docker pull registry

順便下載其他幾個docker映象, 用於本案例測試所用
[root@k8s-master01 ~]# docker pull nginx
[root@k8s-master01 ~]# docker pull tomcat
[root@k8s-master01 ~]# docker pull centos

檢視docker映象
[root@k8s-master01 ~]# docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
docker.io/centos     latest              9f38484d220f        11 hours ago        202 MB
docker.io/registry   latest              f32a97de94e1        7 days ago          25.8 MB
docker.io/tomcat     latest              dd6ff929584a        9 days ago          463 MB
docker.io/nginx      latest              881bd08c0b08        10 days ago         109 MB

預設情況下,會將私有倉庫存放於容器內的/tmp/registry目錄下,這樣如果容器被刪除,則存放於容器中的映象也會丟失。
所以一般情況下會指定本地一個目錄掛載到容器內的/tmp/registry下,如下:
[root@k8s-master01 ~]# docker run -d --name=my_registry -p 5000:5000 -v /opt/data/registry:/tmp/registry docker.io/registry
efca665f3395f9148bc1b40287feef4175966b30975d1e1acaffa3909c9e026f

檢視啟動的registry容器
[root@k8s-master01 ~]# docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                    NAMES
efca665f3395        docker.io/registry   "/entrypoint.sh /e..."   17 seconds ago      Up 16 seconds       0.0.0.0:5000->5000/tcp   my_registry

由上可以看到,已經啟動了一個registry私有倉庫容器,地址為:172.16.60.220:5000

接下來可以把本地映象(上面下載的三個映象)push到私有倉庫中 (修改映象的tag標識)
[root@k8s-master01 ~]# docker tag nginx 172.16.60.220:5000/nginx
[root@k8s-master01 ~]# docker tag tomcat 172.16.60.220:5000/tomcat
[root@k8s-master01 ~]# docker tag centos 172.16.60.220:5000/centos

[root@k8s-master01 ~]# docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
172.16.60.220:5000/centos   latest              9f38484d220f        11 hours ago        202 MB
docker.io/centos            latest              9f38484d220f        11 hours ago        202 MB
docker.io/registry          latest              f32a97de94e1        7 days ago          25.8 MB
172.16.60.220:5000/tomcat   latest              dd6ff929584a        9 days ago          463 MB
docker.io/tomcat            latest              dd6ff929584a        9 days ago          463 MB
docker.io/nginx             latest              881bd08c0b08        10 days ago         109 MB
172.16.60.220:5000/nginx    latest              881bd08c0b08        10 days ago         109 MB

接下來把上面修改tag後的映象上傳到私有倉庫
[root@k8s-master01 ~]# docker push 172.16.60.220:5000/nginx
The push refers to a repository [172.16.60.220:5000/nginx]
 
出現上面報錯: 因為docker預設使用https協議,但是本地現在只支援http協議.
為了解決https的報錯, 需要配置daemon.json的insecure-registries, 具體如下:
[root@k8s-master01 ~]# cat /etc/docker/daemon.json             # 預設該配置檔案為空
{}
 
[root@k8s-master01 ~]# vim /etc/docker/daemon.json
{
   "insecure-registries": [
      "172.16.60.220:5000"
    ]
}
 
==================================================================
除了上面的方法外, 還可以在/etc/sysconfig/docker 檔案裡新增"OPTIONS='--insecure-registry 172.16.60.220:5000'"
==================================================================
 
接著重啟docker和registry容器
[root@k8s-master01 ~]# systemctl restart docker
[root@k8s-master01 ~]# docker start my_registry
my_registry
[root@k8s-master01 ~]# docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                    NAMES
dea03edc49fd        docker.io/registry   "/entrypoint.sh /e..."   8 minutes ago       Up 39 seconds       0.0.0.0:5000->5000/tcp   my_registry
 
然後重新將上面修改tag後的映象上傳到私有倉庫
[root@k8s-master01 ~]# docker push 172.16.60.220:5000/tomcat
[root@k8s-master01 ~]# docker push 172.16.60.220:5000/nginx
[root@k8s-master01 ~]# docker push 172.16.60.220:5000/centos

檢視私有倉庫裡的映象(一定要保證下面能檢視到倉庫裡有映象. 如果倉庫裡沒有映象,那麼客戶端機器就無法從該私有倉庫下載映象了)
[root@k8s-master01 ~]# curl -XGET http://172.16.60.220:5000/v2/_catalog
{"repositories":["centos","nginx","tomcat"]}
 
[root@k8s-master01 ~]# curl -XGET http://172.16.60.220:5000/v2/centos/tags/list
{"name":"centos","tags":["latest"]}
 
[root@k8s-master01 ~]# curl -XGET http://172.16.60.220:5000/v2/nginx/tags/list
{"name":"nginx","tags":["latest"]}
 
[root@k8s-master01 ~]# curl -XGET http://172.16.60.220:5000/v2/tomcat/tags/list
{"name":"tomcat","tags":["latest"]}

現在可以將本地的映象刪除,然後測試從私有倉庫中下載
[root@k8s-master01 ~]# docker rmi docker.io/tomcat
[root@k8s-master01 ~]# docker rmi docker.io/nginx
[root@k8s-master01 ~]# docker rmi docker.io/centos
[root@k8s-master01 ~]# docker rmi 172.16.60.220:5000/centos
[root@k8s-master01 ~]# docker rmi 172.16.60.220:5000/nginx
[root@k8s-master01 ~]# docker rmi 172.16.60.220:5000/tomcat
 
[root@k8s-master01 ~]# docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
docker.io/registry   latest              f32a97de94e1        6 days ago          25.8 MB
 
重新從私倉裡下載
[root@k8s-master01 ~]# docker pull 172.16.60.220:5000/nginx
[root@k8s-master01 ~]# docker pull 172.16.60.220:5000/tomcat
[root@k8s-master01 ~]# docker pull 172.16.60.220:5000/centos

[root@k8s-master01 ~]# docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
172.16.60.220:5000/centos   latest              9f38484d220f        11 hours ago        202 MB
docker.io/registry          latest              f32a97de94e1        7 days ago          25.8 MB
172.16.60.220:5000/tomcat   latest              dd6ff929584a        9 days ago          463 MB
172.16.60.220:5000/nginx    latest              881bd08c0b08        10 days ago         109 MB

3) 安裝etcd
k8s執行依賴etcd,需要先部署etcd,下面採用yum方式安裝:
[root@k8s-master01 ~]# yum install -y etcd
 
yum安裝的etcd預設配置檔案在/etc/etcd/etcd.conf,編輯配置檔案:
[root@k8s-master01 ~]# cp /etc/etcd/etcd.conf /etc/etcd/etcd.conf.bak
[root@k8s-master01 ~]# >/etc/etcd/etcd.conf
[root@k8s-master01 ~]# vim /etc/etcd/etcd.conf
#[member]
#節點名稱
ETCD_NAME=k8s-master
#資料存放位置                                                     
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"                 
#ETCD_WAL_DIR=""
#ETCD_SNAPSHOT_COUNT="10000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
#監聽客戶端地址
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001"            
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
#ETCD_CORS=""
#
#[cluster]
#ETCD_INITIAL_ADVERTISE_PEER_URLS="http://localhost:2380"
# if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=http://..."
#ETCD_INITIAL_CLUSTER="default=http://localhost:2380"
#ETCD_INITIAL_CLUSTER_STATE="new"
#ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
#通知客戶端地址
ETCD_ADVERTISE_CLIENT_URLS="http://172.16.60.220:2379,http://172.16.60.220:4001"             
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_SRV=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
 
啟動etcd並驗證狀態
[root@k8s-master01 ~]# systemctl start etcd
 
[root@k8s-master01 ~]# ps -ef|grep etcd      
etcd       977     1  1 12:47 ?        00:00:00 /usr/bin/etcd --name=k8s-master --data-dir=/var/lib/etcd/default.etcd --listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001
root      1467  7564  0 12:47 pts/1    00:00:00 grep --color=auto etcd
 
[root@k8s-master01 ~]# lsof -i:2379          
COMMAND PID USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
etcd    977 etcd    6u  IPv6 259685220      0t0  TCP *:2379 (LISTEN)
etcd    977 etcd   13u  IPv4 259683141      0t0  TCP localhost:54160->localhost:2379 (ESTABLISHED)
etcd    977 etcd   14u  IPv6 259683142      0t0  TCP localhost:2379->localhost:54160 (ESTABLISHED)
 
[root@k8s-master01 ~]# lsof -i:4001          
COMMAND PID USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
etcd    977 etcd    7u  IPv6 259685221      0t0  TCP *:newoak (LISTEN)
etcd    977 etcd   11u  IPv4 259683140      0t0  TCP localhost:56102->localhost:newoak (ESTABLISHED)
etcd    977 etcd   15u  IPv6 259688733      0t0  TCP localhost:newoak->localhost:56102 (ESTABLISHED)
 
測試etcd
[root@k8s-master01 ~]# etcdctl set testdir/testkey0 0
0
[root@k8s-master01 ~]# etcdctl get testdir/testkey0
0
[root@k8s-master01 ~]# etcdctl -C http://172.16.60.220:2379 cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://172.16.60.220:2379
cluster is healthy
 
[root@k8s-master01 ~]# etcdctl -C http://172.16.60.220:4001 cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://172.16.60.220:2379
cluster is healthy
 
4) 安裝kubernets
[root@k8s-master01 ~]# yum install -y kubernetes
 
配置並啟動kubernetes
在kubernetes master上需要執行以下元件:Kubernets API Server、Kubernets Controller Manager、Kubernets Scheduler
 
[root@k8s-master01 ~]# cp /etc/kubernetes/apiserver /etc/kubernetes/apiserver.bak
[root@k8s-master01 ~]# >/etc/kubernetes/apiserver
[root@k8s-master01 ~]# vim /etc/kubernetes/apiserver
###
# kubernetes system config
#
# The following values are used to configure the kube-apiserver
#
    
# The address on the local server to listen to.
KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0"
    
# The port on the local server to listen on.
KUBE_API_PORT="--port=8080"
    
# Port minions listen on
# KUBELET_PORT="--kubelet-port=10250"
    
# Comma separated list of nodes in the etcd cluster
KUBE_ETCD_SERVERS="--etcd-servers=http://172.16.60.220:2379"
    
# Address range to use for services
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=172.16.0.0/16"
    
# default admission control policies
#KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota"
    
# Add your own!
KUBE_API_ARGS=""
 
[root@k8s-master01 ~]# cp /etc/kubernetes/config /etc/kubernetes/config.bak
[root@k8s-master01 ~]# >/etc/kubernetes/config
[root@k8s-master01 ~]# vim /etc/kubernetes/config
###
# kubernetes system config
#
# The following values are used to configure various aspects of all
# kubernetes services, including
#
#   kube-apiserver.service
#   kube-controller-manager.service
#   kube-scheduler.service
#   kubelet.service
#   kube-proxy.service
# logging to stderr means we get it in the systemd journal
KUBE_LOGTOSTDERR="--logtostderr=true"
  
# journal message level, 0 is debug
KUBE_LOG_LEVEL="--v=0"
  
# Should this cluster be allowed to run privileged docker containers
KUBE_ALLOW_PRIV="--allow-privileged=false"
  
# How the controller-manager, scheduler, and proxy find the apiserver
KUBE_MASTER="--master=http://172.16.60.220:8080"
 
啟動服務並設定開機自啟動
[root@k8s-master01 ~]# systemctl enable kube-apiserver.service
[root@k8s-master01 ~]# systemctl start kube-apiserver.service
[root@k8s-master01 ~]# systemctl enable kube-controller-manager.service
[root@k8s-master01 ~]# systemctl start kube-controller-manager.service
[root@k8s-master01 ~]# systemctl enable kube-scheduler.service
[root@k8s-master01 ~]# systemctl start kube-scheduler.service

3) 部署Node節點 (172.16.60.221, 172.16.60.222)

3) 安裝kubernets  (兩個節點同樣操作)
[root@k8s-node01 ~]# yum install kubernetes
 
配置並啟動kubernetes
在kubernetes master上需要執行以下元件:Kubelet、Kubernets Proxy
[root@k8s-node01 ~]# cp /etc/kubernetes/config /etc/kubernetes/config.bak
[root@k8s-node01 ~]# >/etc/kubernetes/config
[root@k8s-node01 ~]# vim /etc/kubernetes/config
###
# kubernetes system config
#
# The following values are used to configure various aspects of all
# kubernetes services, including
#
#   kube-apiserver.service
#   kube-controller-manager.service
#   kube-scheduler.service
#   kubelet.service
#   kube-proxy.service
# logging to stderr means we get it in the systemd journal
KUBE_LOGTOSTDERR="--logtostderr=true"
  
# journal message level, 0 is debug
KUBE_LOG_LEVEL="--v=0"
  
# Should this cluster be allowed to run privileged docker containers
KUBE_ALLOW_PRIV="--allow-privileged=false"
  
# How the controller-manager, scheduler, and proxy find the apiserver
KUBE_MASTER="--master=http://172.16.60.220:8080"
 
[root@k8s-node01 ~]# cp /etc/kubernetes/kubelet /etc/kubernetes/kubelet.bak
[root@k8s-node01 ~]# >/etc/kubernetes/kubelet
[root@k8s-node01 ~]# vim /etc/kubernetes/kubelet
###
# kubernetes kubelet (minion) config
  
# The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces)
KUBELET_ADDRESS="--address=0.0.0.0"
  
# The port for the info server to serve on
# KUBELET_PORT="--port=10250"
  
# You may leave this blank to use the actual hostname
#特別注意這個,在另一個節點上,要改為它的主機名
KUBELET_HOSTNAME="--hostname-override=k8s-node02"                 
  
# location of the api-server
KUBELET_API_SERVER="--api-servers=http://172.16.60.220:8080"
  
# pod infrastructure container
KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"
  
# Add your own!
KUBELET_ARGS=""
 
啟動服務並設定開機自啟動
[root@k8s-node01 ~]# systemctl enable kubelet.service
[root@k8s-node01 ~]# systemctl start kubelet.service
[root@k8s-node01 ~]# systemctl enable kube-proxy.service
[root@k8s-node01 ~]# systemctl start kube-proxy.service

4) 檢視k8s叢集狀態 (在master節點上)

url中使用主機名和ip地址都可以
[root@k8s-master01 ~]# kubectl -s http://172.16.60.220:8080 get node            
NAME         STATUS    AGE
k8s-node01   Ready     2m
k8s-node02   Ready     1m

[root@k8s-master01 ~]# kubectl -s http://k8s-master01:8080 get node 
NAME         STATUS    AGE
k8s-node01   Ready     2m
k8s-node02   Ready     2m

[root@k8s-master01 ~]# kubectl get nodes
NAME         STATUS    AGE
k8s-node01   Ready     2m
k8s-node02   Ready     2m

到這裡, 一個簡單的K8s叢集環境就搭建完成了.

5) 建立覆蓋網路( Flannel) 

1)安裝Flannel(在master、node節點上同樣操作)
[root@k8s-master01 ~]# yum install -y flannel

[root@k8s-master01 ~]# flanneld --version
0.7.1

2)配置Flannel(在master、node節點上同樣操作)
[root@k8s-master01 ~]# cp /etc/sysconfig/flanneld /etc/sysconfig/flanneld.bak
[root@k8s-master01 ~]# >/etc/sysconfig/flanneld
[root@k8s-master01 ~]# vim /etc/sysconfig/flanneld
# Flanneld configuration options
  
# etcd url location.  Point this to the server where etcd runs
FLANNEL_ETCD_ENDPOINTS="http://172.16.60.220:2379"
  
# etcd config key.  This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_PREFIX="/atomic.io/network"
  
# Any additional options that you want to pass
#FLANNEL_OPTIONS=""

3)配置etcd中關於flannel的key(只在master節點上操作)
Flannel使用Etcd進行配置,來保證多個Flannel例項之間的配置一致性,所以需要在etcd上進行如下配置.

注意: 
'/atomic.io/network/config'這個key與上文/etc/sysconfig/flannel中的配置項FLANNEL_ETCD_PREFIX是相對應的,錯誤的話啟動就會出錯!
flannel設定的ip網段可以任意設定,隨便設定一個網段都可以 (但這個ip網段最好別和節點在同一個網段, 否則Flannel服務啟動後, 可能造成節點登入失敗的情況)

容器的ip就是根據這個網段進行自動分配的,ip分配後,容器一般是可以對外聯網的(網橋模式,只要宿主機能上網就可以)

[root@k8s-master01 ~]# etcdctl mk /atomic.io/network/config '{ "Network": "192.168.0.0/16" }'
{ "Network": "192.168.0.0/16" }

[root@k8s-master01 ~]# etcdctl get /atomic.io/network/config
{ "Network": "192.168.0.0/16" }

===========================================================
刪除上面etcd中指定的key
[root@k8s-master01 ~]# etcdctl rm /atomic.io/network/config
PrevNode.Value: { "Network": "192.168.0.0/16" }
===========================================================

4)啟動Flannel
啟動Flannel之後,需要依次重啟docker、kubernete。
啟動Flannel後,一定要記得重啟docker,這樣Flannel配置分配的ip才能生效,即docker0虛擬網路卡的ip會變成上面flannel設定的ip段

master節點啟動Flannel
[root@k8s-master01 ~]# systemctl enable flanneld.service
[root@k8s-master01 ~]# systemctl start flanneld.service        
[root@k8s-master01 ~]# service docker restart                                       
[root@k8s-master01 ~]# docker start my_registry                         # 因為本節點也作為registry私倉節點 (生產環境下, 私倉容器可以部署到其他機器上)
[root@k8s-master01 ~]# systemctl restart kube-apiserver.service
[root@k8s-master01 ~]# systemctl restart kube-controller-manager.service
[root@k8s-master01 ~]# systemctl restart kube-scheduler.service

在兩個node節點上啟動Flannel
[root@k8s-node01 ~]# systemctl enable flanneld.service
[root@k8s-node01 ~]# systemctl start flanneld.service     
[root@k8s-node01 ~]# service docker restart
[root@k8s-node01 ~]# systemctl restart kubelet.service
[root@k8s-node01 ~]# systemctl restart kube-proxy.service

三個節點啟動Flannel服務後, 檢視各自ip地址, 可以看到Flannel地址已經出來了. 如下三個節點的flannel的ip是可以相互ping通的!

master節點地址檢視
[root@k8s-master01 ~]# ifconfig
................
ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.60.220  netmask 255.255.255.0  broadcast 172.16.60.255
...............

flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1472
        inet 192.168.80.0  netmask 255.255.0.0  destination 192.168.80.0
...............

node01節點地址檢視
[root@k8s-node01 ~]# ifconfig
..............
ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.60.221  netmask 255.255.255.0  broadcast 172.16.60.255
.............
flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1472
        inet 192.168.61.0  netmask 255.255.0.0  destination 192.168.61.0
.............

node02節點地址檢視
[root@k8s-node02 ~]# ifconfig
.............
ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.60.222  netmask 255.255.255.0  broadcast 172.16.60.255
............
flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1472
        inet 192.168.100.0  netmask 255.255.0.0  destination 192.168.100.0
............

6)部署nginx pod 和複製器  (在master節點上操作)
以下面的圖來安裝一個簡單的靜態內容的nginx應用:

用複製器啟動一個2個備份的nginx Pod,然後在前面掛Service,一個service只能被叢集內部訪問,一個能被叢集外的節點訪問.

1) 部署nginx pod 和複製器
[root@k8s-master01 ~]# docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
172.16.60.220:5000/centos   latest              9f38484d220f        17 hours ago        202 MB
docker.io/registry          latest              f32a97de94e1        7 days ago          25.8 MB
172.16.60.220:5000/tomcat   latest              dd6ff929584a        10 days ago         463 MB
172.16.60.220:5000/nginx    latest              881bd08c0b08        10 days ago         109 MB

通過下面命令發現apiVersion版本是v1
[root@k8s-master01 ~]# curl -s -L http://172.16.60.220:8080/api/v1beta1/version | python -mjson.tool             
{
    "apiVersion": "v1",
    "code": 404,
    "details": {},
    "kind": "Status",
    "message": "the server could not find the requested resource",
    "metadata": {},
    "reason": "NotFound",
    "status": "Failure"
}

開始建立pod單元 (replicas: 2 表示2個備份)
[root@k8s-master01 ~]# mkdir -p /home/kubermange && cd /home/kubermange
[root@k8s-master01 kubermange]# vim nginx-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx-controller
spec:
  replicas: 2                              
  selector:
    name: nginx
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
        - name: nginx
          image: 172.16.60.220:5000/nginx
          ports:
            - containerPort: 80

執行建立命令
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 create -f nginx-rc.yaml             
replicationcontroller "nginx-controller" created

注意: 
由於kubernetes要在node機器上去gcr.io下載gcr.io/google_containers/pause映象,然後下載nginx映象;
pod配置檔案yaml中的images映象可以提前在node節點機器裡下載好, 這樣建立pod時就會快點;
如果不提前在node節點機器裡下載好, 建立pod時就會去下載, 這樣會耗費點時間;

檢視pods清單 (狀態為run才是正常的, 如果為pulling或者containercreating都是不正常的)
[root@k8s-master01 kubermange]# kubectl get pods  
NAME                     READY     STATUS    RESTARTS   AGE
nginx-controller-d97wj   1/1       ContainerCreating   0          15s
nginx-controller-lf11n   1/1       ContainerCreating   0          15s

[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 get pods 
NAME                     READY     STATUS    RESTARTS   AGE
nginx-controller-d97wj   1/1       ContainerCreating   0          39s
nginx-controller-lf11n   1/1       ContainerCreating   0          39s

可以使用describe 命令檢視pod所分到的節點 (注意後面pod的name, 可以在pods清單查詢結果中找到)
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 describe pod nginx-controller-d97wj
Name:           nginx-controller-d97wj
Namespace:      default
Node:           k8s-node01/172.16.60.222
Start Time:     Fri, 15 Mar 2019 11:54:38 +0800
Labels:         name=nginx
Status:         Pending
IP:
Controllers:    ReplicationController/nginx-controller
Containers:
  nginx:
    Container ID:
    Image:                      172.16.60.220:5000/nginx
    Image ID:
    Port:                       80/TCP
    State:                      Waiting
      Reason:                   ContainerCreating
    Ready:                      False
    Restart Count:              0
    Volume Mounts:              <none>
    Environment Variables:      <none>
Conditions:
  Type          Status
  Initialized   True 
  Ready         False 
  PodScheduled  True 
No volumes.
QoS Class:      BestEffort
Tolerations:    <none>
Events:
  FirstSeen     LastSeen        Count   From                    SubObjectPath   Type            Reason          Message
  ---------     --------        -----   ----                    -------------   --------        ------          -------
  2h            58s             39      {kubelet k8s-node01}                    Warning         FailedSync      Error syncing pod, skipping: failed to "StartContainer" for "POD" with ErrImagePull: "image pull failed for registry.access.redhat.com/rhel7/pod-infrastructure:latest, this may be because there are no credentials on this request.  details: (open /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt: no such file or directory)"

  2h    5s      774     {kubelet k8s-node01}            Warning FailedSync      Error syncing pod, skipping: failed to "StartContainer" for "POD" with ImagePullBackOff: "Back-off pulling image \"registry.access.redhat.com/rhel7/pod-infrastructure:latest\""

如上發現了兩個報錯:
一. 通過yaml建立了pod,檢視pods清單的時候("kubectl get pods")一直是ContainerCreating狀態。
二. 使用describe 命令檢視pod所分到的節點時, 發現如下報錯:
Error syncing pod, skipping: failed to "StartContainer" for "POD" with ErrImagePull: "image pull failed for 
registry.access.redhat.com/rhel7/pod-infrastructure:latest, this may be because there are no credentials on this request.  
details: (open /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt: no such file or directory)"

Error syncing pod, skipping: failed to "StartContainer" for "POD" with ImagePullBackOff: "Back-off pulling image 
\"registry.access.redhat.com/rhel7/pod-infrastructure:latest\""

發現docker從registry.access.redhat.com/rhel7/pod-infrastructure:latest  拉去映象報錯!並提示:
details: (open /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt: no such file or directory)"

這是因為kubernetes在兩個node節點上會自動去gcr.io下載gcr.io/google_containers/pause映象失敗, 可以手動執行下下載
[root@k8s-node01 ~]# docker pull registry.access.redhat.com/rhel7/pod-infrastructure:latest
Trying to pull repository registry.access.redhat.com/rhel7/pod-infrastructure ... 
open /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt: no such file or directory

解決辦法:
在pod所在的兩個node節點上, 使用ls檢視改檔案是個軟連線,連結目標是/etc/rhsm/ca/redhat-uep.pem不存在, 這是因為沒有rhsm
[root@k8s-node01 ~]# ll /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt 
lrwxrwxrwx 1 root root 27 Mar 14 09:16 /etc/docker/certs.d/registry.access.redhat.com/redhat-ca.crt -> /etc/rhsm/ca/redhat-uep.pem

[root@k8s-node01 ~]# ll /etc/rhsm/ca
[root@k8s-node01 ~]# ll /etc/rhsm/ca/redhat-uep.pem
ls: cannot access /etc/rhsm/ca/redhat-uep.pem: No such file or directory

在兩個node節點上安裝rhsm . 記住: 一定要在pod所在的node節點上安裝rhsm!!!!!
[root@k8s-node01 ~]# yum install *rhsm*

如果在兩個node節點安裝rhsm後, 還是不行!
[root@k8s-master01 kubermange]# kubectl get pods
NAME                     READY     STATUS              RESTARTS   AGE
nginx-controller-d97wj   0/1       ContainerCreating   0          3h
nginx-controller-lf11n   0/1       ContainerCreating   0          3h

這是因為gcr.io被牆了,可以在pod所在的兩個node節點上kubelet配置檔案/etc/kubernetes/kubelet里加上一個引數:
--pod-infra-container-image來指定一個國內的映象。 做法如下:
[root@k8s-node01 ~]# cp /etc/kubernetes/kubelet /etc/kubernetes/kubelet.bak2
[root@k8s-node01 ~]# vim /etc/kubernetes/kubelet
...................
KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.aliyuncs.com/archon/pause-amd64:3.0"

[root@k8s-node01 ~]# diff /etc/kubernetes/kubelet /etc/kubernetes/kubelet.bak2  
18c18
< KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.aliyuncs.com/archon/pause-amd64:3.0"
---
> KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"

接著重啟kubelet.service
[root@k8s-node01 ~]# systemctl restart kubelet.service

注意:上面操作需要再pod所在的node上進行!

然後在master節點上, 檢視pods清單,  注意觀察, 過一會兒後, 發現pods狀態就會由"ContainerCreating" 變為 "Running"
[root@k8s-master01 kubermange]# kubectl get pods  
NAME                     READY     STATUS    RESTARTS   AGE
nginx-controller-d97wj   1/1       Running   0          2m
nginx-controller-lf11n   1/1       Running   0          2m

最後再使用describe 命令檢視pod所分到的節點

先檢視第一個pods所在的node節點情況
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 describe pod nginx-controller-d97wj
Name:           nginx-controller-d97wj
Namespace:      default
Node:           k8s-node02/172.16.60.222
Start Time:     Fri, 15 Mar 2019 22:40:18 +0800
Labels:         name=nginx
Status:         Running
IP:             192.168.100.2
Controllers:    ReplicationController/nginx-controller
Containers:
  nginx:
    Container ID:               docker://8ae4502b4e62120322de98aa532e653d3d2e058ffbb0b842e0f265621bebbe61
    Image:                      172.16.60.220:5000/nginx
    Image ID:                   docker-pullable://172.16.60.220:5000/nginx@sha256:7734a210432278817f8097acf2f72d20e2ccc7402a0509810c44b3a8bfe0094a
    Port:                       80/TCP
    State:                      Running
      Started:                  Fri, 15 Mar 2019 22:40:19 +0800
    Ready:                      True
    Restart Count:              0
    Volume Mounts:              <none>
    Environment Variables:      <none>
Conditions:
  Type          Status
  Initialized   True 
  Ready         True 
  PodScheduled  True 
No volumes.
QoS Class:      BestEffort
Tolerations:    <none>
Events:
  FirstSeen     LastSeen        Count   From                    SubObjectPath           Type            Reason                  Message
  ---------     --------        -----   ----                    -------------           --------        ------                  -------
  1m            1m              1       {default-scheduler }                            Normal          Scheduled               Successfully assigned nginx-controller-d97wj to k8s-node02
  1m            1m              2       {kubelet k8s-node02}                            Warning         MissingClusterDNS       kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. Falling back to DNSDefault policy.
  1m            1m              1       {kubelet k8s-node02}    spec.containers{nginx}  Normal          Pulling                 pulling image "172.16.60.220:5000/nginx"
  1m            1m              1       {kubelet k8s-node02}    spec.containers{nginx}  Normal          Pulled                  Successfully pulled image "172.16.60.220:5000/nginx"
  1m            1m              1       {kubelet k8s-node02}    spec.containers{nginx}  Normal          Created                 Created container with docker id 8ae4502b4e62; Security:[seccomp=unconfined]
  1m            1m              1       {kubelet k8s-node02}    spec.containers{nginx}  Normal          Started                 Started container with docker id 8ae4502b4e62

此時, 上面資訊中的warning和error可以忽略, 後面三行出現了"Successfully, Created, Started"
檢視到的pods清單中的狀態是"Running"就可以了

再檢視另一個pod所在node節點情況
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 describe pod nginx-controller-lf11n
Name:           nginx-controller-lf11n
Namespace:      default
Node:           k8s-node01/172.16.60.221
Start Time:     Fri, 15 Mar 2019 22:40:18 +0800
Labels:         name=nginx
Status:         Running
IP:             192.168.61.2
Controllers:    ReplicationController/nginx-controller
Containers:
  nginx:
    Container ID:               docker://649b228b6b541a6124d98480193541782f28fd238b1ecb6c4b8812bb369d4b79
    Image:                      172.16.60.220:5000/nginx
    Image ID:                   docker-pullable://172.16.60.220:5000/nginx@sha256:7734a210432278817f8097acf2f72d20e2ccc7402a0509810c44b3a8bfe0094a
    Port:                       80/TCP
    State:                      Running
      Started:                  Fri, 15 Mar 2019 22:40:19 +0800
    Ready:                      True
    Restart Count:              0
    Volume Mounts:              <none>
    Environment Variables:      <none>
Conditions:
  Type          Status
  Initialized   True 
  Ready         True 
  PodScheduled  True 
No volumes.
QoS Class:      BestEffort
Tolerations:    <none>
Events:
  FirstSeen     LastSeen        Count   From                    SubObjectPath           Type            Reason                  Message
  ---------     --------        -----   ----                    -------------           --------        ------                  -------
  4m            4m              1       {default-scheduler }                            Normal          Scheduled               Successfully assigned nginx-controller-lf11n to k8s-node01
  4m            4m              2       {kubelet k8s-node01}                            Warning         MissingClusterDNS       kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. Falling back to DNSDefault policy.
  4m            4m              1       {kubelet k8s-node01}    spec.containers{nginx}  Normal          Pulling                 pulling image "172.16.60.220:5000/nginx"
  4m            4m              1       {kubelet k8s-node01}    spec.containers{nginx}  Normal          Pulled                  Successfully pulled image "172.16.60.220:5000/nginx"
  4m            4m              1       {kubelet k8s-node01}    spec.containers{nginx}  Normal          Created                 Created container with docker id 649b228b6b54; Security:[seccomp=unconfined]
  4m            4m              1       {kubelet k8s-node01}    spec.containers{nginx}  Normal          Started                 Started container with docker id 649b228b6b54

通過上面可以看到, 這個複製器啟動了兩個Pod,分別執行在k8s-node01和k8s-node02這兩個節點上了。
到這兩個節點上檢視,發現已經有nginx應用容器建立了。

k8s-node01節點上檢視
[root@k8s-node01 ~]# docker ps
CONTAINER ID        IMAGE                                          COMMAND                  CREATED             STATUS              PORTS               NAMES
649b228b6b54        172.16.60.220:5000/nginx                       "nginx -g 'daemon ..."   5 minutes ago       Up 5 minutes                            k8s_nginx.fc4d011b_nginx-controller-lf11n_default_411e0ff1-4730-11e9-9580-005056881e0f_80f4d28a
3918206c4d03        registry.aliyuncs.com/archon/pause-amd64:3.0   "/pause"                 5 minutes ago       Up 5 minutes                            k8s_POD.4d6004a4_nginx-controller-lf11n_default_411e0ff1-4730-11e9-9580-005056881e0f_6a6c4e65

k8s-node02節點上檢視
[root@k8s-node02 ~]# docker ps
CONTAINER ID        IMAGE                                          COMMAND                  CREATED             STATUS              PORTS               NAMES
8ae4502b4e62        172.16.60.220:5000/nginx                       "nginx -g 'daemon ..."   6 minutes ago       Up 6 minutes                            k8s_nginx.fc4d011b_nginx-controller-d97wj_default_411e034e-4730-11e9-9580-005056881e0f_a30d6956
d8662e6fc177        registry.aliyuncs.com/archon/pause-amd64:3.0   "/pause"                 6 minutes ago       Up 6 minutes                            k8s_POD.4d6004a4_nginx-controller-d97wj_default_411e034e-4730-11e9-9580-005056881e0f_245b70ac

=========================================================================
溫馨提示: 
如果需要重建pod, 則只需要執行下面刪除yaml檔案命令 (執行後, 對應的pods就會被刪除, 但yaml配置檔案還是存在的)
[root@k8s-master01 kubermange]# kubectl delete -f nginx-rc.yaml 
replicationcontroller "nginx-controller" deleted
[root@k8s-master01 kubermange]# kubectl get pods
No resources found.
[root@k8s-master01 kubermange]# ls
nginx-rc.yaml

如果不刪除對應的yaml檔案, 僅僅刪除pods是不行的, 因為刪除之後還會自動建立
[root@k8s-master01 kubermange]# kubectl get pods
NAME                     READY     STATUS              RESTARTS   AGE
nginx-controller-3jr6p   0/1       Running   0          1m
nginx-controller-d3qlg   0/1       Running   0          1m
[root@k8s-master01 kubermange]# kubectl delete po nginx-controller-3jr6p
pod "nginx-controller-3jr6p" deleted
[root@k8s-master01 kubermange]# kubectl delete po nginx-controller-d3qlg
pod "nginx-controller-d3qlg" deleted
[root@k8s-master01 kubermange]# kubectl get pods
NAME                     READY     STATUS              RESTARTS   AGE
nginx-controller-3jr6p   0/1       Running   0          1m
nginx-controller-d3qlg   0/1       Running   0          1m
=======================================================================

2) 部署節點內部可訪問的nginx service

Service的type有ClusterIP和NodePort之分,預設是ClusterIP,這種型別的Service只能在叢集內部訪問。
配置檔案如下:
[root@k8s-master01 kubermange]# vim nginx-service-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-clusterip
spec:
  ports:
    - port: 8001
      targetPort: 80
      protocol: TCP
  selector:
    name: nginx

然後執行下面的命令建立service:
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 create -f ./nginx-service-clusterip.yaml             
service "nginx-service-clusterip" created

[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 get service
NAME                      CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes                172.16.0.1      <none>        443/TCP    1d
nginx-service-clusterip   172.16.77.193   <none>        8001/TCP   8s

接下來可以進行驗證service的可訪問性(訪問節點):
上面的輸出告訴我們這個Service的Cluster IP是172.16.77.193,埠是8001。

那麼現在可以到pod所在的node節點上進行驗證這個PortalNet IP的工作情況.
先到ks8-node01節點上進行驗證:
[root@k8s-node01 ~]# curl -s 172.16.77.193:8001
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

然後到node02節點上驗證
[root@k8s-node02 ~]# curl -s 172.16.77.193:8001
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

由此可見,從前面部署複製器的部分可以知道nginx Pod執行在k8s-node01和k8s-node02這兩個節點上。
從這兩個節點上訪問我們的服務來體現Service Cluster IP在所有叢集節點的可到達性。

接著可以建立NodePort型別的Service,這種型別的Service在叢集外部是可以訪問。下面是本案例用的配置檔案:
[root@k8s-master01 kubermange]# pwd
/home/kubermange
[root@k8s-master01 kubermange]# vim nginx-service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-nodeport
spec:
  ports:
    - port: 8000
      targetPort: 80
      protocol: TCP
  type: NodePort
  selector:
    name: nginx

執行下面的命令建立service:
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 create -f ./nginx-service-nodeport.yaml             
service "nginx-service-nodeport" created

[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 get service  
NAME                      CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes                172.16.0.1      <none>        443/TCP          1d
nginx-service-clusterip   172.16.77.193   <none>        8001/TCP         11m
nginx-service-nodeport    172.16.234.94   <nodes>       8000:32172/TCP   7s

使用下面的命令獲得這個service的節點級別的埠:
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 describe service nginx-service-nodeport 2>/dev/null | grep NodePort 
Type:                   NodePort
NodePort:               <unset> 32172/TCP

驗證nginx的service的可訪問性(在master節點訪問兩個node節點的32172埠)
訪問第一個node節點地址
[root@k8s-master01 kubermange]# curl 172.16.60.221:32172
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

訪問第二個node節點地址
[root@k8s-master01 kubermange]# curl 172.16.60.222:32172
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

可以在瀏覽器裡分別輸入: http://172.16.60.221:32172 或者 http://172.16.60.222:32172 都可以訪問nginx!

                                                                                其他補充說明                          

->  基於上面的實驗環境,可以擴容nginx應用容器,依次新增對應的應用容器的pod、service-clusterip、service-nodeport的yaml檔案即可。注意yaml檔案中的name名。
->  也可以新增其他應用容器,比如tomcat,也是依次建立pod、service-clusterip、service-nodeport的yaml檔案。注意yaml檔案中的name名和port埠不要重複!
->  後面應用容器的叢集環境完成後(外部可訪問的埠是固定的),可以考慮做下master控制機的叢集環境(即做etcd叢集)。可以在控制節點做負載均衡,還可以通過keepalived做高可用。

======================================================   ==========
下面貼出一個基於tomcat的pods應用容器的3個yaml檔案

[root@k8s-master01 kubermange]# pwd
/home/kubermange

1) 開始建立pod單元 (replicas: 2 表示2個備份)
[root@k8s-master01 kubermange]# vim tomcat-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: tomcat-controller
spec:
  replicas: 2                              
  selector:
    name: tomcat
  template:
    metadata:
      labels:
        name: tomcat
    spec:
      containers:
        - name: tomcat
          image: 172.16.60.220:5000/tomcat
          ports:
            - containerPort: 8080

執行建立命令
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 create -f tomcat-rc.yaml 
replicationcontroller "tomcat-controller" created

================================================================================
如果上面命令在建立過程出現報錯: 
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 create -f tomcat-rc.yaml 
error: error validating "tomcat-rc.yaml": error validating data: expected type int, for field spec.template.spec.containers[0].ports[0].containerPort, got string; if you choose to ignore these errors, turn validation off with --validate=false

如果遇到上面的問題, 都是因為格式問題造成的!!!!!  因為kubernetes複製時,空格或製表符都是很嚴格的!!!!!

解決辦法: 因為之前的nginx-rc.yaml配置格式正確, 可以複製它的內容到tomcat-rc.yaml, 然後修改內容
[root@k8s-master01 kubermange]# sed -i 's/nginx/tomcat/g' tomcat-rc.yaml
[root@k8s-master01 kubermange]# sed -i 's/80/8080/g' tomcat-rc.yaml
================================================================================

檢視pods清單
[root@k8s-master01 kubermange]# kubectl get pods 
NAME                      READY     STATUS    RESTARTS   AGE
nginx-controller-d97wj    1/1       Running   0          1h
nginx-controller-lf11n    1/1       Running   0          1h
tomcat-controller-35kzb   1/1       Running   0          2m
tomcat-controller-lsph4   1/1       Running   0          2m

檢視兩個node節點, 發現tomcat的兩個pods已經分佈到兩個node節點上了
[root@k8s-node01 ~]# docker ps
CONTAINER ID        IMAGE                                          COMMAND                  CREATED             STATUS              PORTS               NAMES
d71e6a1cbd27        172.16.60.220:5000/tomcat                      "catalina.sh run"        3 minutes ago       Up 3 minutes                            k8s_tomcat.904d024b_tomcat-controller-35kzb_default_7f5801aa-4738-11e9-9580-005056881e0f_74533613
53ca4f24afa7        registry.aliyuncs.com/archon/pause-amd64:3.0   "/pause"                 3 minutes ago       Up 3 minutes                            k8s_POD.bcb5050c_tomcat-controller-35kzb_default_7f5801aa-4738-11e9-9580-005056881e0f_351ec586
649b228b6b54        172.16.60.220:5000/nginx                       "nginx -g 'daemon ..."   About an hour ago   Up About an hour                        k8s_nginx.fc4d011b_nginx-controller-lf11n_default_411e0ff1-4730-11e9-9580-005056881e0f_80f4d28a
3918206c4d03        registry.aliyuncs.com/archon/pause-amd64:3.0   "/pause"                 About an hour ago   Up About an hour                        k8s_POD.4d6004a4_nginx-controller-lf11n_default_411e0ff1-4730-11e9-9580-005056881e0f_6a6c4e65

[root@k8s-node02 ~]# docker ps
CONTAINER ID        IMAGE                                          COMMAND                  CREATED             STATUS              PORTS               NAMES
366a61005aa3        172.16.60.220:5000/tomcat                      "catalina.sh run"        3 minutes ago       Up 3 minutes                            k8s_tomcat.904d024b_tomcat-controller-lsph4_default_7f57f713-4738-11e9-9580-005056881e0f_d54a2615
64960d85f490        registry.aliyuncs.com/archon/pause-amd64:3.0   "/pause"                 3 minutes ago       Up 3 minutes                            k8s_POD.bcb5050c_tomcat-controller-lsph4_default_7f57f713-4738-11e9-9580-005056881e0f_cb166baa
8ae4502b4e62        172.16.60.220:5000/nginx                       "nginx -g 'daemon ..."   About an hour ago   Up About an hour                        k8s_nginx.fc4d011b_nginx-controller-d97wj_default_411e034e-4730-11e9-9580-005056881e0f_a30d6956
d8662e6fc177        registry.aliyuncs.com/archon/pause-amd64:3.0   "/pause"                 About an hour ago   Up About an hour                        k8s_POD.4d6004a4_nginx-controller-d97wj_default_411e034e-4730-11e9-9580-005056881e0f_245b70ac

2) 建立ClusterIP型別的Service
[root@k8s-master01 kubermange]# vim tomcat-service-clusterip.yaml 
apiVersion: v1
kind: Service
metadata:
  name: tomcat-service-clusterip
spec:
  ports:
    - port: 8801
      targetPort: 8080
      protocol: TCP
  selector:
    name: tomcat

建立service:
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 create -f tomcat-service-clusterip.yaml
service "tomcat-service-clusterip" created

[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 get service 
NAME                       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes                 172.16.0.1       <none>        443/TCP          1d
nginx-service-clusterip    172.16.77.193    <none>        8001/TCP         56m
nginx-service-nodeport     172.16.234.94    <nodes>       8000:32172/TCP   44m
tomcat-service-clusterip   172.16.144.116   <none>        8801/TCP         11s

可知, tomcat的service的clusterip是172.16.144.116, 埠是8801
分別到node01和node02節點上訪問clusterip, 就可以訪問到tomcat容器了
[root@k8s-node01 ~]# curl -s 172.16.144.116:8801
[root@k8s-node02 ~]# curl -s 172.16.144.116:8801

3) 建立NodePort型別的Service,這種型別的Service在叢集外部是可以訪問
[root@k8s-master01 kubermange]# vim tomcat-service-nodeport.yaml 
apiVersion: v1
kind: Service
metadata:
  name: tomcat-service-nodeport
spec:
  ports:
    - port: 8880
      targetPort: 8080
      protocol: TCP
  type: NodePort
  selector:
    name: tomcat

建立service
[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 create -f tomcat-service-nodeport.yaml 
service "tomcat-service-nodeport" created

[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 get service 
NAME                       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes                 172.16.0.1       <none>        443/TCP          1d
nginx-service-clusterip    172.16.77.193    <none>        8001/TCP         59m
nginx-service-nodeport     172.16.234.94    <nodes>       8000:32172/TCP   48m
tomcat-service-clusterip   172.16.144.116   <none>        8801/TCP         3m
tomcat-service-nodeport    172.16.183.234   <nodes>       8880:31960/TCP   23s

[root@k8s-master01 kubermange]# kubectl -s http://172.16.60.220:8080 describe service tomcat-service-nodeport 2>/dev/null | grep NodePort
Type:                   NodePort
NodePort:               <unset> 31960/TCP

驗證tomcat的service的可訪問性(在master節點訪問兩個node節點的31960埠)
[root@k8s-master01 kubermange]# curl 172.16.60.221:31960
[root@k8s-master01 kubermange]# curl 172.16.60.222:31960

可以在瀏覽器裡分別輸入: http://172.16.60.221:31960 或者 http://172.16.60.222:31960 都可以訪問tomcat!

9) K8s常用運維命令

一. 檢視叢集資訊
[root@k8s-master01 ~]# kubectl cluster-info
[root@k8s-master01 ~]# kubectl cluster-info dump
 
二. 檢視各元件狀態
[root@k8s-master01 ~]# kubectl -s http://localhost:8080 get componentstatuses
NAME                 STATUS    MESSAGE             ERROR
controller-manager   Healthy   ok                 
scheduler            Healthy   ok                 
etcd-0               Healthy   {"health":"true"}  
 
或者
[root@k8s-master01 ~]# kubectl -s http://172.16.60.220:8080 get componentstatuses
NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok                 
controller-manager   Healthy   ok                 
etcd-0               Healthy   {"health":"true"} 
 
三. GET資訊
 
1) 檢視節點 (k8s-master01 對應的是 172.16.60.220的主機名)
[root@k8s-master01 ~]# kubectl get node                                #將命令中的node變為nodes也是可以的
NAME         STATUS    AGE
k8s-node01   Ready     1d
k8s-node02   Ready     1d
 
[root@k8s-master01 ~]# kubectl -s http://k8s-master01:8080 get node    #將命令中的node變為nodes也是可以的
NAME         STATUS    AGE
k8s-node01   Ready     1d
k8s-node02   Ready     1d
 
2) 檢視pods清單
[root@k8s-master01 ~]# kubectl get pod                            #將命令中的pod變為pods也是可以的                  
NAME                      READY     STATUS    RESTARTS   AGE
nginx-controller-d97wj    1/1       Running   0          1h
nginx-controller-lf11n    1/1       Running   0          1h
tomcat-controller-35kzb   1/1       Running   0          18m
tomcat-controller-lsph4   1/1       Running   0          18m
 
[root@k8s-master01 ~]# kubectl -s http://k8s-master01:8080 get pod          #將命令中的pod變為pods也是可以的  
NAME                      READY     STATUS    RESTARTS   AGE
nginx-controller-d97wj    1/1       Running   0          1h
nginx-controller-lf11n    1/1       Running   0          1h
tomcat-controller-35kzb   1/1       Running   0          18m
tomcat-controller-lsph4   1/1       Running   0          18m
 
3) 檢視service清單
[root@k8s-master01 ~]# kubectl get service                                             #將命令中的service變為services也是可以的 
NAME                       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes                 172.16.0.1       <none>        443/TCP          1d
nginx-service-clusterip    172.16.77.193    <none>        8001/TCP         1h
nginx-service-nodeport     172.16.234.94    <nodes>       8000:32172/TCP   59m
tomcat-service-clusterip   172.16.144.116   <none>        8801/TCP         14m
tomcat-service-nodeport    172.16.183.234   <nodes>       8880:31960/TCP   11m
 
[root@k8s-master01 ~]# kubectl -s http://172.16.60.220:8080 get service               #將命令中的service變為services也是可以的
NAME                       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes                 172.16.0.1       <none>        443/TCP          1d
nginx-service-clusterip    172.16.77.193    <none>        8001/TCP         1h
nginx-service-nodeport     172.16.234.94    <nodes>       8000:32172/TCP   1h
tomcat-service-clusterip   172.16.144.116   <none>        8801/TCP         17m
tomcat-service-nodeport    172.16.183.234   <nodes>       8880:31960/TCP   14m
 
或者  (後面的sed表示 列印奇數行)
[root@k8s-master01 ~]# kubectl get services -o json|grep '"name":'|sed -n '1~2p'
                "name": "kubernetes",
                "name": "nginx-service-clusterip",
                "name": "nginx-service-nodeport",
                "name": "tomcat-service-clusterip",
                "name": "tomcat-service-nodeport",
 
4) 檢視replicationControllers清單 (同理可以將命令中的replicationControllers變為replicationController也是可以的)
[root@k8s-master01 ~]# kubectl get replicationControllers
NAME                DESIRED   CURRENT   READY     AGE
nginx-controller    2         2         2         2h
tomcat-controller   2         2         2         1h
 
[root@k8s-master01 ~]# kubectl -s http://172.16.60.220:8080 get replicationControllers
NAME                DESIRED   CURRENT   READY     AGE
nginx-controller    2         2         2         2h
tomcat-controller   2         2         2         1h
 
5) 檢視rc和namespace
[root@k8s-master01 ~]# kubectl get rc,namespace
NAME                   DESIRED   CURRENT   READY     AGE
rc/nginx-controller    2         2         2         2h
rc/tomcat-controller   2         2         2         1h
 
NAME             STATUS    AGE
ns/default       Active    1d
ns/kube-system   Active    1d
 
6) 檢視pod和svc(和service一樣)
[root@k8s-master01 ~]# kubectl get pods,svc
NAME                         READY     STATUS    RESTARTS   AGE
po/nginx-controller-d97wj    1/1       Running   0          2h
po/nginx-controller-lf11n    1/1       Running   0          2h
po/tomcat-controller-35kzb   1/1       Running   0          1h
po/tomcat-controller-lsph4   1/1       Running   0          1h
 
NAME                           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
svc/kubernetes                 172.16.0.1       <none>        443/TCP          1d
svc/nginx-service-clusterip    172.16.77.193    <none>        8001/TCP         2h
svc/nginx-service-nodeport     172.16.234.94    <nodes>       8000:32172/TCP   2h
svc/tomcat-service-clusterip   172.16.144.116   <none>        8801/TCP         1h
svc/tomcat-service-nodeport    172.16.183.234   <nodes>       8880:31960/TCP   1h
 
7) 以jison格式輸出pod的詳細資訊.
[root@k8s-master01 ~]# kubectl get pods
NAME                      READY     STATUS    RESTARTS   AGE
nginx-controller-d97wj    1/1       Running   0          2h
nginx-controller-lf11n    1/1       Running   0          2h
tomcat-controller-35kzb   1/1       Running   0          1h
tomcat-controller-lsph4   1/1       Running   0          1h
 
注意下面命令中的pods的名稱可以通過上面命令檢視
[root@k8s-master01 ~]# kubectl get po nginx-controller-d97wj -o json
{
    "apiVersion": "v1",
    "kind": "Pod",
    "metadata": {
        "annotations": {
...................
...................
        "hostIP": "172.16.60.222",
        "phase": "Running",
        "podIP": "192.168.100.2",
        "startTime": "2019-03-15T14:40:18Z"
    }
}
 
還可以輸出其它格式和方法(kubectl get -h檢視幫助)
[root@k8s-master01 ~]# kubectl get -h
 
8) 檢視指定pod跑在哪個node上
[root@k8s-master01 ~]# kubectl get po nginx-controller-d97wj -o wide    
NAME                     READY     STATUS    RESTARTS   AGE       IP              NODE
nginx-controller-d97wj   1/1       Running   0          2h        192.168.100.2   k8s-node02
 
9) 獲取指定json或ymal格式的KEY資料,custom-columns=XXXXX(自定義列名):.status.hostIP(以“點開始”,然後寫路徑就可以)
注意: 下面命令中的nginx-controller-d97wj是pod單元名稱 (kubectl get pods 可以檢視pods)
[root@k8s-master01 ~]# kubectl get po nginx-controller-d97wj -o custom-columns=HOST-IP:.status.hostIP,POD-IP:.status.podIP    
HOST-IP         POD-IP
172.16.60.222   192.168.100.2
 
10) describe方法
describe類似於get,同樣用於獲取resource的相關資訊。不同的是,get獲得的是更詳細的resource個性的詳細資訊,describe獲得的是resource叢集相關的資訊。
describe命令同get類似,但是describe不支援-o選項,對於同一型別resource,describe輸出的資訊格式,內容域相同。
  
需要注意:  如果發現是查詢某個resource的資訊,使用get命令能夠獲取更加詳盡的資訊。但是如果想要查詢某個resource的狀態,如某個pod並不是在running狀態,
這時需要獲取更詳盡的狀態資訊時,就應該使用describe命令。
 
[root@k8s-master01 ~]# kubectl describe po nginx-controller-d97wj
Name:           nginx-controller-d97wj
Namespace:      default
Node:           k8s-node02/172.16.60.222
Start Time:     Fri, 15 Mar 2019 22:40:18 +0800
Labels:         name=nginx
Status:         Running
IP:             192.168.100.2
Controllers:    ReplicationController/nginx-controller
Containers:
  nginx:
    Container ID:               docker://8ae4502b4e62120322de98aa532e653d3d2e058ffbb0b842e0f265621bebbe61
    Image:                      172.16.60.220:5000/nginx
    Image ID:                   docker-pullable://172.16.60.220:5000/nginx@sha256:7734a210432278817f8097acf2f72d20e2ccc7402a0509810c44b3a8bfe0094a
    Port:                       80/TCP
    State:                      Running
      Started:                  Fri, 15 Mar 2019 22:40:19 +0800
    Ready:                      True
    Restart Count:              0
    Volume Mounts:              <none>
    Environment Variables:      <none>
Conditions:
  Type          Status
  Initialized   True
  Ready         True
  PodScheduled  True
No volumes.
QoS Class:      BestEffort
Tolerations:    <none>
No events.
 
11) create建立
kubectl命令用於根據檔案或輸入建立叢集resource。如果已經定義了相應resource的yaml或son檔案,直接kubectl create -f filename即可建立檔案內定義的
resource。也可以直接只用子命令[namespace/secret/configmap/serviceaccount]等直接建立相應的resource。從追蹤和維護的角度出發,建議使用json或
yaml的方式定義資源。
  
命令格式:
# kubectl create -f 檔名
  
12) replace更新替換資源
replace命令用於對已有資源進行更新、替換。如前面create中建立的nginx,當我們需要更新resource的一些屬性的時候,如果修改副本數量,增加、修改label,
更改image版本,修改埠等。都可以直接修改原yaml檔案,然後執行replace命令。
  
需要注意: 名字不能被更更新。另外,如果是更新label,原有標籤的pod將會與更新label後的rc斷開聯絡,有新label的rc將會建立指定副本數的新的pod,但是預設
並不會刪除原來的pod。所以此時如果使用get po將會發現pod數翻倍,進一步check會發現原來的pod已經不會被新rc控制,此處只介紹命令不詳談此問題,好奇者可自行實驗。
  
命令格式:
# kubectl replace -f nginx-rc.yaml
  
13) patch
如果一個容器已經在執行,這時需要對一些容器屬性進行修改,又不想刪除容器,或不方便通過replace的方式進行更新。kubernetes還提供了一種在容器執行時,直接
對容器進行修改的方式,就是patch命令。 如建立pod的label是app=nginx-2,如果在執行過程中,需要把其label改為app=nginx-3。
這個patch命令如下:
[root@k8s-master01 ~]# kubectl patch pod nginx-controller-d97wj -p '{"metadata":{"labels":{"app":"nginx-3"}}}'
"nginx-controller-d97wj" patched
 
14) edit
edit提供了另一種更新resource源的操作,通過edit能夠靈活的在一個common的resource基礎上,發展出更過的significant resource。
例如,使用edit直接更新前面建立的pod的命令為:
# kubectl edit po nginx-controller-d97wj
  
上面命令的效果等效於:
# kubectl get po nginx-controller-d97wj -o yaml >> /tmp/nginx-tmp.yaml
# vim /tmp/nginx-tmp.yaml             // 這此檔案裡做一些修改
# kubectl replace -f /tmp/nginx-tmp.yaml
  
15) Delete
根據resource名或label刪除resource。
# kubectl delete -f nginx-rc.yaml
# kubectl delete po nginx-controller-d97wj
# kubectl delete po nginx-controller-lf11n
  
16) apply
apply命令提供了比patch,edit等更嚴格的更新resource的方式。通過apply,使用者可以將resource的configuration使用source control的方式維護在版本庫中。
每次有更新時,將配置檔案push到server,然後使用kubectl apply將更新應用到resource。kubernetes會在引用更新前將當前配置檔案中的配置同已經應用的配置
做比較,並只更新更改的部分,而不會主動更改任何使用者未指定的部分。
  
apply命令的使用方式同replace相同,不同的是,apply不會刪除原有resource,然後建立新的。apply直接在原有resource的基礎上進行更新。同時kubectl apply
還會resource中新增一條註釋,標記當前的apply。類似於git操作。
  
17) logs
logs命令用於顯示pod執行中,容器內程式輸出到標準輸出的內容。跟docker的logs命令類似。如果要獲得tail -f 的方式,也可以使用-f選項。
# kubectl logs nginx-controller-d97wj
  
18) rolling-update
rolling-update是一個非常重要的命令,對於已經部署並且正在執行的業務,rolling-update提供了不中斷業務的更新方式。rolling-update每次起一個新的pod,
等新pod完全起來後刪除一箇舊的pod,然後再起一個新的pod替換舊的pod,直到替換掉所有的pod。
  
rolling-update需要確保新的版本有不同的name,Version和label,否則會報錯 。
# kubectl rolling-update nginx-controller -f nginx-rc.yaml
  
如果在升級過程中,發現有問題還可以中途停止update,並回滾到前面版本
# kubectl rolling-update nginx-controller --rollback
  
rolling-update還有很多其他選項提供豐富的功能,如--update-period指定間隔週期,使用時可以使用-h檢視help資訊.
  
19) scale  (注意下面的nginx-controller 是在nginx-rc.yaml檔案中定義的name名稱)
scale用於程式在負載加重或縮小時副本進行擴容或縮小,如前面建立的nginx有兩個副本,可以輕鬆的使用scale命令對副本數進行擴充套件或縮小。
擴充套件副本數到4:
# kubectl scale rc nginx-controller --replicas=4
  
重新縮減副本數到2:
# kubectl scale rc nginx-controller --replicas=2
  
20) autoscale
scale雖然能夠很方便的對副本數進行擴充套件或縮小,但是仍然需要人工介入,不能實時自動的根據系統負載對副本數進行擴、縮。autoscale命令提供了自動根據pod負載
對其副本進行擴縮的功能。
  
autoscale命令會給一個rc指定一個副本數的範圍,在實際執行中根據pod中執行的程式的負載自動在指定的範圍內對pod進行擴容或縮容。如前面建立的nginx,可以用
如下命令指定副本範圍在1~4
# kubectl autoscale rc nginx-controller --min=1 --max=4
  
21) attach
attach命令類似於docker的attach命令,可以直接檢視容器中以daemon形式執行的程式的輸出,效果類似於logs -f,退出檢視使用ctrl-c。如果一個pod中有多個容器,
要檢視具體的某個容器的的輸出,需要在pod名後使用-c containers name指定執行的容器。如下示例的命令為檢視kube-system namespace中的kube-dns-v9-rcfuk pod
中的skydns容器的輸出。
# kubectl attach kube-dns-v9-rcfuk -c skydns --namespace=kube-system
  
22) exec
exec命令同樣類似於docker的exec命令,為在一個已經執行的容器中執行一條shell命令,如果一個pod容器中,有多個容器,需要使用-c選項指定容器。
  
23) run
類似於docker的run命令,直接執行一個image。
  
24) cordon, drain, uncordon
這三個命令是正式release的1.2新加入的命令,三個命令一起介紹,是因為三個命令配合使用可以實現節點的維護。在1.2之前,因為沒有相應的命令支援,如果要維護一個
節點,只能stop該節點上的kubelet將該節點退出叢集,是叢集不在將新的pod排程到該節點上。如果該節點上本生就沒有pod在執行,則不會對業務有任何影響。如果該節
點上有pod正在執行,kubelet停止後,master會發現該節點不可達,而將該節點標記為notReady狀態,不會將新的節點排程到該節點上。同時,會在其他節點上建立新的
pod替換該節點上的pod。這種方式雖然能夠保證叢集的健壯性,但是任然有些暴力,如果業務只有一個副本,而且該副本正好執行在被維護節點上的話,可能仍然會造成業
務的短暫中斷。
  
1.2中新加入的這3個命令可以保證維護節點時,平滑的將被維護節點上的業務遷移到其他節點上,保證業務不受影響。如下圖所示是一個整個的節點維護的流程(為了方便
demo增加了一些檢視節點資訊的操作):
1- 首先檢視當前叢集所有節點狀態,可以看到共四個節點都處於ready狀態;
2- 檢視當前nginx兩個副本分別執行在d-node1和k-node2兩個節點上;
3- 使用cordon命令將d-node1標記為不可排程;
4- 再使用kubectl get nodes檢視節點狀態,發現d-node1雖然還處於Ready狀態,但是同時還被禁能了排程,這意味著新的pod將不會被排程到d-node1上。
5- 再檢視nginx狀態,沒有任何變化,兩個副本仍執行在d-node1和k-node2上;
6- 執行drain命令,將執行在d-node1上執行的pod平滑的趕到其他節點上;
7- 再檢視nginx的狀態發現,d-node1上的副本已經被遷移到k-node1上;這時候就可以對d-node1進行一些節點維護的操作,如升級核心,升級Docker等;
8- 節點維護完後,使用uncordon命令解鎖d-node1,使其重新變得可排程;8)檢查節點狀態,發現d-node1重新變回Ready狀態
  
# kubectl get nodes
# kubectl get po -o wide
# kubectl cordon d-node1
# kubectl get nodes
# kubectl get po -o wide
# kubectl drain d-node1
# kubectl get po -o wide
# kubectl uncordon
# kubectl uncordon d-node1
# kubectl get nodes
  
25) 檢視某個pod重啟次數(這個是參考)
# kubectl get pod nginx-controller-d97wj --template="{{range .status.containerStatuses}}{{.name}}:{{.restartCount}}{{end}}"
  
26) 檢視pod生命週期
[root@k8s-master01 ~]# kubectl get pod nginx-controller-d97wj --template="{{.status.phase}}"
Running

=====================================================================

常用命令
kubectl get pods
kubectl get rc
kubectl get service
kubectl get componentstatuses
kubectl get endpoints
kubectl cluster-info
kubectl create -f redis-master-controller.yaml
kubectl delete -f redis-master-controller.yaml
kubectl delete pod nginx-772ai
kubectl logs -f pods/heapster-xxxxx -n kube-system                     #檢視日誌
kubectl scale rc redis-slave --replicas=3                                     #修改RC的副本數量,來實現Pod的動態縮放
etcdctl cluster-health                                                                  #檢查網路叢集健康狀態
etcdctl --endpoints=http://172.16.60.220:2379 cluster-health     #帶有安全認證檢查網路叢集健康狀態
etcdctl member list
etcdctl set /k8s/network/config '{ "Network": "10.1.0.0/16" }'
etcdctl get /k8s/network/config

基礎進階
kubectl get services kubernetes-dashboard -n kube-system          #檢視所有service
kubectl get deployment kubernetes-dashboard -n kube-system    #檢視所有釋出
kubectl get pods --all-namespaces             #檢視所有pod
kubectl get pods -o wide --all-namespaces             #檢視所有pod的IP及節點
kubectl get pods -n kube-system | grep dashboard
kubectl describe service/kubernetes-dashboard --namespace="kube-system"
kubectl describe pods/kubernetes-dashboard-349859023-g6q8c --namespace="kube-system"       #指定型別檢視
kubectl describe pod nginx-772ai        #檢視pod詳細資訊
kubectl scale rc nginx --replicas=5        # 動態伸縮
kubectl scale deployment redis-slave --replicas=5          #動態伸縮
kubectl scale --replicas=2 -f redis-slave-deployment.yaml         #動態伸縮
kubectl exec -it tomcat-controller-35kzb /bin/bash       #進入容器
kubectl label nodes k8s-node01 zone=north                #增加節點lable值 spec.nodeSelector: zone: north, 指定pod在哪個節點
kubectl get nodes -lzone                          #獲取zone的節點
kubectl label pod tomcat-controller-35kzb role=master   #增加lable值 [key]=[value]
kubectl label pod tomcat-controller-35kzb role-                       #刪除lable值
kubectl label pod tomcat-controller-35kzb role=backend --overwrite    #修改lable值
kubectl rolling-update redis-master -f redis-master-controller-v2.yaml      #配置檔案滾動升級
kubectl rolling-update redis-master --image=redis-master:2.0                #命令升級
kubectl rolling-update redis-master --image=redis-master:1.0 --rollback     #pod版本回滾

                                                            kubernetes配置etcd叢集和Flannel網路部署                                                      

以上的環境配置的是etcd單節點, 線上生產環境建議配置etcd叢集環境. 部署範例大致如下:
1) 部署Etcd叢集
二進位制包下載地址:https://github.com/coreos/etcd/releases/tag/v3.2.12

以下部署步驟在規劃的三個etcd節點操作一樣,唯一不同的是etcd配置檔案中的伺服器IP要寫當前的:
解壓二進位制包:
# mkdir /opt/etcd/{bin,cfg,ssl} -p
# tar zxvf etcd-v3.2.12-linux-amd64.tar.gz
# mv etcd-v3.2.12-linux-amd64/{etcd,etcdctl} /opt/etcd/bin/

建立etcd配置檔案:
# cat /opt/etcd/cfg/etcd   
#[Member]
ETCD_NAME="etcd01"
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="https://172.16.60.220:2380"
ETCD_LISTEN_CLIENT_URLS="https://172.16.60.220:2379"

#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://172.16.60.220:2380"
ETCD_ADVERTISE_CLIENT_URLS="https://172.16.60.220:2379"
ETCD_INITIAL_CLUSTER="etcd01=https://172.16.60.220:2380,etcd02=https://172.16.60.221:2380,etcd03=https://172.16.60.222:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"

引數解釋:
ETCD_NAME 節點名稱
ETCD_DATA_DIR 資料目錄
ETCD_LISTEN_PEER_URLS 叢集通訊監聽地址
ETCD_LISTEN_CLIENT_URLS 客戶端訪問監聽地址
ETCD_INITIAL_ADVERTISE_PEER_URLS 叢集通告地址
ETCD_ADVERTISE_CLIENT_URLS 客戶端通告地址
ETCD_INITIAL_CLUSTER 叢集節點地址
ETCD_INITIAL_CLUSTER_TOKEN 叢集Token
ETCD_INITIAL_CLUSTER_STATE 加入叢集的當前狀態,new是新叢集,existing表示加入已有叢集

systemd管理etcd:
# cat /usr/lib/systemd/system/etcd.service 
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
EnvironmentFile=/opt/etcd/cfg/etcd
ExecStart=/opt/etcd/bin/etcd \
--name=${ETCD_NAME} \
--data-dir=${ETCD_DATA_DIR} \
--listen-peer-urls=${ETCD_LISTEN_PEER_URLS} \
--listen-client-urls=${ETCD_LISTEN_CLIENT_URLS},http://127.0.0.1:2379 \
--advertise-client-urls=${ETCD_ADVERTISE_CLIENT_URLS} \
--initial-advertise-peer-urls=${ETCD_INITIAL_ADVERTISE_PEER_URLS} \
--initial-cluster=${ETCD_INITIAL_CLUSTER} \
--initial-cluster-token=${ETCD_INITIAL_CLUSTER_TOKEN} \
--initial-cluster-state=new \
--cert-file=/opt/etcd/ssl/server.pem \
--key-file=/opt/etcd/ssl/server-key.pem \
--peer-cert-file=/opt/etcd/ssl/server.pem \
--peer-key-file=/opt/etcd/ssl/server-key.pem \
--trusted-ca-file=/opt/etcd/ssl/ca.pem \
--peer-trusted-ca-file=/opt/etcd/ssl/ca.pem
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

把剛才生成的證照拷貝到配置檔案中的位置:
# cp ca*pem server*pem /opt/etcd/ssl

啟動並設定開啟啟動:
# systemctl start etcd
# systemctl enable etcd

都部署完成後,檢查etcd叢集狀態:
# /opt/etcd/bin/etcdctl \
--ca-file=ca.pem --cert-file=server.pem --key-file=server-key.pem \
--endpoints="https://172.16.60.220:2379,https://172.16.60.221:2379,https://172.16.60.222:2379" \
cluster-health
member 18218cfabd4e0dea is healthy: got healthy result from https://172.16.60.220:2379
member 541c1c40994c939b is healthy: got healthy result from https://172.16.60.221:2379
member a342ea2798d20705 is healthy: got healthy result from https://172.16.60.222:2379
cluster is healthy

如果輸出上面資訊,就說明叢集部署成功。如果有問題第一步先看日誌:/var/log/message 或 journalctl -u etcd

2) Flannel部署
Falnnel要用etcd儲存自身一個子網資訊,所以要保證能成功連線Etcd,寫入預定義子網段 (網路型別指定vxlan):
# /opt/etcd/bin/etcdctl \
--ca-file=ca.pem --cert-file=server.pem --key-file=server-key.pem \
--endpoints="https://172.16.60.220:2379,https://172.16.60.221:2379,https://172.16.60.222:2379" \
set /atomic.io/network/config  '{ "Network": "192.16.0.0/16", "Backend": {"Type": "vxlan"}}'

以下部署步驟在規劃的每個node節點都操作。
下載二進位制包:
# wget https://github.com/coreos/flannel/releases/download/v0.10.0/flannel-v0.10.0-linux-amd64.tar.gz
# tar zxvf flannel-v0.9.1-linux-amd64.tar.gz
# mv flanneld mk-docker-opts.sh /opt/kubernetes/bin

配置Flannel:
# cat /opt/kubernetes/cfg/flanneld
FLANNEL_OPTIONS="--etcd-endpoints=https://172.16.60.220:2379,https://172.16.60.221:2379,https://172.16.60.222:2379 -etcd-cafile=/opt/etcd/ssl/ca.pem -etcd-certfile=/opt/etcd/ssl/server.pem -etcd-keyfile=/opt/etcd/ssl/server-key.pem"

systemd管理Flannel:
# cat /usr/lib/systemd/system/flanneld.service
[Unit]
Description=Flanneld overlay address etcd agent
After=network-online.target network.target
Before=docker.service

[Service]
Type=notify
EnvironmentFile=/opt/kubernetes/cfg/flanneld
ExecStart=/opt/kubernetes/bin/flanneld --ip-masq $FLANNEL_OPTIONS
ExecStartPost=/opt/kubernetes/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/subnet.env
Restart=on-failure

[Install]
WantedBy=multi-user.target

配置Docker啟動指定子網段:
# cat /usr/lib/systemd/system/docker.service 

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
EnvironmentFile=/run/flannel/subnet.env
ExecStart=/usr/bin/dockerd $DOCKER_NETWORK_OPTIONS
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target

重啟flannel和docker:
# systemctl daemon-reload
# systemctl start flanneld
# systemctl enable flanneld
# systemctl restart docker

相關文章