無法置入文檔因為pdfl初始化失敗(無法完成請求,因為pdfl初始化失敗)
寫在前面
筆者今年?9?月從端側開發轉到后臺開發,第一個系統開發任務就強依賴了?Kubernetes,加之項目任務重、排期緊,必須馬上對?Kubernetes?有概念上的了解。然而,很多所謂“Kubernetes?入門概念”的文章看的一頭霧水,對于大部分新手來說并不友好。經歷了幾天痛苦地學習之后,回顧來看,Kubernetes?根本不復雜。于是,決心寫下這篇文章,一方面希望對新手同學有幫助;另一方面,以文會友,希望能夠有機會交流討論技術。
本文組織方式:
Kubernetes?是什么,即作用和目的。涉及?Kubernetes?架構的整理,Master?和?Node?之間的關系,以及?Kubernetes?幾個重要的組件:API?Server、Scheduler、Controller、etcd?等。
Kubernetes?的重要概念,即?Kubernetes?的?API?對象,也就是常常聽到的?Pod、Deployment、Service?等。
如何配置?kubectl,介紹?kubectl?工具和配置辦法。
如何用?kubectl?部署服務。
如何用?kubectl?查看、更新/編輯、刪除服務。
如何用?kubectl?排查部署在?Kubernetes?集群上的服務出現的問題。
1.?Kubernetes?概覽
1.1?Kubernetes?是什么?
先看官方介紹:
Kubernetes?is?an?open?source?system?for?managing?containerized?applications?across?multiple?hosts.?It?provides?basic?mechanisms?for?deployment,?maintenance,?and?scaling?of?applications.?用于自動部署、擴展和管理“容器化(containerized)應用程序”的開源系統。
翻譯成大白話就是:“Kubernetes?是負責自動化運維管理多個?Docker?程序的集群”。那么問題來了:Docker?運行可方便了,為什么要用?Kubernetes,它有什么優勢?
插一句題外話:
為什么?Kubernetes?要叫?Kubernetes?呢?維基百科已經交代了(老美對星際是真的癡迷):
Kubernetes(在希臘語意為“舵手”或“駕駛員”)由?Joe?Beda、Brendan?Burns?和?Craig?McLuckie?創立,并由其他谷歌工程師,包括?Brian?Grant?和?Tim?Hockin?等進行加盟創作,并由谷歌在?2014?年首次對外宣布?。該系統的開發和設計都深受谷歌的?Borg?系統的影響,其許多頂級貢獻者之前也是?Borg?系統的開發者。在谷歌內部,Kubernetes?的原始代號曾經是?Seven,即星際迷航中的?Borg(博格人)。Kubernetes?標識中舵輪有七個輪輻就是對該項目代號的致意。
為什么?Kubernetes?的縮寫是?K8S?呢?我個人贊同?Why?Kubernetes?is?Abbreviated?k8s[1]?中說的觀點“嘛,寫全稱也太累了吧,不如整個縮寫”。其實只保留首位字符,用具體數字來替代省略的字符個數的做法,還是比較常見的。
1.2?為什么是?Kubernetes?
試想下傳統的后端部署辦法:把程序包(包括可執行二進制文件、配置文件等)放到服務器上,接著運行啟動腳本把程序跑起來,同時啟動守護腳本定期檢查程序運行狀態、必要的話重新拉起程序。
有問題嗎?顯然有!最大的一個問題在于:如果服務的請求量上來,已部署的服務響應不過來怎么辦?傳統的做法往往是,如果請求量、內存、CPU?超過閾值做了告警,運維馬上再加幾臺服務器,部署好服務之后,接入負載均衡來分擔已有服務的壓力。
問題出現了:從監控告警到部署服務,中間需要人力介入!那么,有沒有辦法自動完成服務的部署、更新、卸載和擴容、縮容呢?
這,就是?Kubernetes?要做的事情:自動化運維管理?Docker(容器化)程序。
1.3?Kubernetes?怎么做?
我們已經知道了?Kubernetes?的核心功能:自動化運維管理多個容器化程序。那么?Kubernetes?怎么做到的呢?這里,我們從宏觀架構上來學習?Kubernetes?的設計思想。首先看下圖,圖片來自文章?Components?of?Kubernetes?Architecture[2]:
Kubernetes?是屬于主從設備模型(Master-Slave?架構),即有?Master?節點負責核心的調度、管理和運維,Slave?節點則在執行用戶的程序。但是在?Kubernetes?中,主節點一般被稱為?Master?Node?或者?Head?Node(本文采用?Master?Node?稱呼方式),而從節點則被稱為Worker?Node?或者?Node(本文采用?Worker?Node?稱呼方式)。
要注意一點:Master?Node?和?Worker?Node?是分別安裝了?Kubernetes?的?Master?和?Woker?組件的實體服務器,每個?Node?都對應了一臺實體服務器(雖然?Master?Node?可以和其中一個?Worker?Node?安裝在同一臺服務器,但是建議?Master?Node?單獨部署),所有?Master?Node?和?Worker?Node?組成了?Kubernetes?集群,同一個集群可能存在多個?Master?Node?和?Worker?Node。
首先來看Master?Node都有哪些組件:
API?Server,Kubernetes?的請求入口服務。API?Server?負責接收?Kubernetes?所有請求(來自?UI?界面或者?CLI?命令行工具),然后,API?Server?根據用戶的具體請求,去通知其他組件干活。
Scheduler,Kubernetes?所有?Worker?Node?的調度器。當用戶要部署服務時,Scheduler?會選擇最合適的?Worker?Node(服務器)來部署。
Controller?Manager,Kubernetes?所有?Worker?Node?的監控器。Controller?Manager?有很多具體的?Controller,在文章?Components?of?Kubernetes?Architecture[2]?中提到的有?Node?Controller、Service?Controller、Volume?Controller?等。Controller?負責監控和調整在?Worker?Node?上部署的服務的狀態,比如用戶要求?A?服務部署?2?個副本,那么當其中一個服務掛了的時候,Controller?會馬上調整,讓?Scheduler?再選擇一個?Worker?Node?重新部署服務。
etcd,Kubernetes?的存儲服務。etcd?存儲了?Kubernetes?的關鍵配置和用戶配置,Kubernetes?中僅?API?Server?才具備讀寫權限,其他組件必須通過?API?Server?的接口才能讀寫數據(見?Kubernetes?Works?Like?an?Operating?System[3])。
接著來看Worker?Node的組件,筆者更贊同?HOW?DO?APPLICATIONS?RUN?ON?KUBERNETES[4]?文章中提到的組件介紹:
Kubelet,Worker?Node?的監視器,以及與?Master?Node?的通訊器。Kubelet?是?Master?Node?安插在?Worker?Node?上的“眼線”,它會定期向?Master?Node?匯報自己?Node?上運行的服務的狀態,并接受來自?Master?Node?的指示采取調整措施。
Kube-Proxy,Kubernetes?的網絡代理。私以為稱呼為?Network-Proxy?可能更適合?Kube-Proxy?負責?Node?在?Kubernetes?的網絡通訊、以及對外部網絡流量的負載均衡。
Container?Runtime,Worker?Node?的運行環境。即安裝了容器化所需的軟件環境確保容器化程序能夠跑起來,比如?Docker?Engine。大白話就是幫忙裝好了?Docker?運行環境。
Logging?Layer,Kubernetes?的監控狀態收集器。私以為稱呼為?Monitor?可能更合適?Logging?Layer?負責采集?Node?上所有服務的?CPU、內存、磁盤、網絡等監控項信息。
Add-Ons,Kubernetes?管理運維?Worker?Node?的插件組件。有些文章認為?Worker?Node?只有三大組件,不包含?Add-On,但筆者認為?Kubernetes?系統提供了?Add-On?機制,讓用戶可以擴展更多定制化功能,是很不錯的亮點。
總結來看,Kubernetes?的?Master?Node?具備:請求入口管理(API?Server),Worker?Node?調度(Scheduler),監控和自動調節(Controller?Manager),以及存儲功能(etcd);而?Kubernetes?的?Worker?Node?具備:狀態和監控收集(Kubelet),網絡和負載均衡(Kube-Proxy)、保障容器化運行環境(Container?Runtime)、以及定制化功能(Add-Ons)。
到這里,相信你已經對?Kubernetes?究竟是做什么的,有了大概認識。接下來,再來認識下?Kubernetes?的?Deployment、Pod、Replica?Set、Service?等,但凡談到?Kubernetes,就繞不開這些名詞,而這些名詞也是最讓?Kubernetes?新手們感到頭疼、困惑的。
2.?Kubernetes?重要概念
2.1?Pod?實例
官方對于Pod的解釋是:
Pod?是可以在?Kubernetes?中創建和管理的、最小的可部署的計算單元。
這樣的解釋還是很難讓人明白究竟?Pod?是什么,但是對于?Kubernetes?而言,Pod?可以說是所有對象中最重要的概念了!因此,我們必須首先清楚地知道“Pod?是什么”,再去了解其他的對象。
從官方給出的定義,聯想下“最小的?xxx?單元”,是不是可以想到本科在學校里學習“進程”的時候,教科書上有一段類似的描述:資源分配的最小單位;還有”線程“的描述是:CPU?調度的最小單位。什么意思呢?“最小?xx?單位”要么就是事物的衡量標準單位,要么就是資源的閉包、集合。前者比如長度米、時間秒;后者比如一個“進程”是存儲和計算的閉包,一個“線程”是?CPU?資源(包括寄存器、ALU?等)的閉包。
同樣的,Pod?就是?Kubernetes?中一個服務的閉包。這么說的好像還是有點玄乎,更加云里霧里了。簡單來說,Pod?可以被理解成一群可以共享網絡、存儲和計算資源的容器化服務的集合。再打個形象的比喻,在同一個?Pod?里的幾個?Docker?服務/程序,好像被部署在同一臺機器上,可以通過?localhost?互相訪問,并且可以共用?Pod?里的存儲資源(這里是指?Docker?可以掛載?Pod?內的數據卷,數據卷的概念,后文會詳細講述,暫時理解為“需要手動?mount?的磁盤”)。筆者總結?Pod?如下圖,可以看到:同一個?Pod?之間的?Container?可以通過?localhost?互相訪問,并且可以掛載?Pod?內所有的數據卷;但是不同的?Pod?之間的?Container?不能用?localhost?訪問,也不能掛載其他?Pod?的數據卷。
對?Pod?有直觀的認識之后,接著來看?Kubernetes?中?Pod?究竟長什么樣子,具體包括哪些資源?
Kubernetes?中所有的對象都通過?yaml?來表示,筆者從官方網站摘錄了一個最簡單的?Pod?的?yaml:
apiVersion:?v1
kind:?Pod
metadata:
name:?memory-demo
namespace:?mem-example
spec:
containers:
-?name:?memory-demo-ctr
image:?polinux/stress
resources:
limits:
memory:?"200Mi"
requests:
memory:?"100Mi"
command:?[?"stress"]
args:?[?"--vm",?"1",?"--vm-bytes",?"150M",?"--vm-hang",?"1"]
volumeMounts:
-?name:?redis-storage
mountPath:?/data/redis
volumes:
-?name:?redis-storage
emptyDir:?{}
看不懂不必慌張,且耐心聽下面的解釋:
apiVersion?記錄?Kubernetes?的?API?Server?版本,現在看到的都是?v1,用戶不用管。
kind?記錄該?yaml?的對象,比如這是一份?Pod?的?yaml?配置文件,那么值內容就是?Pod。
metadata?記錄了?Pod?自身的元數據,比如這個?Pod?的名字、這個?Pod?屬于哪個?namespace(命名空間的概念,后文會詳述,暫時理解為“同一個命名空間內的對象互相可見”)。
spec?記錄了?Pod?內部所有的資源的詳細信息,看懂這個很重要:
containers?記錄了?Pod?內的容器信息,containers?包括了:name?容器名,image?容器的鏡像地址,resources?容器需要的?CPU、內存、GPU?等資源,command?容器的入口命令,args?容器的入口參數,volumeMounts?容器要掛載的?Pod?數據卷等。可以看到,上述這些信息都是啟動容器的必要和必需的信息。
volumes?記錄了?Pod?內的數據卷信息,后文會詳細介紹?Pod?的數據卷。
2.2?Volume?數據卷
Kubernetes?支持很多類型的?Volume?數據卷掛載,具體請參見?Kubernetes?卷[5]。前文就“如何理解?Volume”提到:“需要手動?mount?的磁盤”,此外,有一點可以幫助理解:數據卷?Volume?是?Pod?內部的磁盤資源。
其實,單單就?Volume?來說,不難理解。但是上面還看到了?volumeMounts,這倆是什么關系呢?
Volume?是?Kubernetes?的對象,對應一個實體的數據卷;而?volumeMounts?只是?container?的掛載點,對應?container?的其中一個參數。但是,volumeMounts?依賴于?Volume,只有當?Pod?內有?Volume?資源的時候,該?Pod?內部的?container?才可能有?volumeMounts。
2.3?Container?容器
本文中提到的鏡像?Image、容器?Container,都指代了?Pod?下的一個?container。關于?Kubernetes?中的容器,在?2.1?Pod?章節都已經交代了,這里無非再啰嗦一句:一個?Pod?內可以有多個容器?container。
在?Pod?中,容器也有分類,對這個感興趣的同學歡迎自行閱讀更多資料:
標準容器(Application?Container)。
初始化容器(Init?Container)。
邊車容器(Sidecar?Container)。
臨時容器(Ephemeral?Container)。
一般來說,我們部署的大多是標準容器(Application?Container)。
2.4?Deployment?和?ReplicaSet(簡稱?RS)
除了?Pod?之外,Kubernetes?中最常聽到的另一個對象就是?Deployment?了。那么,什么是?Deployment?呢?官方給出了一個要命的解釋:
一個?Deployment?控制器為?Pods?和?ReplicaSets?提供聲明式的更新能力。你負責描述?Deployment?中的目標狀態,而?Deployment?控制器以受控速率更改實際狀態,使其變為期望狀態。你可以定義?Deployment?以創建新的?ReplicaSet,或刪除現有?Deployment,并通過新的?Deployment?收養其資源。
翻譯一下:Deployment?的作用是管理和控制?Pod?和?ReplicaSet,管控它們運行在用戶期望的狀態中。哎,打個形象的比喻,Deployment?就是包工頭,主要負責監督底下的工人?Pod?干活,確保每時每刻有用戶要求數量的?Pod?在工作。如果一旦發現某個工人?Pod?不行了,就趕緊新拉一個?Pod?過來替換它。
新的問題又來了:那什么是?ReplicaSets?呢?
ReplicaSet?的目的是維護一組在任何時候都處于運行狀態的?Pod?副本的穩定集合。因此,它通常用來保證給定數量的、完全相同的?Pod?的可用性。
再來翻譯下:ReplicaSet?的作用就是管理和控制?Pod,管控他們好好干活。但是,ReplicaSet?受控于?Deployment。形象來說,ReplicaSet?就是總包工頭手下的小包工頭。
筆者總結得到下面這幅圖,希望能幫助理解:
新的問題又來了:如果都是為了管控?Pod?好好干活,為什么要設置?Deployment?和?ReplicaSet?兩個層級呢,直接讓?Deployment?來管理不可以嗎?
回答:不清楚,但是私以為是因為先有?ReplicaSet,但是使用中發現?ReplicaSet?不夠滿足要求,于是又整了一個?Deployment(有清楚?Deployment?和?ReplicaSet?聯系和區別的小伙伴歡迎留言啊)。
但是,從?Kubernetes?使用者角度來看,用戶會直接操作?Deployment?部署服務,而當?Deployment?被部署的時候,Kubernetes?會自動生成要求的?ReplicaSet?和?Pod。在?Kubernetes?官方文檔中也指出用戶只需要關心?Deployment?而不操心?ReplicaSet:
This?actually?means?that?you?may?never?need?to?manipulate?ReplicaSet?objects:?use?a?Deployment?instead,?and?define?your?application?in?the?spec?section.這實際上意味著您可能永遠不需要操作?ReplicaSet?對象:直接使用?Deployments?并在規范部分定義應用程序。
補充說明:在?Kubernetes?中還有一個對象?——?ReplicationController(簡稱?RC),官方文檔對它的定義是:
ReplicationController?確保在任何時候都有特定數量的?Pod?副本處于運行狀態。換句話說,ReplicationController?確保一個?Pod?或一組同類的?Pod?總是可用的。
怎么樣,和?ReplicaSet?是不是很相近?在?Deployments,?ReplicaSets,?and?pods[6]?教程中說“ReplicationController?是?ReplicaSet?的前身”,官方也推薦用?Deployment?取代?ReplicationController?來部署服務。
2.5?Service?和?Ingress
吐槽下?Kubernetes?的概念/對象/資源是真的多啊!前文介紹的?Deployment、ReplicationController?和?ReplicaSet?主要管控?Pod?程序服務;那么,Service?和?Ingress?則負責管控?Pod?網絡服務。
我們先來看看官方文檔中?Service?的定義:
將運行在一組?Pods?上的應用程序公開為網絡服務的抽象方法。使用?Kubernetes,您無需修改應用程序即可使用不熟悉的服務發現機制。Kubernetes?為?Pods?提供自己的?IP?地址,并為一組?Pod?提供相同的?DNS?名,?并且可以在它們之間進行負載均衡。
翻譯下:Kubernetes?中的服務(Service)并不是我們常說的“服務”的含義,而更像是網關層,是若干個?Pod?的流量入口、流量均衡器。
那么,為什么要?Service?呢?
私以為在這一點上,官方文檔講解地非常清楚:
Kubernetes?Pod?是有生命周期的。它們可以被創建,而且銷毀之后不會再啟動。如果您使用?Deployment?來運行您的應用程序,則它可以動態創建和銷毀?Pod。每個?Pod?都有自己的?IP?地址,但是在?Deployment?中,在同一時刻運行的?Pod?集合可能與稍后運行該應用程序的?Pod?集合不同。這導致了一個問題:如果一組?Pod(稱為“后端”)為群集內的其他?Pod(稱為“前端”)提供功能,?那么前端如何找出并跟蹤要連接的?IP?地址,以便前端可以使用工作量的后端部分?
補充說明:Kubernetes?集群的網絡管理和拓撲也有特別的設計,以后會專門出一章節來詳細介紹?Kubernetes?中的網絡。這里需要清楚一點:Kubernetes?集群內的每一個?Pod?都有自己的?IP(是不是很類似一個?Pod?就是一臺服務器,然而事實上是多個?Pod?存在于一臺服務器上,只不過是?Kubernetes?做了網絡隔離),在?Kubernetes?集群內部還有?DNS?等網絡服務(一個?Kubernetes?集群就如同管理了多區域的服務器,可以做復雜的網絡拓撲)。
此外,筆者推薦?Kubernetes?外網如何訪問業務應用對于?Service?的介紹,不過對于新手而言,推薦閱讀前半部分對于?service?的介紹即可,后半部分就太復雜了。我這里做了簡單的總結:
Service?是?Kubernetes?服務的核心,屏蔽了服務細節,統一對外暴露服務接口,真正做到了“微服務”。舉個例子,我們的一個服務?A,部署了?3?個備份,也就是?3?個?Pod;對于用戶來說,只需要關注一個?Service?的入口就可以,而不需要操心究竟應該請求哪一個?Pod。優勢非常明顯:一方面外部用戶不需要感知因為?Pod?上服務的意外崩潰、Kubernetes?重新拉起?Pod?而造成的?IP?變更,外部用戶也不需要感知因升級、變更服務帶來的?Pod?替換而造成的?IP?變化,另一方面,Service?還可以做流量負載均衡。
但是,Service?主要負責?Kubernetes?集群內部的網絡拓撲。那么集群外部怎么訪問集群內部呢?這個時候就需要?Ingress?了,官方文檔中的解釋是:
Ingress?是對集群中服務的外部訪問進行管理的?API?對象,典型的訪問方式是?HTTP。Ingress?可以提供負載均衡、SSL?終結和基于名稱的虛擬托管。
翻譯一下:Ingress?是整個?Kubernetes?集群的接入層,復雜集群內外通訊。
最后,筆者把?Ingress?和?Service?的關系繪制網絡拓撲關系圖如下,希望對理解這兩個概念有所幫助:
2.6?namespace?命名空間
和前文介紹的所有的概念都不一樣,namespace?跟?Pod?沒有直接關系,而是?Kubernetes?另一個維度的對象。或者說,前文提到的概念都是為了服務?Pod?的,而?namespace?則是為了服務整個?Kubernetes?集群的。
那么,namespace?是什么呢?
上官方文檔定義:
Kubernetes?支持多個虛擬集群,它們底層依賴于同一個物理集群。這些虛擬集群被稱為名字空間。
翻譯一下:namespace?是為了把一個?Kubernetes?集群劃分為若干個資源不可共享的虛擬集群而誕生的。
也就是說,可以通過在?Kubernetes?集群內創建?namespace?來分隔資源和對象。比如我有?2?個業務?A?和?B,那么我可以創建?ns-a?和?ns-b?分別部署業務?A?和?B?的服務,如在?ns-a?中部署了一個?deployment,名字是?hello,返回用戶的是“hello?a”;在?ns-b?中也部署了一個?deployment,名字恰巧也是?hello,返回用戶的是“hello?b”(要知道,在同一個?namespace?下?deployment?不能同名;但是不同?namespace?之間沒有影響)。前文提到的所有對象,都是在?namespace?下的;當然,也有一些對象是不隸屬于?namespace?的,而是在?Kubernetes?集群內全局可見的,官方文檔提到的可以通過命令來查看,具體命令的使用辦法,筆者會出后續的實戰文章來介紹,先貼下命令:
#?位于名字空間中的資源
kubectl?api-resources?--namespaced=?true
#?不在名字空間中的資源
kubectl?api-resources?--namespaced=?false
不在?namespace?下的對象有:
在?namespace?下的對象有(部分):
2.7?其他
Kubernetes?的對象實在太多了,2.1-2.6?介紹的是在實際使用?Kubernetes?部署服務最常見的。其他的還有?Job、CronJob?等等,在對?Kubernetes?有了比較清楚的認知之后,再去學習更多的?Kubernetes?對象,不是難事。
3.?配置?kubectl
3.1?什么是?kubectl?
官方文檔中介紹?kubectl?是:
Kubectl?是一個命令行接口,用于對?Kubernetes?集群運行命令。Kubectl?的配置文件在$HOME/.kube?目錄。我們可以通過設置?KUBECONFIG?環境變量或設置命令參數--kubeconfig?來指定其他位置的?kubeconfig?文件。
也就是說,可以通過?kubectl?來操作?Kubernetes?集群,基本語法:
使用以下語法?kubectl?從終端窗口運行命令:
kubectl?[?command]?[TYPE]?[NAME]?[flags]
其中?command、TYPE、NAME?和?flags?分別是:
command:指定要對一個或多個資源執行的操作,例如?create、get、describe、delete。
TYPE:指定資源類型。資源類型不區分大小寫,可以指定單數、復數或縮寫形式。例如,以下命令輸出相同的結果:
kubectl?get?pod?pod1
kubectl?get?pods?pod1
kubectl?get?po?pod1
NAME:指定資源的名稱。名稱區分大小寫。如果省略名稱,則顯示所有資源的詳細信息?kubectl?get?pods。
在對多個資源執行操作時,您可以按類型和名稱指定每個資源,或指定一個或多個文件:
要按類型和名稱指定資源:
要對所有類型相同的資源進行分組,請執行以下操作:TYPE1?name1?name2?name<#>。?例子:kubectl?get?pod?example-pod1?example-pod2
分別指定多個資源類型:TYPE1/name1?TYPE1/name2?TYPE2/name3?TYPE<#>/name<#>。?例子:kubectl?get?pod/example-pod1?replicationcontroller/example-rc1
用一個或多個文件指定資源:-f?file1?-f?file2?-f?file<#>
使用?YAML?而不是?JSON?因為?YAML?更容易使用,特別是用于配置文件時。?例子:kubectl?get?-f?./pod.yaml
flags:指定可選的參數。例如,可以使用?-s?或?-server?參數指定?Kubernetes?API?服務器的地址和端口。
就如何使用?kubectl?而言,官方文檔已經說得非常清楚。不過對于新手而言,還是需要解釋幾句:kubectl?是?Kubernetes?的命令行工具,并不需要?kubectl?安裝在?Kubernetes?集群的任何?Node?上,但是,需要確保安裝?kubectl?的機器和?Kubernetes?的集群能夠進行網絡互通。
接下來,一起看看怎么使用?kubectl?吧,切身感受下?kubectl?的使用。
請注意,如何安裝?kubectl?的辦法有許多非常明確的教程,比如《安裝并配置?kubectl[7]》,本文不再贅述。
3.2?怎么配置?kubectl?
第一步,必須準備好要連接/使用的?Kubernetes?的配置文件,筆者給出一份杜撰的配置:
apiVersion:?v1
clusters:
-?cluster:
certificate-authority-data:?thisisfakecertifcateauthoritydata00000000000
server:?https://1.2.3.4:1234
name:?cls-dev
contexts:
-?context:
cluster:?cls-dev
user:?kubernetes-admin
name:?kubernetes-admin@?test
current-context:?kubernetes-admin@?test
kind:?Config
preferences:?{}
users:
-?name:?kubernetes-admin
user:
token:?thisisfaketoken00000
解讀如下:
clusters?記錄了?clusters(一個或多個?Kubernetes?集群)信息:
name?是這個?cluster(Kubernetes?集群)的名稱代號
server?是這個?cluster(Kubernetes?集群)的訪問方式,一般為?IP+PORT
certificate-authority-data?是證書數據,只有當?cluster(Kubernetes?集群)的連接方式是?https?時,為了安全起見需要證書數據
users?記錄了訪問?cluster(Kubernetes?集群)的賬號信息:
name?是用戶賬號的名稱代號
user/token?是用戶的?token?認證方式,token?不是用戶認證的唯一方式,其他還有賬號+密碼等。
contexts?是上下文信息,包括了?cluster(Kubernetes?集群)和訪問?cluster(Kubernetes?集群)的用戶賬號等信息:
name?是這個上下文的名稱代號
cluster?是?cluster(Kubernetes?集群)的名稱代號
user?是訪問?cluster(Kubernetes?集群)的用戶賬號代號
current-context?記錄當前?kubectl?默認使用的上下文信息
kind?和?apiVersion?都是固定值,用戶不需要關心
preferences?則是配置文件的其他設置信息,筆者沒有使用過,暫時不提。
第二步,給?kubectl?配置上配置文件。
--kubeconfig?參數。第一種辦法是每次執行?kubectl?的時候,都帶上?--kubeconfig=${CONFIG_PATH}。給一點溫馨小提示:每次都帶這么一長串的字符非常麻煩,可以用?alias?別名來簡化碼字量,比如?alias?k=kubectl?--kubeconfig=${CONFIG_PATH}。
KUBECONFIG?環境變量。第二種做法是使用環境變量?KUBECONFIG?把所有配置文件都記錄下來,即?export?KUBECONFIG=$KUBECONFIG:${CONFIG_PATH}。接下來就可以放心執行?kubectl?命令了。
$HOME/.kube/config?配置文件。第三種做法是把配置文件的內容放到?$HOME/.kube/config?內。具體做法為:
如果$HOME/.kube/config?不存在,那么cp?${CONFIG_PATH}?$HOME/.kube/config即可;
如果如果?$HOME/.kube/config已經存在,那么需要把新的配置內容加到?$HOME/.kube/config?下。單單只是cat?${CONFIG_PATH}?>>?$HOME/.kube/config是不行的,正確的做法是:KUBECONFIG=$HOME/.kube/config:${CONFIG_PATH}?kubectl?config?view?--flatten?>?$HOME/.kube/config?。解釋下這個命令的意思:先把所有的配置文件添加到環境變量KUBECONFIG中,然后執行kubectl?config?view?--flatten打印出有效的配置文件內容,最后覆蓋$HOME/.kube/config?即可。
請注意,上述操作的優先級分別是?1>2>3,也就是說,kubectl?會優先檢查--kubeconfig,若無則檢查KUBECONFIG,若無則最后檢查$HOME/.kube/config,如果還是沒有,報錯。但凡某一步找到了有效的?cluster,就中斷檢查,去連接?Kubernetes?集群了。
第三步:配置正確的上下文。
按照第二步的做法,如果配置文件只有一個?cluster?是沒有任何問題的,但是對于有多個?cluster?怎么辦呢?到這里,有幾個關于配置的必須掌握的命令:
kubectl?config?get-contexts。列出所有上下文信息。
kubect?l?config?current-context。?查看當前的上下文信息。?其實,命令?1?線束出來的*所指示的就是當前的上下文信息。
kubectl?config?use-context?${CONTEXT_NAME}。?更改上下文信息。
kubectl?config?set-context?${CONTEXT_NAME}|--current?--${KEY}=${VALUE}。?修改上下文的元素。?比如可以修改用戶賬號、集群信息、連接到?Kubernetes?后所在的?namespace。
關于該命令,還有幾點要啰嗦的:
config?set-context可以修改任何在配置文件中的上下文信息,只需要在命令中指定上下文名稱就可以。而--current?則指代當前上下文。
上下文信息所包括的內容有:cluster?集群(名稱)、用戶賬號(名稱)、連接到?Kubernetes?后所在的?namespace,因此有?config?set-context?嚴格意義上的用法:
kubectl?config?set-context?[NAME|--current]?[--cluster=cluster_nickname]?[--user=user_nickname]?[--namespace=namespace]?[options]
備注:[options]可以通過?kubectl?options?查看。
綜上,如何操作?kubectl?配置都已交代。
??????4.?kubectl?部署服務
??????
Kubernetes?核心功能就是部署運維容器化服務,因此最重要的就是如何又快又好地部署自己的服務了。本章會介紹如何部署?Pod?和?Deployment。
4.1?如何部署?Pod?
通過?kubectl?部署?Pod?的辦法分為兩步:1).?準備?Pod?的?yaml?文件;2).?執行?kubectl?命令部署。
第一步:準備?Pod?的?yaml?文件。關于?Pod?的?yaml?文件初步解釋,本文已經有了初步介紹,這里再復習下:
apiVersion:?v1
kind:?Pod
metadata:
name:?memory-demo
namespace:?mem-example
spec:
containers:
-?name:?memory-demo-ctr
image:?polinux/stress
resources:
limits:
memory:?"200Mi"
requests:
memory:?"100Mi"
command:?[?"stress"]
args:?[?"--vm",?"1",?"--vm-bytes",?"150M",?"--vm-hang",?"1"]
volumeMounts:
-?name:?redis-storage
mountPath:?/data/redis
volumes:
-?name:?redis-storage
emptyDir:?{}
繼續解讀:
metadata,對于新入門的同學來說,需要重點掌握的兩個字段:
name,這個?Pod?的名稱,后面到?Kubernetes?集群中查找?Pod?的關鍵字段。
namespace,命名空間,即該?Pod?隸屬于哪個?namespace?下,關于?Pod?和?namespace?的關系,之前內容已經交代了。
spec?記錄了?Pod?內部所有的資源的詳細信息,這里我們重點查看?containers?下的幾個重要字段:
name,Pod?下該容器名稱,后面查找?Pod?下的容器的關鍵字段。
image,容器的鏡像地址,Kubernetes?會根據這個字段去拉取鏡像。
resources,容器化服務涉及到的?CPU、內存、GPU?等資源要求。可以看到有?limits?和?requests?兩個子項,那么這兩者有什么區別嗎,該怎么使用?在?What's?the?difference?between?Pod?resources.limits?and?resources.requests?in?Kubernetes?[8]?回答了:limits是?Kubernetes?為該容器至多分配的資源配額;而?requests?則是?Kubernetes?為該容器至少分配的資源配額。打個比方,配置中要求了?memory?的?requests?為?100M,而此時如果?Kubernetes?集群中所有的?Node?的可用內存都不足?100M,那么部署服務會失敗;又如果有一個?Node?的內存有?16G?充裕,可以部署該?Pod,而在運行中,該容器服務發生了內存泄露,那么一旦超過?200M?就會因為?OOM?被?kill,盡管此時該機器上還有?15G+的內存。
command,容器的入口命令。對于這個筆者還存在很多困惑不解的地方,暫時挖個坑,有清楚的同學歡迎留言。
args,容器的入口參數。同上,有清楚的同學歡迎留言。
volumeMounts,容器要掛載的?Pod?數據卷等。請務必記住:Pod?的數據卷只有被容器掛載后才能使用!
第二步:執行?kubectl?命令部署。有了?Pod?的?yaml?文件之后,就可以用?kubectl?部署了,命令非常簡單:kubectl?create?-f?${POD_YAML}。
隨后,會提示該命令是否執行成功,比如?yaml?內容不符合要求,則會提示哪一行有問題:
修正后,再次部署:
4.2?如何部署?Deployment?
第一步:準備?Deployment?的?yaml?文件。首先來看?Deployment?的?yaml?文件內容:
apiVersion:?extensions/v1beta1
kind:?Deployment
metadata:
name:?rss-site
namespace:?mem-example
spec:
replicas:?2
template:
metadata:
labels:
app:?web
spec:
containers:
-?name:?memory-demo-ctr
image:?polinux/stress
resources:
limits:
emory:?"200Mi"
requests:
memory:?"100Mi"
command:?[?"stress"]
args:?[?"--vm",?"1",?"--vm-bytes",?"150M",?"--vm-hang",?"1"]
volumeMounts:
-?name:?redis-storage
mountPath:?/data/redis
volumes:
-?name:?redis-storage
emptyDir:?{}
繼續來看幾個重要的字段:
metadata?同?Pod?的?yaml,這里提一點:如果沒有指明?namespace,那么就是用?kubectl?默認的?namespace(如果?kubectl?配置文件中沒有指明?namespace,那么就是?default?空間)。
spec,可以看到?Deployment?的?spec?字段是在?Pod?的?spec?內容外“包了一層”,那就來看?Deployment?有哪些需要注意的:
metadata,新手同學先不管這邊的信息。
spec,會發現這完完全全是上文提到的?Pod?的?spec?內容,在這里寫明了?Deployment?下屬管理的每個?Pod?的具體內容。
replicas,副本個數。也就是該?Deployment?需要起多少個相同的?Pod,如果用戶成功在?Kubernetes?中配置了?n(n>1)個,那么?Deployment?會確保在集群中始終有?n?個服務在運行。
template。
第二步:執行?kubectl?命令部署。Deployment?的部署辦法同?Pod:kubectl?create?-f?${DEPLOYMENT_YAML}。由此可見,Kubernetes?會根據配置文件中的kind字段來判斷具體要創建的是什么資源。
這里插一句題外話:部署完?Deployment?之后,可以查看到自動創建了?ReplicaSet?和?Pod,如下圖所示:
還有一個有趣的事情:通過?Deployment?部署的服務,其下屬的?RS?和?Pod?命名是有規則的。讀者朋友們自己總結發現哦。
綜上,如何部署一個?Pod?或者?Deployment?就結束了。
5.?kubectl?查看、更新/編輯、刪除服務
作為?Kubernetes?使用者而言,更關心的問題應該是本章所要討論的話題:如何通過?kubectl?查看、更新/編輯、刪除在?Kubernetes?上部署著的服務。
5.1?如何查看服務?
請務必記得一個事情:在?Kubernetes?中,一個獨立的服務即對應一個?Pod。即,當我們說要?xxx?一個服務的就是,也就是操作一個?Pod。而與?Pod?服務相關的且需要用戶關心的,有?Deployment。
通過?kubectl?查看服務的基本命令是:
$?kubectl?get|describe?${RESOURCE}[-o?${FORMAT}]?-n=?${NAMESPACE}
#?${RESOURCE}有:?pod、deployment、replicaset(rs)
在此之前,還有一個需要回憶的事情是:Deployment、ReplicaSet?和?Pod?之間的關系?——?層層隸屬;以及這些資源和?namespace?的關系是?——?隸屬。如下圖所示:
因此,要查看一個服務,也就是一個?Pod,必須首先指定?namespace!那么,如何查看集群中所有的?namespace?呢?kubectl?get?ns:
于是,只需要通過?-n=${NAMESPACE}?就可以指定自己要操作的資源所在的?namespace。比如查看?Pod:kubectl?get?pod?-n=oona-test,同理,查看?Deployment:kubectl?get?deployment?-n=oona-test。
問題又來了:如果已經忘記自己所部屬的服務所在的?namespace?怎么辦?這么多?namespace,一個一個查看過來嗎?
kubectl?get?pod?--all-namespaces
這樣子就可以看到所有?namespace?下面部署的?Pod?了!同理,要查找所有的命名空間下的?Deployment?的命令是:kubectl?get?deployment?--all-namespaces。
于是,就可以開心地查看?Pod:kubectl?get?pod?[-o?wide]?-n=oona-test,或者查看?Deployment:kubectl?get?deployment?[-o?wide]?-n=oona-test。
哎,這里是否加?-o?wide?有什么區別嗎?實際操作下就明白了,其他資源亦然:
哎,我們看到之前部署的?Pod?服務?memory-demo?顯示的“ImagePullBackOff”是怎么回事呢?先不著急,我們慢慢看下去。
5.2?如何更新/編輯服務?
兩種辦法:1).?修改?yaml?文件后通過?kubectl?更新;2).?通過?kubectl?直接編輯?Kubernetes?上的服務。
方法一:修改?yaml?文件后通過?kubectl?更新。我們看到,創建一個?Pod?或者?Deployment?的命令是?kubectl?create?-f?${YAML}。但是,如果?Kubernetes?集群當前的?namespace?下已經有該服務的話,會提示資源已經存在:
通過?kubectl?更新的命令是?kubectl?apply?-f?${YAML},我們再來試一試:
備注:命令?kubectl?apply?-f?${YAML}?也可以用于首次創建一個服務哦。
方法二:通過?kubectl?直接編輯?Kubernetes?上的服務。命令為kubectl?edit?${RESOURCE}?${NAME},比如修改剛剛的?Pod?的命令為kubectl?edit?pod?memory-demo,然后直接編輯自己要修改的內容即可。
但是請注意,無論方法一還是方法二,能修改的內容還是有限的,從筆者實戰下來的結論是:只能修改/更新鏡像的地址和個別幾個字段。如果修改其他字段,會報錯:
The?Pod?"memory-demo"?is?invalid:?spec:?Forbidden:?pod?updates?may?not?change?fields?other?than?spec.containers[].image,?spec.initContainers[].image,?spec.activeDeadlineSeconds?or?spec.tolerations?(only?additions?to?existing?tolerations)
如果真的要修改其他字段怎么辦呢?恐怕只能刪除服務后重新部署了。
5.3?如何刪除服務?
在?Kubernetes?上刪除服務的操作非常簡單,命令為?kubectl?delete?${RESOURCE}?${NAME}。比如刪除一個?Pod?是:kubectl?delete?pod?memory-demo,再比如刪除一個?Deployment?的命令是:kubectl?delete?deployment?${DEPLOYMENT_NAME}。但是,請注意:
如果只部署了一個?Pod,那么直接刪除該?Pod?即可;
如果是通過?Deployment?部署的服務,那么僅僅刪除?Pod?是不行的,正確的刪除?方式應該是:先刪除?Deployment,再刪除?Pod。
關于第二點應該不難想象:僅僅刪除了?Pod?但是?Deployment?還在的話,Deployment?定時會檢查其下屬的所有?Pod,如果發現失敗了則會再拉起。因此,會發現過一會兒,新的?Pod?又被拉起來了。
另外,還有一個事情:有時候會發現一個?Pod?總也刪除不了,這個時候很有可能要實施強制刪除措施,命令為?kubectl?delete?pod?--force?--grace-period=0?${POD_NAME}。
6.?kubectl?排查服務問題
上文說道:部署的服務?memory-demo?失敗了,是怎么回事呢?本章就會帶大家一起來看看常見的?Kubernetes?中服務部署失敗、服務起來了但是不正常運行都怎么排查呢?
首先,祭出筆者最愛的一張?Kubernetes?排查手冊,來自博客《?Kubernetes?Deployment?故障排除圖解指南?》:
哈哈哈,對于新手同學來說,上圖還是不夠友好,下面我們簡單來看兩個例子:
6.1?Kubernetes?上部署服務失敗了怎么排查?
請一定記住這個命令:kubectl?describe?${RESOURCE}?${NAME}。比如剛剛的?Pod?服務?memory-demo,我們來看:
拉到最后看到Events部分,會顯示出?Kubernetes?在部署這個服務過程的關鍵日志。這里我們可以看到是拉取鏡像失敗了,好吧,大家可以換一個可用的鏡像再試試。
一般來說,通過?kubectl?describe?pod?${POD_NAME}?已經能定位絕大部分部署失敗的問題了,當然,具體問題還是得具體分析。大家如果遇到具體的報錯,歡迎分享交流。
6.2?Kubernetes?上部署的服務不正常怎么排查?
如果服務部署成功了,且狀態為?running,那么就需要進入?Pod?內部的容器去查看自己的服務日志了:
查看?Pod?內部某個?container?打印的日志:kubectl?log?${POD_NAME}?-c?${CONTAINER_NAME}。
進入?Pod?內部某個?container:kubectl?exec?-it?[options]?${POD_NAME}?-c?${CONTAINER_NAME}?[args],嗯,這個命令的作用是通過?kubectl?執行了?docker?exec?xxx?進入到容器實例內部。之后,就是用戶檢查自己服務的日志來定位問題。
顯然,線上可能會遇到更復雜的問題,需要借助更多更強大的命令和工具。
寫在后面
本文希望能夠幫助對?Kubernetes?不了解的新手快速了解?Kubernetes。筆者一邊寫文章,一邊查閱和整理?Kubernetes?資料,過程中越發感覺?Kubernetes?架構的完備、設計的精妙,是值得深入研究的,Kubernetes?大受歡迎是有道理的。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。