一、 kubernetes帶來(lái)的變革
1. 對(duì)于開(kāi)發(fā)人員
由于公司業(yè)務(wù)多,開(kāi)發(fā)環(huán)境、測(cè)試環(huán)境、預(yù)生產(chǎn)環(huán)境和生產(chǎn)環(huán)境都是隔離的,而且除了生產(chǎn)環(huán)境,為了節(jié)省成本,其他環(huán)境可能是沒(méi)有日志收集的,在沒(méi)有用k8s的時(shí)候,查看線下測(cè)試的日志,需要開(kāi)發(fā)或者測(cè)試人員,找到對(duì)應(yīng)的機(jī)器,在找到對(duì)應(yīng)的容器,然后才能查看日志,在用了k8s之后,開(kāi)發(fā)和測(cè)試可以直接在k8s的dashboard到對(duì)應(yīng)的namespace,即可定位到業(yè)務(wù)的容器,然后可以直接通過(guò)控制臺(tái)查看到對(duì)應(yīng)的日志,大大降低了操作時(shí)間。
把應(yīng)用部署到k8s之后,代碼的發(fā)布、回滾,以及藍(lán)綠發(fā)布、金絲雀發(fā)布等都變得特別簡(jiǎn)單,不僅加快了業(yè)務(wù)代碼迭代的速度,而且全程無(wú)需人工干預(yù)。目前我們使用jenkins、gitrunner進(jìn)行發(fā)版或者回滾等,從開(kāi)發(fā)環(huán)境到測(cè)試環(huán)境,到生產(chǎn)環(huán)境,完全遵守一次構(gòu)建,多集群、多環(huán)境部署,通過(guò)不同的啟動(dòng)參數(shù)、不同的環(huán)境變量、不同的配置文件實(shí)現(xiàn)區(qū)分不同的環(huán)境。目前已經(jīng)實(shí)現(xiàn)Python、Java、PHP、NodeJS、Go、.NET Core、Python等多種語(yǔ)言的一鍵式發(fā)版、一鍵式回滾,大大提高了開(kāi)發(fā)人員的開(kāi)發(fā)效率。
在使用服務(wù)網(wǎng)格后,開(kāi)發(fā)人員在開(kāi)發(fā)應(yīng)用的過(guò)程中,不用再關(guān)心代碼的網(wǎng)絡(luò)部分,這些功能都被服務(wù)網(wǎng)格實(shí)現(xiàn),讓開(kāi)發(fā)人員可以只關(guān)心代碼邏輯部分,即可實(shí)現(xiàn)網(wǎng)絡(luò)部分的功能,比如:斷流、分流、路由、負(fù)載均衡、限速和觸發(fā)故障等功能。
測(cè)試過(guò)程中,可能同時(shí)多套環(huán)境,當(dāng)然也會(huì)需要再創(chuàng)建一套測(cè)試環(huán)境,之前測(cè)試環(huán)境的創(chuàng)建,需要找運(yùn)維或者自行手工搭建。在遷移至k8s集群后,只需要在jenkins上點(diǎn)點(diǎn)鼠標(biāo)即可在k8s集群上創(chuàng)建一套新的測(cè)試環(huán)境。
2. 對(duì)于運(yùn)維人員
如果你是一名運(yùn)維人員,可能經(jīng)常因?yàn)橐恍┲貜?fù)、繁瑣的工作感覺(jué)厭倦。比如:這個(gè)需要一套新的測(cè)試環(huán)境,那個(gè)需要一套新的測(cè)試環(huán)境,之前可能需要裝系統(tǒng)、裝依賴(lài)環(huán)境、開(kāi)通權(quán)限等等。而如今,可以直接用鏡像直接部署一套新的測(cè)試環(huán)境,甚至全程無(wú)需自己干預(yù),開(kāi)發(fā)人員通過(guò)jenkins或者自動(dòng)化運(yùn)維平臺(tái)即可一鍵式創(chuàng)建,大大降低了運(yùn)維成本。
一開(kāi)始,公司業(yè)務(wù)故障,可能是因?yàn)榛A(chǔ)環(huán)境不一致、依賴(lài)不一致、端口沖突等等問(wèn)題,現(xiàn)在實(shí)現(xiàn)Docker鏡像部署,k8s編排,所有的依賴(lài)、基礎(chǔ)都是一樣的,并且環(huán)境的自動(dòng)化擴(kuò)容、健康檢查、容災(zāi)、恢復(fù)都是全自動(dòng)的,大大減少了因?yàn)檫@類(lèi)基礎(chǔ)問(wèn)題引發(fā)的故障。也有可能公司業(yè)務(wù)是由于服務(wù)器宕機(jī)、網(wǎng)絡(luò)等問(wèn)題,造成服務(wù)不可用,此類(lèi)情況均需要運(yùn)維人員及時(shí)去修復(fù),而如今,可能在你收到告警信息的時(shí)候,k8s已經(jīng)幫你恢復(fù)了。
在沒(méi)有使用k8s時(shí),業(yè)務(wù)應(yīng)用的擴(kuò)容和縮容,都需要人工去處理,從采購(gòu)服務(wù)器、上架、到部署依賴(lài)環(huán)境,不僅需要大量的人力物力,而且非常容易在中間過(guò)程出現(xiàn)問(wèn)題,又要花費(fèi)大量的時(shí)間去查找問(wèn)題。成功上架后,還需要在前端反代端添加或該服務(wù)器,而如今,可以利用k8s的彈性計(jì)算,一鍵式進(jìn)行擴(kuò)容和縮容,不僅大大提高了運(yùn)維效率,而且還節(jié)省了不少的服務(wù)器資源,提高了資源利用率。
對(duì)于反代配置方面,比如可能你并不會(huì),或者對(duì)nginx的配置規(guī)則并不熟悉,一些高級(jí)的功能你也不會(huì)實(shí)現(xiàn),而如今,利用k8s的ingress即可簡(jiǎn)單的實(shí)現(xiàn)那些復(fù)雜的邏輯。并且也不會(huì)在遇到nginx少加一個(gè)斜杠和多加一個(gè)斜杠的問(wèn)題。
對(duì)于負(fù)載均衡方面,之前負(fù)載均衡可能是Nginx、LVS、HAProxy、F5等,云上可能是云服務(wù)商提供的不在均衡機(jī)制。每次添加刪除節(jié)點(diǎn)時(shí),都需要手動(dòng)去配置前端負(fù)載均衡,手動(dòng)去匹配后端節(jié)點(diǎn),而如今,使用k8s內(nèi)部的service可以動(dòng)態(tài)發(fā)現(xiàn)實(shí)現(xiàn)自動(dòng)管理節(jié)點(diǎn),并且支持自動(dòng)擴(kuò)容縮容。之前遇到高峰流量時(shí),經(jīng)常服務(wù)器性能不夠,需要臨時(shí)加服務(wù)器面對(duì)高峰流量,而如今對(duì)于高性能k8s集群加上serverless,基本實(shí)現(xiàn)無(wú)需管理,自動(dòng)擴(kuò)容。
對(duì)于高可用方面,k8s天生的高可用功能,徹底釋放了雙手,無(wú)需再去創(chuàng)建各類(lèi)高可用工具、檢測(cè)檢查腳本。k8s支持進(jìn)程接口級(jí)別的健康檢查,如發(fā)現(xiàn)接口超時(shí)或者返回值不正確,會(huì)自動(dòng)處理該問(wèn)題。
對(duì)于中間件搭建方面,根據(jù)定義好的資源文件,可以實(shí)現(xiàn)秒級(jí)搭建各類(lèi)中間件高可用集群,并且支持一鍵式擴(kuò)縮容,如Redis、RabbitMQ、Zookeeper等,并且大大減少了出錯(cuò)的概率。
對(duì)于應(yīng)用端口方面,傳統(tǒng)行業(yè)中,一個(gè)服務(wù)器可能跑了很多進(jìn)程,每個(gè)進(jìn)程都有一個(gè)端口,需要人為的去配置端口,并且還需要考慮端口沖突的問(wèn)題,如果有防火墻的話,還需要配置防火墻,在k8s中,端口統(tǒng)一管理,統(tǒng)一配置,每個(gè)應(yīng)用的端口都可設(shè)置成一樣的,之后通過(guò)service進(jìn)行負(fù)載均衡,大大降低了端口管理的復(fù)雜度和端口沖突。
無(wú)論是對(duì)于開(kāi)發(fā)人員、測(cè)試人員還是運(yùn)維人員,k8s的誕生,不僅減少了工作的復(fù)雜性,還減少了各種成本。上述帶來(lái)的變革只是其中比較小的一部分,更多優(yōu)點(diǎn)只有用了才能體會(huì)到。
二、 kubernetes帶來(lái)的挑戰(zhàn)
首先是對(duì)于k8s的學(xué)習(xí)本身就是很難的,概念太多,無(wú)從入手,可能學(xué)習(xí)了一個(gè)月也無(wú)法入門(mén),甚至連集群也搭建不出來(lái),使人望而卻步。并且k8s對(duì)運(yùn)維的技術(shù)能力要求比較高,已經(jīng)不僅僅局限于傳統(tǒng)運(yùn)維,有時(shí)候你可能要修改業(yè)務(wù)代碼等。并且需要掌握的知識(shí)也需要很多,你可能需要掌握公司所有使用到的代碼,比如代碼是如何進(jìn)行編譯的、如何正確發(fā)布、如何修改代碼配置文件等,這對(duì)于運(yùn)維人員,也是一種挑戰(zhàn)。Kubernetes之所以被叫做k8s,業(yè)界有兩種說(shuō)法,通俗的說(shuō)法是k和s之間有8個(gè)字母,另一種比較說(shuō)法是k8s集群至少需要搭建8遍才能搭建成功。當(dāng)然,在實(shí)際使用時(shí),可能不止8遍。k8s的誕生,把運(yùn)維從傳統(tǒng)轉(zhuǎn)變到了DevOps方向,需要面臨的問(wèn)題會(huì)更多,需要面臨的新技術(shù)也有很多,但是當(dāng)你掌握到了k8s的核心使用,就會(huì)受益終身。
三、Pod初體驗(yàn)
1.pod簡(jiǎn)單介紹
K8s有很多技術(shù)概念,同時(shí)對(duì)應(yīng)很多API對(duì)象,最重要的也是最基礎(chǔ)的是微服務(wù)Pod。Pod是在K8s集群中運(yùn)行部署應(yīng)用或服務(wù)的最小單元,它是可以支持多容器的。Pod的設(shè)計(jì)理念是支持多個(gè)容器在一個(gè)Pod中共享網(wǎng)絡(luò)地址和文件系統(tǒng),可以通過(guò)進(jìn)程間通信和文件共享這種簡(jiǎn)單高效的方式組合完成服務(wù)。Pod對(duì)多容器的支持是K8s最基礎(chǔ)的設(shè)計(jì)理念。比如你運(yùn)行一個(gè)操作系統(tǒng)發(fā)行版的軟件倉(cāng)庫(kù),一個(gè)Nginx容器用來(lái)發(fā)布軟件,另一個(gè)容器專(zhuān)門(mén)用來(lái)從源倉(cāng)庫(kù)做同步,這兩個(gè)容器的鏡像不太可能是一個(gè)團(tuán)隊(duì)開(kāi)發(fā)的,但是他們一塊兒工作才能提供一個(gè)微服務(wù);這種情況下,不同的團(tuán)隊(duì)各自開(kāi)發(fā)構(gòu)建自己的容器鏡像,在部署的時(shí)候組合成一個(gè)微服務(wù)對(duì)外提供服務(wù)。這就是K8S中的POD。
Pod是K8s集群中所有業(yè)務(wù)類(lèi)型的基礎(chǔ),可以看作運(yùn)行在K8s集群中的小機(jī)器人,不同類(lèi)型的業(yè)務(wù)就需要不同類(lèi)型的小機(jī)器人去執(zhí)行。目前K8s中的業(yè)務(wù)主要可以分為長(zhǎng)期伺服型(long-running)、批處理型(batch)、節(jié)點(diǎn)后臺(tái)支撐型(node-daemon)和有狀態(tài)應(yīng)用型(stateful application);分別對(duì)應(yīng)的小機(jī)器人控制器為Deployment、Job、DaemonSet和StatefulSet。
總結(jié)來(lái)說(shuō),Pod 是 k8s 系統(tǒng)中可以創(chuàng)建和管理的最小單元,是資源對(duì)象模型中由用戶創(chuàng)建或部署的最小資源對(duì)象模型,也是在 k8s 上運(yùn)行容器化應(yīng)用的資源對(duì)象,其他的資源對(duì)象都是用來(lái)支撐或者擴(kuò)展 Pod 對(duì)象功能的,比如控制器對(duì)象是用來(lái)管控 Pod 對(duì)象的,Service 或者Ingress 資源對(duì)象是用來(lái)暴露 Pod 引用對(duì)象的,PersistentVolume資源對(duì)象是用來(lái)為 Pod 提供存儲(chǔ)等等,k8s 不會(huì)直接處理容器,而是 Pod,Pod 是由一個(gè)或多個(gè) container 組成。
Pod 是 Kubernetes 的最重要概念,每一個(gè) Pod 都有一個(gè)特殊的被稱(chēng)為”根容器“的 Pause 容器。Pause 容器對(duì)應(yīng)的鏡 像屬于 Kubernetes 平臺(tái)的一部分,除了 Pause 容器,每個(gè) Pod 還包含一個(gè)或多個(gè)緊密相關(guān)的用戶業(yè)務(wù)容器
2.Pod實(shí)現(xiàn)機(jī)制
#1.共享網(wǎng)絡(luò)(通過(guò)Pause容器。把其他業(yè)務(wù)容器加入到Pause容器里面,讓所有業(yè)務(wù)容器在同—個(gè)名稱(chēng)空間中,可以實(shí)現(xiàn)網(wǎng)絡(luò)共享)
Pod中可以同時(shí)運(yùn)行多個(gè)進(jìn)程(作為容器運(yùn)行)協(xié)同工作。同一個(gè)Pod中的容器會(huì)自動(dòng)的分配到同一個(gè) node 上。同一個(gè)Pod中的容器共享資源、網(wǎng)絡(luò)環(huán)境和依賴(lài),所以它們總是被同時(shí)調(diào)度。在一個(gè)Pod中同時(shí)運(yùn)行多個(gè)容器是一種比較高級(jí)的用法。只有當(dāng)你的容器需要緊密配合協(xié)作的時(shí)候才考慮用這種模式。
#2.共享存儲(chǔ)(引入數(shù)據(jù)卷概念Volumn,使用數(shù)據(jù)卷進(jìn)行持久化存儲(chǔ))
Pod在設(shè)計(jì)?持就不是作為持久化實(shí)體的。在調(diào)度失敗、節(jié)點(diǎn)故障、缺少資源或者節(jié)點(diǎn)維護(hù)的狀態(tài)下都會(huì)死掉會(huì)被驅(qū)逐。通常,我們是需要借助類(lèi)似于Docker存儲(chǔ)卷這樣的資源來(lái)做Pod的數(shù)據(jù)久化的。
3.Pod vs 應(yīng)用
每個(gè) Pod 都是應(yīng)用的一個(gè)實(shí)例,有專(zhuān)用的 IP
4.Pod vs 容器
一個(gè) Pod 可以有多個(gè)容器,彼此間共享網(wǎng)絡(luò)和存儲(chǔ)資源,每個(gè) Pod 中有一個(gè) Pause 容器保存所有的容器狀態(tài), 通過(guò)管理 pause 容器,達(dá)到管理 pod 中所有容器的效果
5.Pod vs 節(jié)點(diǎn)
同一個(gè) Pod 中的容器總會(huì)被調(diào)度到相同 Node 節(jié)點(diǎn),不同節(jié)點(diǎn)間 Pod 的通信基于虛擬二層網(wǎng)絡(luò)技術(shù)實(shí)現(xiàn)
6.Pod vs Pod
普通的 Pod 和靜態(tài) Pod
四、Pod存在的意義及好處
1.意義
#1.創(chuàng)建容器使用doeker,一個(gè)docker對(duì)應(yīng)一個(gè)容器,一個(gè)容器有進(jìn)程。一個(gè)容器運(yùn)行一個(gè)應(yīng)用程序
#2.Pod是多進(jìn)程設(shè)計(jì),運(yùn)行多個(gè)應(yīng)用程序
一個(gè)Pod有多個(gè)容器,一個(gè)容器里面運(yùn)行一個(gè)應(yīng)用程序
#3.Pod存在為了親密性應(yīng)用
兩個(gè)應(yīng)用之間進(jìn)行交互
網(wǎng)絡(luò)之間調(diào)用
兩個(gè)應(yīng)用需要頻繁調(diào)用
2.好處
#1.Pod做為一個(gè)可以獨(dú)立運(yùn)行的服務(wù)單元,簡(jiǎn)化了應(yīng)用部署的難度,以更高的抽象層次為應(yīng)用部署管提供了極大的方便。
#2.Pod做為最小的應(yīng)用實(shí)例可以獨(dú)立運(yùn)行,因此可以方便的進(jìn)行部署、水平擴(kuò)展和收縮、方便進(jìn)行調(diào)度管理與資源的分配。
#3.Pod中的容器共享相同的數(shù)據(jù)和網(wǎng)絡(luò)地址空間,Pod之間也進(jìn)行了統(tǒng)一的資源管理與分配。
五、Pod特性
1.資源共享
一個(gè) Pod 里的多個(gè)容器可以共享存儲(chǔ)和網(wǎng)絡(luò),可以看作一個(gè)邏輯的主機(jī)。共享的如namespace,cgroups 或者其他的隔離資源。
多個(gè)容器共享同一network namespace,由此在一個(gè) Pod 里的多個(gè)容器共享 Pod 的 IP 和端口 namespace,所以一個(gè) Pod 內(nèi)的多個(gè)容器之間可以通過(guò) localhost 來(lái)進(jìn)行通信,所需要注意的是不同容器要注意不要有端口沖突即可。不同的 Pod 有不同的 IP,不同 Pod 內(nèi)的多個(gè)容器之前通信,不可以使用 IPC(如果沒(méi)有特殊指定的話)通信,通常情況下使用 Pod 的 IP 進(jìn)行通信。
一個(gè) Pod 里的多個(gè)容器可以共享存儲(chǔ)卷,這個(gè)存儲(chǔ)卷會(huì)被定義為 Pod 的一部分,并且可以掛載到該 Pod 里的所有容器的文件系統(tǒng)上。
2.生命周期短暫
Pod 屬于生命周期比較短暫的組件,比如,當(dāng) Pod 所在節(jié)點(diǎn)發(fā)生故障,那么該節(jié)點(diǎn)上的 Pod 會(huì)被調(diào)度到其他節(jié)點(diǎn),但需要注意的是,被重新調(diào)度的 Pod 是一個(gè)全新的 Pod,跟之前的Pod 沒(méi)有半毛錢(qián)關(guān)系。
3.平坦的網(wǎng)絡(luò)
K8s 集群中的所有 Pod 都在同一個(gè)共享網(wǎng)絡(luò)地址空間中,也就是說(shuō)每個(gè) Pod 都可以通過(guò)其他 Pod 的 IP 地址來(lái)實(shí)現(xiàn)訪問(wèn)。
六、Pod的資源清單詳解
apiVersion: v1 # 必選,API的版本號(hào)
kind: Pod # 必選,類(lèi)型Pod
metadata: # 必選,元數(shù)據(jù)
name: nginx # 必選,符合RFC 1035規(guī)范的Pod名稱(chēng)
namespace: web-testing # 可選,不指定默認(rèn)為default,Pod所在的命名空間
labels: # 可選,標(biāo)簽選擇器,一般用于Selector
- app: nginx
annotations: # 可選,注釋列表
- app: nginx
spec: # 必選,用于定義容器的詳細(xì)信息
containers: # 必選,容器列表
- name: nginx # 必選,符合RFC 1035規(guī)范的容器名稱(chēng)
image: nginx:v1 # 必選,容器所用的鏡像的地址
imagePullPolicy: Always # 可選,鏡像拉取策略
workingDir: /usr/share/nginx/html # 可選,容器的工作目錄
volumeMounts: # 可選,存儲(chǔ)卷配置
- name: webroot # 存儲(chǔ)卷名稱(chēng)
mountPath: /usr/share/nginx/html # 掛載目錄
readOnly: true # 只讀
ports: # 可選,容器需要暴露的端口號(hào)列表
- name: http # 端口名稱(chēng)
containerPort: 80 # 端口號(hào)
protocol: TCP # 端口協(xié)議,默認(rèn)TCP
env: # 可選,環(huán)境變量配置
- name: TZ # 變量名
value: Asia/Shanghai
- name: LANG
value: en_US.utf8
resources: # 可選,資源限制和資源請(qǐng)求限制
limits: # 最大限制設(shè)置
cpu: 1000m
memory: 1024MiB
requests: # 啟動(dòng)所需的資源
cpu: 100m
memory: 512MiB
readinessProbe: # 可選,容器狀態(tài)檢查
httpGet: # 檢測(cè)方式
path: / # 檢查路徑
port: 80 # 監(jiān)控端口
timeoutSeconds: 2 # 超時(shí)時(shí)間
initialDelaySeconds: 60 # 初始化時(shí)間
livenessProbe: # 可選,監(jiān)控狀態(tài)檢查
exec: # 檢測(cè)方式
command:
- cat
- /health
httpGet: # 檢測(cè)方式
path: /_health
port: 8080
httpHeaders:
- name: end-user
value: jason
tcpSocket: # 檢測(cè)方式
port: 80
initialDelaySeconds: 60 # 初始化時(shí)間
timeoutSeconds: 2 # 超時(shí)時(shí)間
periodSeconds: 5 # 檢測(cè)間隔
successThreshold: 2 # 檢查成功為2次表示就緒
failureThreshold: 1 # 檢測(cè)失敗1次表示未就緒
securityContext: # 可選,限制容器不可信的行為
provoleged: false
restartPolicy: Always # 可選,默認(rèn)為Always
nodeSelector: # 可選,指定Node節(jié)點(diǎn)
region: subnet7
imagePullSecrets: # 可選,拉取鏡像使用的secret
- name: default-dockercfg-86258
hostNetwork: false # 可選,是否為主機(jī)模式,如是,會(huì)占用主機(jī)端口
volumes: # 共享存儲(chǔ)卷列表
- name: webroot # 名稱(chēng),與上述對(duì)應(yīng)
emptyDir: {} # 共享卷類(lèi)型,空
hostPath: # 共享卷類(lèi)型,本機(jī)目錄
path: /etc/hosts
secret: # 共享卷類(lèi)型,secret模式,一般用于密碼
secretName: default-token-tf2jp # 名稱(chēng)
defaultMode: 420 # 權(quán)限
configMap: # 一般用于配置文件
name: nginx-conf
defaultMode: 420
七、Pod 的基本使用
在 kubernetes 中對(duì)運(yùn)行容器的要求為:容器的主程序需要一直在前臺(tái)運(yùn)行,而不是后臺(tái)運(yùn)行。應(yīng)用需要改造成前臺(tái)運(yùn)行的方式。如果我們創(chuàng)建的 Docker 鏡像的啟動(dòng)命令是后臺(tái)執(zhí)行程序,則在 kubelet 創(chuàng)建包含這個(gè)容器的 pod 之后運(yùn)行完該命令,即認(rèn)為 Pod 已經(jīng)結(jié)束, 將立刻銷(xiāo)毀該P(yáng)od。如果為該 Pod 定義了 RC,則創(chuàng)建、銷(xiāo)毀會(huì)陷入一個(gè)無(wú)限循環(huán)的過(guò)程中。
Pod 可以由 1 個(gè)或多個(gè)容器組合而成。
1.一個(gè)容器組成的 Pod 的 yaml 示例
[root@k8s-master-001 ~]# vi first-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: first-pod
labels:
app: bash
spec:
containers:
- name: bash-container
image: busybox
command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 10']
2.多個(gè)容器組成的 Pod 的 yaml 示例
[root@k8s-master-001 ~]# vi second-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myweb
labels:
name: tomcat-redis
spec:
containers:
- name: tomcat
image: tomcat
ports:
- containerPort: 8080
- name: redis
image: redis
ports:
- containerPort: 6379
3.創(chuàng)建
[root@k8s-master-001 ~]# kubectl apply -f first-pod.yaml
pod/first-pod created
[root@k8s-master-001 ~]# kubectl apply -f second-pod.yaml
pod/myweb created
4.查看
[root@k8s-master-001 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
first-pod 0/1 Completed 3 5m2s
myweb 2/2 Running 0 4m49s
[root@k8s-master-001 ~]# kubectl logs first-pod
Hello Kubernetes
[root@k8s-master-001 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
first-pod 0/1 CrashLoopBackOff 6 14m 10.241.184.2 k8s-node-002 <none> <none>
myweb 2/2 Running 0 13m 10.241.184.3 k8s-node-002 <none> <none>
[root@k8s-master-001 ~]# kubectl describe pod first-pod
Name: first-pod
Namespace: default
Priority: 0
Node: k8s-node-002/172.16.1.114
Start Time: Tue, 28 Sep 2021 14:54:47 +0800
Labels: app=bash
Annotations: Status: Running
IP: 10.241.184.2
IPs:
IP: 10.241.184.2
Containers:
bash-container:
Container ID: docker://6560a18d58bc165464ee7155ab3001a4337a5108098f47fa7f9dfee6b9deed07
Image: busybox
Image ID: docker-pullable://busybox@sha256:f7ca5a32c10d51aeda3b4d01c61c6061f497893d7f6628b92f822f7117182a57
Port: <none>
Host Port: <none>
Command:
sh
-c
echo Hello Kubernetes! && sleep 10
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Tue, 28 Sep 2021 15:05:52 +0800
Finished: Tue, 28 Sep 2021 15:06:02 +0800
Ready: False
Restart Count: 6
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-cvczf (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
default-token-cvczf:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-cvczf
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 360s
node.kubernetes.io/unreachable:NoExecute for 360s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned default/first-pod to k8s-node-002
Normal Started 10m (x4 over 14m) kubelet, k8s-node-002 Started container bash-container
Normal Pulling 9m30s (x5 over 14m) kubelet, k8s-node-002 Pulling image "busybox"
Normal Pulled 9m14s (x5 over 14m) kubelet, k8s-node-002 Successfully pulled image "busybox"
Normal Created 9m14s (x5 over 14m) kubelet, k8s-node-002 Created container bash-container
Warning BackOff 4m48s (x26 over 11m) kubelet, k8s-node-002 Back-off restarting failed container
[root@k8s-master-001 ~]# kubectl describe pod myweb
Name: myweb
Namespace: default
Priority: 0
Node: k8s-node-002/172.16.1.114
Start Time: Tue, 28 Sep 2021 14:55:01 +0800
Labels: name=tomcat-redis
Annotations: Status: Running
IP: 10.241.184.3
IPs:
IP: 10.241.184.3
Containers:
tomcat:
Container ID: docker://5659eaf2061c015c57274881b0a95a76edcc88b3d6b2b5c99e15f5da2bc6510b
Image: tomcat
Image ID: docker-pullable://tomcat@sha256:54876d82d30746c5b625a784938864d5b726219e0aace09b3e57ef4dfa85d594
Port: 8080/TCP
Host Port: 0/TCP
State: Running
Started: Tue, 28 Sep 2021 14:57:45 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-cvczf (ro)
redis:
Container ID: docker://6e8a571baf372571de70d9e672c3ef8a8e9cfeeab9845d661abd2a80b084585b
Image: redis
Image ID: docker-pullable://redis@sha256:e595e79c05c7690f50ef0136acc9d932d65d8b2ce7915d26a68ca3fb41a7db61
Port: 6379/TCP
Host Port: 0/TCP
State: Running
Started: Tue, 28 Sep 2021 14:58:18 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-cvczf (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-cvczf:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-cvczf
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 360s
node.kubernetes.io/unreachable:NoExecute for 360s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned default/myweb to k8s-node-002
Normal Pulling 15m kubelet, k8s-node-002 Pulling image "tomcat"
Normal Pulled 12m kubelet, k8s-node-002 Successfully pulled image "tomcat"
Normal Created 12m kubelet, k8s-node-002 Created container tomcat
Normal Started 12m kubelet, k8s-node-002 Started container tomcat
Normal Pulling 12m kubelet, k8s-node-002 Pulling image "redis"
Normal Pulled 11m kubelet, k8s-node-002 Successfully pulled image "redis"
Normal Created 11m kubelet, k8s-node-002 Created container redis
Normal Started 11m kubelet, k8s-node-002 Started container redis
5.刪除
[root@k8s-master-001 ~]# kubectl delete -f first-pod.yaml
pod "first-pod" deleted
[root@k8s-master-001 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myweb 2/2 Running 0 24m
nginx-f89759699-knhc6 1/1 Running 0 26m
[root@k8s-master-001 ~]# kubectl delete pod --all
pod "myweb" deleted
[root@k8s-master-001 ~]# kubectl get pod
No resources found in default namespace.
八、Pod 的分類(lèi)
1.普通 Pod
普通 Pod 一旦被創(chuàng)建,就會(huì)被放入到 etcd 中存儲(chǔ),隨后會(huì)被 Kubernetes Master 調(diào)度到某個(gè)具體的 Node 上并進(jìn)行綁定,隨后該 Pod 對(duì)應(yīng)的 Node 上的 kubelet 進(jìn)程實(shí)例化成一組相關(guān)的 Docker 容器并啟動(dòng)起來(lái)。在默認(rèn)情 況下,當(dāng) Pod 里某個(gè)容器停止時(shí),Kubernetes 會(huì)自動(dòng)檢測(cè)到這個(gè)問(wèn)題并且重新啟動(dòng)這個(gè) Pod 里某所有容器, 如果 Pod 所在的 Node 宕機(jī), 則會(huì)將這個(gè) Node 上的所有 Pod 重新調(diào)度到其它節(jié)點(diǎn)上。
2.靜態(tài) Pod
靜態(tài) Pod 是由 kubelet 進(jìn)行管理的僅存在于特定 Node 上的 Pod,它們不能通過(guò) API Server 進(jìn)行管理,無(wú)法與 ReplicationController、Deployment 或 DaemonSet 進(jìn)行關(guān)聯(lián),并且kubelet 也無(wú)法對(duì)它們進(jìn)行健康檢查。
九、Pod的生命周期和重啟策略
Pod 在整個(gè)生命周期過(guò)程中被系統(tǒng)定義為各種狀態(tài),熟悉 Pod 各種狀態(tài)對(duì)于理解如何設(shè)置 Pod的調(diào)度策略、重啟策略是很有必要的。
1.Pod的狀態(tài)
狀態(tài)值 |
描述 |
掛起(Pending) |
API Server創(chuàng)建了pod資源對(duì)象已存入etcd中,但它尚未被調(diào)度完成,或者仍處于從倉(cāng)庫(kù)下載鏡像的過(guò)程中。 |
運(yùn)行中(Running) |
Pod已經(jīng)被調(diào)度至某節(jié)點(diǎn),并且所有容器都已經(jīng)被kubelet創(chuàng)建完成 |
成功(Successed/Completed) |
Pod中的所有容器都已經(jīng)成功終止并且不會(huì)被重啟 |
失?。‵ailed) |
Pod中的所有容器都已終止了,并且至少有一個(gè)容器是因?yàn)槭〗K止。即容器以非0狀態(tài)退出或者被系統(tǒng)禁止。 |
未知(Unknown) |
Api Server無(wú)法正常獲取到Pod對(duì)象的狀態(tài)信息,通常是由于無(wú)法與所在工作節(jié)點(diǎn)的kubelet通信所致。 |
2.Pod的重啟策略
Pod 重啟策略( RestartPolicy )應(yīng)用于 Pod 內(nèi)的所有容器,井且僅在 Pod 所處的 Node 上由kubelet 進(jìn)行判斷和重啟操作。當(dāng)某個(gè)容器異常退出或者健康檢查失敗時(shí), kubelet將根據(jù) RestartPolicy 設(shè)置來(lái)進(jìn)行相應(yīng)的操作。Pod的重啟策略包括:Always、OnFailure和Never,默認(rèn)值為Always
狀態(tài)值 |
說(shuō)明 |
Always |
當(dāng)容器失效時(shí),由kubelet自動(dòng)重啟該容器。 |
OnFailure |
當(dāng)容器終止運(yùn)行且退出碼不為0時(shí),由kubelet自動(dòng)重啟該容器。 |
Never |
不論容器運(yùn)行狀態(tài)如何,kubelet都不會(huì)重啟該容器。 |
kubelet 重啟失效容器的時(shí)間間隔以 sync-frequency 乘以 2n 來(lái)計(jì)算;例如1、2、4、8倍等,最長(zhǎng)延時(shí) 5min ,并且在成功重啟后的 10 min 后重置該時(shí)間。
Pod的重啟策略與控制方式息息相關(guān),當(dāng)前可用于管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接通過(guò)kubelet管理(靜態(tài)Pod)。每種控制器對(duì)Pod的重啟策略要求如下:
1.RC和DaemonSet:必須設(shè)置為Always,需要保證該容器持續(xù)運(yùn)行。
2.Job和CronJob:OnFailure或Never,確保容器執(zhí)行完成后不再重啟。
3.kubelet:在Pod失效時(shí)自動(dòng)重啟它,不論將RestartPolicy設(shè)置為什么值,也不會(huì)對(duì)Pod進(jìn)行健康檢查。
3.常見(jiàn)狀態(tài)轉(zhuǎn)換
Pod包含的容器數(shù) |
Pod當(dāng)前的狀態(tài) |
發(fā)生事件 |
Pod的結(jié)果狀態(tài) |
|
|
|
|
|
RestartPolicy=Always |
RestartPolicy=OnFailure |
RestartPolicy=Never |
包含一個(gè)容器 |
Running |
容器成功退出 |
Running |
Succeeded |
Succeeded |
包含一個(gè)容器 |
Running |
容器失敗退出 |
Running |
Running |
Failure |
包含兩個(gè)容器 |
Running |
1個(gè)容器失敗退出 |
Running |
Running |
Running |
包含兩個(gè)容器 |
Running |
容器被OOM殺掉 |
Running |
Running |
Failure |
十、Pod 資源配置
每個(gè) Pod 都可以對(duì)其能使用的服務(wù)器上的計(jì)算資源設(shè)置限額,Kubernetes 中可以設(shè)置限額的計(jì)算資源有 CPU 與 Memory 兩種,其中 CPU 的資源單位為 CPU 數(shù)量,是一個(gè)絕對(duì)值而非相對(duì)值。Memory 配額也是一個(gè)絕對(duì)值,它的單 位是內(nèi)存字節(jié)數(shù)。
Kubernetes 里,一個(gè)計(jì)算資源進(jìn)行配額限定需要設(shè)定以下兩個(gè)參數(shù): Requests 該資源最小申請(qǐng)數(shù)量,系統(tǒng)必須滿足要求 Limits 該資源最大允許使用的量,不能突破,當(dāng)容器試圖使用超過(guò)這個(gè)量的資源時(shí),可能會(huì)被 Kubernetes Kill 并重啟。
1.舉例
apiVersion: v1 # 必選,API的版本號(hào)
kind: Pod # 必選,類(lèi)型Pod
metadata: # 必選,元數(shù)據(jù)
name: nginx # 必選,符合RFC 1035規(guī)范的Pod名稱(chēng)
namespace: web-testing # 可選,不指定默認(rèn)為default,Pod所在的命名空間
labels: # 可選,標(biāo)簽選擇器,一般用于Selector
- app: nginx
annotations: # 可選,注釋列表
- app: nginx
spec: # 必選,用于定義容器的詳細(xì)信息
containers: # 必選,容器列表
- name: nginx # 必選,符合RFC 1035規(guī)范的容器名稱(chēng)
image: nginx:v1 # 必選,容器所用的鏡像的地址
imagePullPolicy: Always # 可選,鏡像拉取策略
workingDir: /usr/share/nginx/html # 可選,容器的工作目錄
volumeMounts: # 可選,存儲(chǔ)卷配置
- name: webroot # 存儲(chǔ)卷名稱(chēng)
mountPath: /usr/share/nginx/html # 掛載目錄
readOnly: true # 只讀
ports: # 可選,容器需要暴露的端口號(hào)列表
- name: http # 端口名稱(chēng)
containerPort: 80 # 端口號(hào)
protocol: TCP # 端口協(xié)議,默認(rèn)TCP
env: # 可選,環(huán)境變量配置
- name: TZ # 變量名
value: Asia/Shanghai
- name: LANG
value: en_US.utf8
resources: # 可選,資源限制和資源請(qǐng)求限制
limits: # 最大限制設(shè)置
cpu: 1000m
memory: 1024MiB
requests: # 啟動(dòng)所需的資源
cpu: 100m
memory: 512MiB
上述代碼表明 nginx 容器申請(qǐng)最少 0.1 個(gè) CPU 以及 512MiB 內(nèi)存,在運(yùn)行過(guò)程中容器所能使用的資源配額為 1 個(gè) CPU 以及 1G 內(nèi)存。