本章節(jié)將繼續(xù)分享關于kubernetes中的一些重要概念。
一、Pod
Pod 是 Kubernetes 的最小工作單元。每個 Pod 包含一個或多個容器。Pod 中的容器會作為一個整體被 Master 調(diào)度到某個 Node 上運行。(可以把pod想象成豌豆莢,里面的豌豆就是容器,可以有一個或多個。)
說到Pod,簡單介紹其概念。首先,Pod運行在一個我們稱之為節(jié)點(Node)的環(huán)境中,這個節(jié)點可能是物理機或虛擬機,通常一個節(jié)點上上面運行幾百個Pod;其次每個Pod運行著一個特殊的被稱之為根容器(Pause),和一組用戶容器組成。一方面,用Pause 容器的狀態(tài)代表整個容器組的狀態(tài);另一方面,這些業(yè)務容器共享根容器(Pause)的網(wǎng)絡棧和Volume掛載卷,因此它們之間的通信和數(shù)據(jù)交換效率更為高效。在設計時我們可以充分利用這一特性將一組密切相關的服務進程放到同一個Pod中。最后需要注意的是并不是每一個Pod和它里面運行的容器都能映射到一個Service上,只有那些提供服務的一組Pod才會被映射成一個服務。
Kubernetes 引入 Pod 主要基于下面兩個目的:
- 可管理性:
在一組容器作為一個單元的情況下,我們難以對“整體”簡單地進行判斷及有效地進行行動。比如,一個容器死亡了,此時算是整體死亡么?引入業(yè)務無關并且不易死亡的Pause容器作為Pod的根容器,以它的狀態(tài)代表整體容器組的狀態(tài),就簡單、巧妙地解決了這個難題。 - 通信和資源共享:
Pod里的多個業(yè)務容器共享Pause容器的IP,即相同的 IP 地址和 Port 空間。它們可以直接用 localhost 通信。同樣的,這些容器可以共享存儲,當 Kubernetes 掛載 volume 到 Pod,本質(zhì)上是將 volume 掛載到 Pod 中的每一個容器。這樣既簡化了密切關聯(lián)的業(yè)務容器之間的通信問題,也很好地解決了它們之間的文件共享問題。
靜態(tài)Pod & 普通Pod
-
普通的Pod:
普通Pod一旦被創(chuàng)建,就會被放入到etcd中存儲,隨后會被Kubernetes Master調(diào)度到某個具體的Node上并進行綁定(Binding),隨后該Pod 被對應的Node上的kubelet進程實例化成一組相關的docker容器運行起來。
當Pod里的某個容器停止時,Kubernetes會自動檢測到這個問題并且重新啟動這個Pod (重啟Pod里的所有容器),如果Pod所在的Node宕機,則會將這個Node上所有的Pod從新調(diào)度到其他節(jié)點上。 -
靜態(tài)Pod (Static Pod):
靜態(tài)Pod不存放在Kubernetes的etcd存儲里,而是存放在某個具體的Node上的文件夾中(如果是k8s集群是通過kubeadm部署的,該文件夾默認是/etc/kubernetes/manifests/),并且只在此Node上啟動運行。
靜態(tài)Pod是由kubelet進行管理的僅存在于特定Node上的Pod。他們不能通過API Server進行管理,無法與ReplicationController(RC)、Deployment、或者DaemonSet進行關聯(lián),并且kubelet也無法對它們進行健康檢查。靜態(tài)Pod總是由kubelet進行創(chuàng)建的,并且總是在kubelet所在的Node上運行的
副本控制器類型(Pod叫副本)
ReplicationController (簡稱為RC)
ReplicaSet (簡稱為RS)
Deployment
StatefulSet
DaemonSet
Job,Cronjob
Pods 有兩種使用方式:
運行單一容器:
one-container-per-Pod 是 Kubernetes 最常見的模型,這種情況下,只是將單個業(yè)務容器簡單封裝成 Pod。即便是只有一個容器,Kubernetes 管理的也是 Pod 而不是直接管理容器。
運行多個容器:
但問題在于:哪些容器應該放到一個 Pod 中?
答案是:這些容器聯(lián)系必須 非常緊密,而且需要 直接共享資源。
示例:
下面這個 Pod 包含兩個容器:一個 File Puller,一個是 Web Server。他們兩個container的net namespace、uts namespace、ipc namespace是屬于共享的。 mnt namespace、user namespace、pid namespace是互相隔離的。
Kubernetes里的所有資源對象都可以采用yaml或者JSON格式的文件來定義或描述,下面是我們在之前Hello World例子里用到的myweb這個Pod的資源定義文件:
apiVersion: v1
kind: Pod
metadata:
name: myweb
spec:
containers:
- name: myweb
image: tomcat:jre8
ports:
- containerPort: 8080
env:
- name: MYSQL_SERVICE_HOST
value: 'mysql'
- name: MYSQL_SERVICE_PORTT
value: '3306'
說明:kind為Pod表明這是一個Pod的定義,metadata里的name屬性為Pod的名字,metadata里還能定義資源對象的標簽(Label),這里表明myweb擁有一個name=myweb的標簽(Label)。Pod里所包含的容器組的定義是在spec中,這里定義了一個名字為myweb、對應鏡像為tomcat:jre8的容器,該容器注入了名為MYSQL_SERVICE_HOST='mysql’和MYSQL_SERVICE_PORT='3306’的環(huán)境變量(env關鍵字),并且在8080端口(containerPort)上啟動容器進程。
Pod的IP加上這里的容器端口(containerPort),就組成了一個新的概念 --Endpoint,它代表著此Pod里的一個服務進程的對外通信地址。
我們所熟悉的Docker Volume在Kubernetes里也有對應的概念 — Pod Volume,后者有一些擴展,比如可以用分布式文件系統(tǒng)ceph實現(xiàn)后端存儲功能;Pod Volume是定義在Pod之上,然后被各個容器掛載到自己的文件系統(tǒng)中。
順便提一下Kubernetes的Event概念,Event是一個事件的記錄,記錄了事件的最早產(chǎn)生時間、最后重現(xiàn)時間、重復次數(shù)、發(fā)起者、類型,以及導致此事件的原因等眾多信息。Event通常會關聯(lián)到某個具體的資源對象上,是排查故障的重要參考信息,之前我們看到Node的描述信息包括了Event,而Pod同樣有Event記錄,用來發(fā)現(xiàn)某個Pod遲遲無法創(chuàng)建時,可以用kubectl describe pod xxxx來查看它的描述信息,用來定位問題的原因,比如下面這個Event記錄信息表明Pod里的一個容器被探針檢測失敗一次:
[root@k8s-m1 ~]# kubectl describe po -n metallb-system speaker-t44hq
......(省略了一部分)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning BackOff 59s (x26996 over 4d1h) kubelet Back-off restarting failed container
每個Pod都可以對其能使用的服務器上的計算資源設置限額,當前可以設置限額的計算資源有CPU與Memory兩種,其中CPU的資源單位為CPU(Core)的數(shù)量,是一個絕對值而非相對值。
一個CPU的配額對于絕大多數(shù)容器來說是相當大的一個資源配額了,所以,在Kubernetes里,通常以千分之一的CPU配額為最小單位,用m來表示。通常一個容器的CPU配額被定義為100~300m,即占用0.1~0.3個CPU。由于CPU配額是一個絕對值,所以無論在擁有一個Core的機器上,還是在擁有48個Core的機器上,100m這個配額所代表的CPU的使用量都是一樣的。與CPU配額類似,Memory配額也是一個絕對值,它的單位是內(nèi)存字節(jié)數(shù)。
在Kubernetes里,一個計算資源進行配額限定需要設定以下兩個參數(shù)。
Request:該資源的最小申請量,系統(tǒng)必須滿足要求。
Limits:該資源最大允許使用量,不能被突破,當容器試圖使用超過這個量的資源時,可能會被Kubernetes Kill并重啟。
通常我們會把Request設置為一個比較小的數(shù)值,符合容器平時的工作負載情況下的資源需求,而把Limit設置為負載均衡情況下資源占用的最大量。比如下面這些定義,表明MySQL容器申請最少0.3個CPU及128MiB內(nèi)存,在運行過程中MySQL容器所能使用的資源配額最大為0.6個CPU及256MiB內(nèi)存:
spec:
containers:
- name: mydb
image: mysql
resources:
requests:
memory: "128Mi"
cpu: "300m"
limits:
memory: "256Mi"
cpu: "600m"
最后給出Pod及Pod周邊對象的示意圖作為總結(jié),如圖所示,后面部分涉及這張圖里的對象和概念,以進一步加強理解。
二、Lable
Label是Kubernetes系統(tǒng)中另外一個核心概念。一個Label是一個key=value的鍵值對,其中key與vaue由用戶自己指定。Label可以附加到各種資源對象上,例如Node、Pod、Service、RC等,一個資源對象可以定義任意數(shù)量的Label,同一個Label也可以被添加到任意數(shù)量的資源對象上去,Label通常在資源對象定義時確定,也可以在對象創(chuàng)建后動態(tài)添加或者刪除。
我們可以通過指定的資源對象捆綁一個或多個不同的Label來實現(xiàn)多維度的資源分組管理功能,以便于靈活、方便地進行資源分配、調(diào)度、配置、部署等管理工作。例如:部署不同版本的應用到不同的環(huán)境中;或者監(jiān)控和分析應用(日志記錄、監(jiān)控、告警)等。一些常用等label示例如下
版本標簽:“release”:“stable”,“release”:“canary”…
環(huán)境標簽:“environment”:“dev”,“environment”:“qa”,“environment”:“production”
架構(gòu)標簽:“tier”:“fronted”,“tier”:“backend”,“tier”:"middleware”
分區(qū)標簽:“partition”:“customerA”,“partition”:"customerB”…
質(zhì)量管控標簽:“track”:“daily”:“rack”:“weekly”
Label相當于我們熟悉的“標簽”,給某個資源對象定義一個Label,就相當于給它打了一個標簽,隨后可以通過Label Selector(標簽選擇器)查詢和篩選擁有某些Label的資源對象,Kubernetes通過這種方式實現(xiàn)了類似SQL的簡單又通用的對象查詢機制。
Label Selector可以被類比為SQL語句中的where查詢條件,例如,name=redis-slave這個label Selector作用于Pod時,可以被類比為select * from pod where pod’s name = 'redis-slave’這樣的語句。當前有兩種Label Selector的表達式:基于等式的(Equality-based)和基于集合的(Set-based),前者采用“等式類”的表達式匹配標簽,下面是一些具體的例子。
-
基于等式的表達式匹配標簽實例:
name=redis-slave:匹配所有具有標簽name=redis-slave的資源對象。
env != production:匹配所有不具有標簽env=production的資源對象。 -
基于集合方式的表達式匹配標簽實例:
name in (redis-master,redis-slave):匹配所有具有標簽name=redis-master或者name=redis-slave的資源對象。
name notin (php-frontend):匹配所有不具有標簽name=php-frontend的資源對象。
可以通過多個Label Selector表達式的組合實現(xiàn)復雜的條件,多個表達式之間用“,”進行分隔即可,幾個條件之間是“AND”的關系,即同時滿足多個條件,比如下面的例子:
name=redis-slave,env!=production
name notin (php-fronted),env!=production
Label Selector在Kubernetes中重要使用場景有以下幾種:
- kube-controller進程通過資源對象RC上定義都Label Selector來篩選要監(jiān)控的Pod副本的數(shù)量,從而實現(xiàn)Pod副本的數(shù)量始終符合預期設定的全自動控制流程。
- kube-proxy進程通過Service的Label Selector來選擇對應的Pod,自動建立起每個Service到對應Pod的請求轉(zhuǎn)發(fā)路由表,從而實現(xiàn)Service的智能負載均衡機制。
通過對某些Node定義特定的Label,并且在Pod定義文件中使用NodeSelector這種標簽調(diào)度策略,kube-scheduler進程可以實現(xiàn)Pod“定向調(diào)度”的特性。 - 前面我們只是介紹了一個name=XXX的Label Selector。讓我們看一個更復雜的例子。假設為Pod定義了Label: release、env和role,不同的Pod定義了不同的Label值,如圖下圖所示,如果我們設置了“role=frontend”的Label Selector,則會選取到Node 1和Node 2上到Pod。
而設置“release=beta”的Label Selector,則會選取到Node 2和Node 3上的Pod,如下圖所示。
總結(jié):使用Label可以給對象創(chuàng)建多組標簽,Label和Label Selector共同構(gòu)成了Kubernetes系統(tǒng)中最核心的應用模型,使得被管理對象能夠被精細地分組管理,同時實現(xiàn)了整個集群的高可用性。
三、Annotation
可以使用 Kubernetes Annotation(注解)為對象附加任意的非標識的元數(shù)據(jù)自定義信息。
Annotation與Label類似,也使用key/value鍵值對的形式進行定義。不同的是Label具有嚴格的命名規(guī)則,Label定義的是Kubernetes對象的元數(shù)據(jù)(Metadata),并且用于Label Selector(標簽選擇器)。而Annotation(注解)則是用戶任意定義的“附加”信息,便于用戶自行的一些查找行為。
注解和標簽一樣,是鍵/值對的:
“metadata”: {
“annotations”: {
“key1” : “value1”,
“key2” : “value2”
}
}
說明:
Map 中的鍵和值必須是字符串。也就是說,你不能使用數(shù)字、布爾值、列表或其他類型的鍵或值。
以下是一些例子,用來說明哪些信息可以使用注解來記錄:
build信息、release信息、Docker鏡像信息等,例如時間戳、release id號、鏡像hash值、docker registry地址等。
日志庫、監(jiān)控庫、分析庫等資源庫的地址信息。
程序調(diào)試工具信息,例如工具、版本號等。
團隊等聯(lián)系信息,例如各種聯(lián)系方式、負責人名稱、網(wǎng)址等。
例如,下面是一個 Pod 的配置文件,其注解中包含 imagebuilder: “margu_168”
[root@k8s-m1 tmp]# cat anno.yaml
apiVersion: v1
kind: Pod
metadata:
name: annotations-test
annotations:
imagebuilder: "margu_168"
spec:
containers:
- name: nginx
image: nginx:1.20.1
ports:
- containerPort: 80
其實一般的pod我們不會添加annotation,在使用ingress-nginx,我們常常通過annotation添加一些關于nginx額外的配置,如rewrite-target、use-regex等等。文章來源:http://www.zghlxwxcb.cn/news/detail-508162.html
更多關于kubernetes的知識分享,請前往博客主頁。編寫過程中,難免出現(xiàn)差錯,敬請指出文章來源地址http://www.zghlxwxcb.cn/news/detail-508162.html
到了這里,關于【kubernetes系列】Kubernetes之pod、lable和annotation的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!