K8S主要概念大梳理!
本文轉(zhuǎn)載自微信公眾號(hào)「小姐姐味道」,作者小姐姐養(yǎng)的狗02號(hào)。轉(zhuǎn)載本文請(qǐng)聯(lián)系小姐姐味道公眾號(hào)。
k8s已經(jīng)成為了絕對(duì)熱門的技術(shù),一個(gè)上點(diǎn)規(guī)模的公司,如果不搞k8s,都不好意思出去見(jiàn)人。安裝k8s要突破種種網(wǎng)絡(luò)阻礙,但更大的阻礙還在后面...
我發(fā)現(xiàn),很多k8s的文章,根本不說(shuō)人話,包括那要命的官網(wǎng)。
要弄明白k8s的細(xì)節(jié),需要知道k8s是個(gè)什么東西。它的主要功能,就是容器的調(diào)度--也就是把部署實(shí)例,根據(jù)整體資源的使用狀況,部署到任何地方。先不要扯別的,那會(huì)擾亂視線,增加復(fù)雜性。
注意任何這兩個(gè)字,預(yù)示著你并不能夠通過(guò)常規(guī)的IP、端口方式訪問(wèn)部署的實(shí)例。復(fù)雜性由此而生。
我們學(xué)k8s,就要看它要調(diào)度哪些資源。以傳統(tǒng)的感覺(jué)來(lái)看,無(wú)非就是cpu、內(nèi)存、網(wǎng)絡(luò)、io等。在了解怎么對(duì)這些資源調(diào)度之前,先要搞懂什么叫Pod,這可是k8s的核心概念之一。
搞不懂Pod,就沒(méi)法玩k8s。
本文的腦圖,可以在這里在線查看:http://mind.xjjdog.cn/mind/cloud-k8s
1. Pod
pod是k8s調(diào)度的最小單元,包含一個(gè)或者多個(gè)容器(這里的容器你可以暫時(shí)認(rèn)為是docker)。
Pod擁有一個(gè)唯一的IP地址,在包含多個(gè)容器的時(shí)候,依然是擁有一個(gè)IP地址,它是怎么辦到的呢?
xjjdog之前寫(xiě)過(guò)兩篇Docker原理的文章,指出其中兩個(gè)使用到的底層技術(shù),就是namespace和cgroup,k8s在使用多個(gè)容器的時(shí)候,用到的就是共享namespace,這樣Pod里的容器就可以通過(guò)localhost通信了,就像兩個(gè)進(jìn)程一樣。同理的,Pod 可以掛載多個(gè)共享的存儲(chǔ)卷(Volume),這時(shí)內(nèi)部的各個(gè)容器就可以訪問(wèn)共享的 Volume 進(jìn)行數(shù)據(jù)的讀寫(xiě)。
一些邊車(Sidecar),以及存活探針等,也是以容器的形式,存在于Pod中的。所以Pod是一個(gè)大雜燴,它取代了docker容器的一部分工作(這既是Pause容器的職責(zé)),比如創(chuàng)建一些共享的net namespace等。
那如何表示、聲明一個(gè)Pod呢?又如何指定這些容器與Pod的關(guān)系呢?k8s選用了yaml這種配置方式,初衷是避免過(guò)度的API設(shè)計(jì)。
很好,這又引入了另外一個(gè)問(wèn)題,那就是yml文件的膨脹。所有的k8s運(yùn)維,都有過(guò)被yml文件給支配的恐懼。
沒(méi)有銀彈,只不過(guò)把問(wèn)題轉(zhuǎn)移到另外一個(gè)場(chǎng)景罷了。
聲明一個(gè)Pod,就是寫(xiě)yml文件。一個(gè)Pod的yml樣例,可能長(zhǎng)得像下面這樣。
- apiVersion: v1 #本版號(hào)
- kind: Service #創(chuàng)建的資源類型
- metadata: #元數(shù)據(jù)必選
- namespace: bcmall #綁定命名空間
- name: bcmall-srv #Service資源名稱
- spec: #定義詳細(xì)信息
- type: NodePort #類型
- selector: #標(biāo)簽選擇器
- app: container-bcmall-pod
- ports: #定義端口
- - port: 8080 #port 指定server端口,此端口用于集群內(nèi)部訪問(wèn)
- targetPort: 80 #綁定pod端口
- nodePort: 14000 #將server 端口映射到Node節(jié)點(diǎn)的端口,用于外網(wǎng)訪問(wèn)
- protocol: TCP #端口協(xié)議
注意kind這個(gè)選項(xiàng),這將是k8s概念膨脹的噩夢(mèng)!k8s的各種配置,基本上都是圍著這里轉(zhuǎn)。哦對(duì)了,要讓這些yml文件生效,你需要用到kubectl 命令,就像這樣。
- kubectl create -f ./bcmall.yaml
訪問(wèn)一個(gè)Pod,可以通過(guò)它的IP,也可以通過(guò)內(nèi)部的域名(這時(shí)候就需要CoreDNS)。當(dāng)這么用的時(shí)候,其實(shí)Pod的表現(xiàn),就相當(dāng)于一臺(tái)普通的機(jī)器,里面的容器就是一堆進(jìn)程而已。
2. 探針和鉤子
一個(gè)Pod被調(diào)度之后,就要進(jìn)行初始化。初始化肯定是得有一個(gè)反饋的,否則都不知道最終有沒(méi)有啟動(dòng)成功。這些健康檢查的功能,叫做探針(Probe),一個(gè)比較怪異的英文名詞。
常見(jiàn)的有l(wèi)ivenessProbe、readinessProbe、startupProbe等三種探針。
livenessProbe有點(diǎn)像心跳,如果判定不在線了,就會(huì)把它干掉;readinessProbe一般表示就緒狀態(tài),也比較像心跳,證明你的服務(wù)在正常跑著;startupProbe用于判斷容器是否已經(jīng)啟動(dòng)好,避免一些超時(shí)等,比如你的JVM啟動(dòng)完畢了,才能對(duì)外提供服務(wù)。
一般,花費(fèi)120s startupProbe的啟動(dòng)實(shí)踐,每隔5s檢測(cè)一下livenessProbe,每隔10s檢測(cè)一下readinessProbe,是常用的操作。
這些信息,也是在yml中配置的,具體的配置層次如何,這里不羅嗦,您就查文檔去吧。
再說(shuō)一下鉤子(Hook)。主要有PostStart和PreStop兩種。PostStart 可以在容器啟動(dòng)之后就執(zhí)行,PreStop 則在容器被終止之前被執(zhí)行。這沒(méi)什么神奇的,就是執(zhí)行一些shell腳本而已,只不過(guò)比較常用,就提升到了關(guān)鍵字的級(jí)別。
我們來(lái)看看它長(zhǎng)什么樣子。由于這些配置文件大同小異,后面就不再貼這樣的代碼了。
- apiVersion: v1
- kind: Pod
- metadata:
- labels:
- test: liveness
- name: liveness-exec
- spec:
- containers:
- - name: liveness
- image: k8s.gcr.io/busybox
- args:
- - /bin/sh
- - -c
- - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
- livenessProbe:
- exec:
- command:
- - cat
- - /tmp/healthy
- initialDelaySeconds: 5
- periodSeconds: 5
3. 高可用引起的名詞爆炸
上面說(shuō)到,yaml的復(fù)雜性,是由于kind的種類多所引起的。首先我們要接觸的,就是ReplicaSet。
我們需要多個(gè)副本,才能做高可用。
原因很簡(jiǎn)單,一個(gè)Pod就相當(dāng)于一臺(tái)機(jī)器,當(dāng)?shù)糁螅蜔o(wú)法提供服務(wù)了,這是哪門子的高可用?所以對(duì)等的Pod,要有多份才行。
ReplicaSet簡(jiǎn)稱RS,可以讓你的Pod數(shù)量一直保持在某個(gè)水平。但它在操作起來(lái)還是有點(diǎn)麻煩了,所以一般使用更加高級(jí)的Deployment。Deployment可以實(shí)現(xiàn)一些滾動(dòng)升級(jí)的需求,但前提是你需要在spec.template.metadata.labels中設(shè)置了相應(yīng)的鍵值對(duì)。
k8s的一些過(guò)濾工作,都是通過(guò)labels來(lái)實(shí)現(xiàn)的。這其實(shí)是一種非常折衷的做法,因?yàn)樗旧聿](méi)有做一些類似于sql查詢之類的工作,就只能在這一堆map的鍵值對(duì)上做文章。比如這樣:
- kubectl get pod -n demo -l app=nginx,version=v1
是不是很魔幻的寫(xiě)法?不要緊,習(xí)慣了就好了。
這些yml配置,通常都是一環(huán)套一環(huán)的,還會(huì)有交叉引用,所以也會(huì)有優(yōu)先級(jí)。高階的kind會(huì)直接順帶把低階的kind一起創(chuàng)建了,屬于一個(gè)級(jí)聯(lián)關(guān)系。
一切不過(guò)是yml文件包了一層而已。
好了,我們要接觸下一個(gè)kind:service了。
為什么需要Service?因?yàn)槲覀兩厦鎰?chuàng)建的Pod,哪怕是Deployment創(chuàng)建的Pod,你訪問(wèn)它都要費(fèi)些功夫。雖然Pod有IP,但如果它重啟了,或者銷毀了,IP就會(huì)動(dòng)態(tài)變化。因?yàn)镻od是被調(diào)度的,它并不知道自己會(huì)被調(diào)度到哪一臺(tái)機(jī)器。
Service這個(gè)東西,就是要提供一種非IP的訪問(wèn)途徑,使得不論P(yáng)od在哪里,我們都能訪問(wèn)的到它。
如圖所示,通過(guò)Labels的過(guò)濾,可以把多個(gè)Pod歸結(jié)為一類,然后以某種類型對(duì)外暴露服務(wù)。Service說(shuō)白了也是一個(gè)組合后的東西。
對(duì)外訪問(wèn)的類型,這里要著重說(shuō)明一下,因?yàn)樗匾?,所以要敲黑板。主要?種:
ClusterIP 創(chuàng)建一個(gè)虛擬的IP,唯一且不可修改。所有訪問(wèn)該IP的請(qǐng)求,都將被iptables轉(zhuǎn)發(fā)到后端。這是默認(rèn)的行為,就是一個(gè)coredns的插件
NodePort 提供一個(gè)靜態(tài)端口(NodePort)來(lái)暴露服務(wù),主要使用的技術(shù)是NAT
LoadBalancer LoadBalancer主要用于做外部的服務(wù)發(fā)現(xiàn),即暴露給集群外部的訪問(wèn)
ExternalName 使用較少,感興趣的可以自行了解
但是等等。k8s是如何實(shí)現(xiàn)跨主機(jī)的Pod相互訪問(wèn)的呢?
在單個(gè)Node上的Pod相互訪問(wèn)可以理解,直接通過(guò)docker0網(wǎng)橋分配的IP,就可相互訪問(wèn)。
那k8s的底層網(wǎng)絡(luò)是真么設(shè)置的呢?答案可能令人沮喪。k8s本身并不負(fù)責(zé)網(wǎng)絡(luò)管理,也不為容器提供具體的網(wǎng)絡(luò)設(shè)置,它是通過(guò)CNI(容器網(wǎng)絡(luò)接口)來(lái)實(shí)現(xiàn)的。在不同的Node之上,不同的Pod訪問(wèn)就費(fèi)了點(diǎn)勁,這正是CNI的工作。常用的CNI插件有:Flannel、Calico、Canal、Weave。
沒(méi)錯(cuò),又是一堆名詞,而且各個(gè)都很難搞。
網(wǎng)絡(luò)方面是k8s最復(fù)雜的知識(shí)點(diǎn),框架也奇多,后面的文章會(huì)專門進(jìn)行介紹。
4. 內(nèi)部組件
在開(kāi)啟更多的Kind之前,我們來(lái)看一下k8s的內(nèi)部組件。
下面這張圖,就是官網(wǎng)的一張圖片,說(shuō)明了k8s的一系列必要的組件。其中,etcd根本就不是這個(gè)體系里的,但k8s的一些持久化狀態(tài),需要有個(gè)地方存,就引入了這么一個(gè)組件,用來(lái)存儲(chǔ)配置信息。
其中左半部分,是k8s自身的組件;右半部分,就在每個(gè)Node(也就是物理機(jī))上的守護(hù)進(jìn)程。它們的作用如下:
- kube-apiserver 提供Rest接口,屬于k8s的靈魂,所有的認(rèn)證、授權(quán)、訪問(wèn)控制、服務(wù)發(fā)現(xiàn)等功能,都通過(guò)它來(lái)暴露
- kube-scheduler 一看就是個(gè)調(diào)度組件,實(shí)際上它的作用也是這樣。它會(huì)監(jiān)聽(tīng)未調(diào)度的 Pod,實(shí)現(xiàn)你指定的目標(biāo)
- kube-controller-manager 負(fù)責(zé)維護(hù)整個(gè)k8s集群的狀態(tài)。注意是k8s集群的狀態(tài),它不管Pod
- kubelet 這是個(gè)守護(hù)進(jìn)程,用來(lái)和apiserver通信,匯報(bào)自己Node的狀態(tài);一些調(diào)度命令,也是通過(guò)kubelet來(lái)接收?qǐng)?zhí)行任務(wù)
- kube-proxy kube-proxy其實(shí)就是管理service的訪問(wèn)入口,包括集群內(nèi)Pod到Service的訪問(wèn)和集群外訪問(wèn)service。我們上面提到的四種模式,就是通過(guò)proxy進(jìn)行轉(zhuǎn)發(fā)的
這些組件的職責(zé),已經(jīng)是非常非常清楚了。難點(diǎn)還是在多種Kind概念上。
5. 更多概念
圖中的這些概念,本質(zhì)上都是在Pod之上,又包了一層。層次越高,功能越抽象,依賴的配置也越多。下面將挑主要的進(jìn)行介紹。
- StatefulSet Deployment部署后的實(shí)例,它的id都是隨機(jī)的,比如bcmall-deployment-5d45f98bd9,它是無(wú)狀態(tài)的。與此對(duì)用的是StatefulSet,生成的實(shí)例名稱是類似bcmall-deployment-1這樣的。它具備固定的網(wǎng)絡(luò)標(biāo)記,比如主機(jī)名,域名等,可以按照順序來(lái)部署和擴(kuò)展,非常適合類似MySQL這樣的實(shí)例部署
- DaemonSet 用于確保集群中的每一個(gè)節(jié)點(diǎn)只運(yùn)行特定的pod副本,通常用于實(shí)現(xiàn)系統(tǒng)級(jí)后臺(tái)任務(wù)
- configMap和Secret 顧名思義,就是做配置用的,因?yàn)槿萜骰蚨嗷蛏贂?huì)需要外部傳入一些環(huán)境變量??梢杂脕?lái)實(shí)現(xiàn)業(yè)務(wù)配置的統(tǒng)一管理, 允許將配置文件與鏡像文件分離,以使容器化的應(yīng)用程序具有可移植性
- PV和PVC 業(yè)務(wù)運(yùn)行就需要存儲(chǔ),可以通過(guò)PV進(jìn)行定義。PV的生命周期獨(dú)立于Pod的生命周期,就是一段網(wǎng)絡(luò)存儲(chǔ);PVC是用戶對(duì)于存儲(chǔ)的需求:Pod消耗節(jié)點(diǎn)資源,PVC消耗PV資源,PVC和PV是一一對(duì)應(yīng)的。沒(méi)錯(cuò),它們都是通過(guò)yml文件聲明的
- **StorageClass ** 可以實(shí)現(xiàn)動(dòng)態(tài)PV,是更進(jìn)一步的封裝
- Job 只要完成就立即退出,不需要重啟或重建
- Cronjob 周期性任務(wù)控制,不需要持續(xù)后臺(tái)運(yùn)行
- CRD
6. 資源限制
很好,我們終于要聊一點(diǎn)資源限制方面的內(nèi)容了。k8s的資源限制,仍然是通過(guò)cgroup來(lái)實(shí)現(xiàn)的。
k8s提供了requests和limits 兩種類型參數(shù)對(duì)資源進(jìn)行預(yù)分配和使用限制。
不要被這兩個(gè)詞給迷惑了。requests就相當(dāng)于JVM參數(shù)中的-Xms,limits就相當(dāng)于-Xmx。所以,如果你類比著把這兩個(gè)值設(shè)置成一樣的,是一種最佳的實(shí)踐方式。
只是它的設(shè)置有點(diǎn)怪異:
- requests:
- memory: "64Mi"
- cpu: "250m"
- limits:
- memory: "128Mi"
- cpu: "500m"
內(nèi)存的單位是Mi,而cpu的單位是m,要多別扭有多別扭,但它是有原因的。
m是毫核的意思。比如,我們的操作系統(tǒng)有4核,把它乘以1000,那就是總CPU資源是4000毫核。如果你想要你的應(yīng)用最多占用1/4核,那就設(shè)置成250m。
再來(lái)看內(nèi)存,Mi是MiB的意思,我也搞不懂為啥不用MB,而使用Mi,可能是想讓你印象深刻吧(MB和MiB還真不一樣)。
若內(nèi)存使用超出限制,會(huì)引發(fā)系統(tǒng)的OOM機(jī)制,但CPU不會(huì),頂多會(huì)影響系統(tǒng)運(yùn)行罷了。
k8s還提供了叫做LimitRange和ResourceQuota的Kind,用來(lái)限定CPU和Memory的申請(qǐng)范圍,功能更加高級(jí)。
7. 集群搭建工具
k8s的集群搭建,常見(jiàn)的有kind,minikube,kubeadm,rancher2等。其中rancher2可以說(shuō)是相對(duì)來(lái)說(shuō)比較容易的方式。它考慮了一些網(wǎng)絡(luò)不通的因素,有一些推薦的代理選項(xiàng),對(duì)于新手來(lái)說(shuō),拿來(lái)嘗嘗鮮還是很好用的。
但在正常的使用中,還是推薦你使用kubeadm這個(gè)工具,這是官方維護(hù)和推薦的搭建工具,并做到了向下兼容,按照官方的指引,只需要kubeadm init就能搭建完畢。至于什么監(jiān)控、日志等,反倒是好處理的了。
k8s最麻煩的有三點(diǎn):
- yml文件概念爆炸
- 網(wǎng)絡(luò)方案多樣、復(fù)雜
- 權(quán)限、證書(shū)配置繁瑣
搞懂了這三個(gè)方面,可以說(shuō)玩轉(zhuǎn)k8s就沒(méi)問(wèn)題了。
作者簡(jiǎn)介:小姐姐味道 (xjjdog),一個(gè)不允許程序員走彎路的公眾號(hào)。聚焦基礎(chǔ)架構(gòu)和Linux。十年架構(gòu),日百億流量,與你探討高并發(fā)世界,給你不一樣的味道。我的個(gè)人微信xjjdog0,歡迎添加好友,進(jìn)一步交流。