一、需求來源
首先來看一下井辜,整個(gè)需求的來源:當(dāng)把應(yīng)用遷移到 Kubernetes 之后绎谦,要如何去保障應(yīng)用的健康與穩(wěn)定呢?其實(shí)很簡(jiǎn)單粥脚,可以從兩個(gè)方面來進(jìn)行增強(qiáng):
- 首先是提高應(yīng)用的可觀測(cè)性窃肠;
- 第二是提高應(yīng)用的可恢復(fù)能力。
從可觀測(cè)性上來講刷允,可以在三個(gè)方面來去做增強(qiáng):
- 首先是應(yīng)用的健康狀態(tài)上面冤留,可以實(shí)時(shí)地進(jìn)行觀測(cè)碧囊;
- 第二個(gè)是可以獲取應(yīng)用的資源使用情況;
- 第三個(gè)是可以拿到應(yīng)用的實(shí)時(shí)日志纤怒,進(jìn)行問題的診斷與分析糯而。
當(dāng)出現(xiàn)了問題之后,首先要做的事情是要降低影響的范圍肪跋,進(jìn)行問題的調(diào)試與診斷歧蒋。最后當(dāng)出現(xiàn)問題的時(shí)候,理想的狀況是:可以通過和 K8s 集成的自愈機(jī)制進(jìn)行完整的恢復(fù)州既。
二谜洽、Liveness 與 Readiness
本小節(jié)為大家介紹 Liveness probe 和 eadiness probe。
應(yīng)用健康狀態(tài)-初識(shí) Liveness 與 Readiness
Readiness probe 也叫就緒指針吴叶,用來判斷一個(gè) pod 是否處在就緒狀態(tài)阐虚。當(dāng)一個(gè) pod 處在就緒狀態(tài)的時(shí)候,它才能夠?qū)ν馓峁┫鄳?yīng)的服務(wù)蚌卤,也就是說接入層的流量才能打到相應(yīng)的 pod实束。當(dāng)這個(gè) pod 不處在就緒狀態(tài)的時(shí)候,接入層會(huì)把相應(yīng)的流量從這個(gè) pod 上面進(jìn)行摘除逊彭。
來看一下簡(jiǎn)單的一個(gè)例子:
如下圖其實(shí)就是一個(gè) Readiness 就緒的一個(gè)例子:
當(dāng)這個(gè) pod 指針判斷一直處在失敗狀態(tài)的時(shí)候咸灿,其實(shí)接入層的流量不會(huì)打到現(xiàn)在這個(gè) pod 上。
當(dāng)這個(gè) pod 的狀態(tài)從 FAIL 的狀態(tài)轉(zhuǎn)換成 success 的狀態(tài)時(shí)侮叮,它才能夠真實(shí)地承載這個(gè)流量避矢。
Liveness 指針也是類似的,它是存活指針囊榜,用來判斷一個(gè) pod 是否處在存活狀態(tài)审胸。當(dāng)一個(gè) pod 處在不存活狀態(tài)的時(shí)候,會(huì)出現(xiàn)什么事情呢卸勺?
這個(gè)時(shí)候會(huì)由上層的判斷機(jī)制來判斷這個(gè) pod 是否需要被重新拉起砂沛。那如果上層配置的重啟策略是 restart always 的話,那么此時(shí)這個(gè) pod 會(huì)直接被重新拉起曙求。
應(yīng)用健康狀態(tài)-使用方式
接下來看一下 Liveness 指針和 Readiness 指針的具體的用法碍庵。
探測(cè)方式
Liveness 指針和 Readiness 指針支持三種不同的探測(cè)方式:
- 第一種是 httpGet。它是通過發(fā)送 http Get 請(qǐng)求來進(jìn)行判斷的悟狱,當(dāng)返回碼是 200-399 之間的狀態(tài)碼時(shí)怎抛,標(biāo)識(shí)這個(gè)應(yīng)用是健康的;
- 第二種探測(cè)方式是 Exec芽淡。它是通過執(zhí)行容器中的一個(gè)命令來判斷當(dāng)前的服務(wù)是否是正常的马绝,當(dāng)命令行的返回結(jié)果是 0,則標(biāo)識(shí)容器是健康的挣菲;
- 第三種探測(cè)方式是 tcpSocket 富稻。它是通過探測(cè)容器的 IP 和 Port 進(jìn)行 TCP 健康檢查掷邦,如果這個(gè) TCP 的鏈接能夠正常被建立,那么標(biāo)識(shí)當(dāng)前這個(gè)容器是健康的椭赋。
探測(cè)結(jié)果
從探測(cè)結(jié)果來講主要分為三種:
- 第一種是 success抚岗,當(dāng)狀態(tài)是 success 的時(shí)候,表示 container 通過了健康檢查哪怔,也就是 Liveness probe 或 Readiness probe 是正常的一個(gè)狀態(tài)宣蔚;
- 第二種是 Failure,F(xiàn)ailure 表示的是這個(gè) container 沒有通過健康檢查认境,如果沒有通過健康檢查的話胚委,那么此時(shí)就會(huì)進(jìn)行相應(yīng)的一個(gè)處理,那在 Readiness 處理的一個(gè)方式就是通過 service叉信。service 層將沒有通過 Readiness 的 pod 進(jìn)行摘除亩冬,而 Liveness 就是將這個(gè) pod 進(jìn)行重新拉起,或者是刪除硼身。
- 第三種狀態(tài)是 Unknown硅急,Unknown 是表示說當(dāng)前的執(zhí)行的機(jī)制沒有進(jìn)行完整的一個(gè)執(zhí)行,可能是因?yàn)轭愃葡癯瑫r(shí)或者像一些腳本沒有及時(shí)返回佳遂,那么此時(shí) Readiness-probe 或 Liveness-probe 會(huì)不做任何的一個(gè)操作营袜,會(huì)等待下一次的機(jī)制來進(jìn)行檢驗(yàn)。
那在 kubelet 里面有一個(gè)叫 ProbeManager 的組件丑罪,這個(gè)組件里面會(huì)包含 Liveness-probe 或 Readiness-probe连茧,這兩個(gè) probe 會(huì)將相應(yīng)的 Liveness 診斷和 Readiness 診斷作用在 pod 之上,來實(shí)現(xiàn)一個(gè)具體的判斷巍糯。
應(yīng)用健康狀態(tài)-Pod Probe Spec
下面介紹這三種方式不同的檢測(cè)方式的一個(gè) yaml 文件的使用。
首先先看一下 exec客扎,exec 的使用其實(shí)非常簡(jiǎn)單祟峦。如下圖所示,大家可以看到這是一個(gè) Liveness probe徙鱼,它里面配置了一個(gè) exec 的一個(gè)診斷宅楞。接下來,它又配置了一個(gè) command 的字段袱吆,這個(gè) command 字段里面通過 cat 一個(gè)具體的文件來判斷當(dāng)前 Liveness probe 的狀態(tài)厌衙,當(dāng)這個(gè)文件里面返回的結(jié)果是 0 時(shí),或者說這個(gè)命令返回是 0 時(shí)绞绒,它會(huì)認(rèn)為此時(shí)這個(gè) pod 是處在健康的一個(gè)狀態(tài)婶希。
那再來看一下這個(gè) httpGet,httpGet 里面有一個(gè)字段是路徑蓬衡,第二個(gè)字段是 port喻杈,第三個(gè)是 headers彤枢。這個(gè)地方有時(shí)需要通過類似像 header 頭的一個(gè)機(jī)制做 health 的一個(gè)判斷時(shí),需要配置這個(gè) header筒饰,通常情況下缴啡,可能只需要通過 health 和 port 的方式就可以了。
第三種是 tcpSocket瓷们,tcpSocket 的使用方式其實(shí)也比較簡(jiǎn)單业栅,你只需要設(shè)置一個(gè)檢測(cè)的端口,像這個(gè)例子里面使用的是 8080 端口谬晕,當(dāng)這個(gè) 8080 端口 tcp connect 審核正常被建立的時(shí)候碘裕,那 tecSocket,Probe 會(huì)認(rèn)為是健康的一個(gè)狀態(tài)固蚤。
此外還有如下的五個(gè)參數(shù)娘汞,是 Global 的參數(shù)。
- 第一個(gè)參數(shù)叫 initialDelaySeconds夕玩,它表示的是說這個(gè) pod 啟動(dòng)延遲多久進(jìn)行一次檢查你弦,比如說現(xiàn)在有一個(gè) Java 的應(yīng)用,它啟動(dòng)的時(shí)間可能會(huì)比較長(zhǎng)燎孟,因?yàn)樯婕暗?jvm 的啟動(dòng)禽作,包括 Java 自身 jar 的加載。所以前期揩页,可能有一段時(shí)間是沒有辦法被檢測(cè)的旷偿,而這個(gè)時(shí)間又是可預(yù)期的,那這時(shí)可能要設(shè)置一下 initialDelaySeconds爆侣;
- 第二個(gè)是 periodSeconds萍程,它表示的是檢測(cè)的時(shí)間間隔,正常默認(rèn)的這個(gè)值是 10 秒兔仰;
- 第三個(gè)字段是 timeoutSeconds茫负,它表示的是檢測(cè)的超時(shí)時(shí)間,當(dāng)超時(shí)時(shí)間之內(nèi)沒有檢測(cè)成功乎赴,那它會(huì)認(rèn)為是失敗的一個(gè)狀態(tài)忍法;
- 第四個(gè)是 successThreshold,它表示的是:當(dāng)這個(gè) pod 從探測(cè)失敗到再一次判斷探測(cè)成功榕吼,所需要的閾值次數(shù)饿序,默認(rèn)情況下是 1 次,表示原本是失敗的羹蚣,那接下來探測(cè)這一次成功了原探,就會(huì)認(rèn)為這個(gè) pod 是處在一個(gè)探針狀態(tài)正常的一個(gè)狀態(tài);
- 最后一個(gè)參數(shù)是 failureThreshold,它表示的是探測(cè)失敗的重試次數(shù)踢匣,默認(rèn)值是 3告匠,表示的是當(dāng)從一個(gè)健康的狀態(tài)連續(xù)探測(cè) 3 次失敗,那此時(shí)會(huì)判斷當(dāng)前這個(gè)pod的狀態(tài)處在一個(gè)失敗的狀態(tài)离唬。
應(yīng)用健康狀態(tài)-Liveness 與 Readiness 總結(jié)
接下來對(duì) Liveness 指針和 Readiness 指針進(jìn)行一個(gè)簡(jiǎn)單的總結(jié)后专。
介紹
Liveness 指針是存活指針,它用來判斷容器是否存活输莺、判斷 pod 是否 running戚哎。如果 Liveness 指針判斷容器不健康,此時(shí)會(huì)通過 kubelet 殺掉相應(yīng)的 pod嫂用,并根據(jù)重啟策略來判斷是否重啟這個(gè)容器型凳。如果默認(rèn)不配置 Liveness 指針,則默認(rèn)情況下認(rèn)為它這個(gè)探測(cè)默認(rèn)返回是成功的嘱函。
Readiness 指針用來判斷這個(gè)容器是否啟動(dòng)完成甘畅,即 pod 的 condition 是否 ready。如果探測(cè)的一個(gè)結(jié)果是不成功往弓,那么此時(shí)它會(huì)從 pod 上 Endpoint 上移除疏唾,也就是說從接入層上面會(huì)把前一個(gè) pod 進(jìn)行摘除,直到下一次判斷成功函似,這個(gè) pod 才會(huì)再次掛到相應(yīng)的 endpoint 之上槐脏。
檢測(cè)失敗
對(duì)于檢測(cè)失敗上面來講 Liveness 指針是直接殺掉這個(gè) pod,而 Readiness 指針是切掉 endpoint 到這個(gè) pod 之間的關(guān)聯(lián)關(guān)系撇寞,也就是說它把這個(gè)流量從這個(gè) pod 上面進(jìn)行切掉顿天。
適用場(chǎng)景
Liveness 指針適用場(chǎng)景是支持那些可以重新拉起的應(yīng)用,而 Readiness 指針主要應(yīng)對(duì)的是啟動(dòng)之后無法立即對(duì)外提供服務(wù)的這些應(yīng)用蔑担。
注意事項(xiàng)
在使用 Liveness 指針和 Readiness 指針的時(shí)候有一些注意事項(xiàng)牌废。因?yàn)椴徽撌?Liveness 指針還是 Readiness 指針都需要配置合適的探測(cè)方式,以免被誤操作啤握。
- 第一個(gè)是調(diào)大超時(shí)的閾值鸟缕,因?yàn)樵谌萜骼锩鎴?zhí)行一個(gè) shell 腳本,它的執(zhí)行時(shí)長(zhǎng)是非常長(zhǎng)的恨统,平時(shí)在一臺(tái) ecs 或者在一臺(tái) vm 上執(zhí)行,可能 3 秒鐘返回的一個(gè)腳本在容器里面需要 30 秒鐘三妈。所以這個(gè)時(shí)間是需要在容器里面事先進(jìn)行一個(gè)判斷的畜埋,那如果可以調(diào)大超時(shí)閾值的方式,來防止由于容器壓力比較大的時(shí)候出現(xiàn)偶發(fā)的超時(shí)畴蒲;
- 第二個(gè)是調(diào)整判斷的一個(gè)次數(shù)悠鞍,3 次的默認(rèn)值其實(shí)在比較短周期的判斷周期之下,不一定是最佳實(shí)踐,適當(dāng)調(diào)整一下判斷的次數(shù)也是一個(gè)比較好的方式咖祭;
- 第三個(gè)是 exec掩宜,如果是使用 shell 腳本的這個(gè)判斷,調(diào)用時(shí)間會(huì)比較長(zhǎng)么翰,比較建議大家可以使用類似像一些編譯性的腳本 Golang 或者一些 C 語言牺汤、C++ 編譯出來的這個(gè)二進(jìn)制的 binary 進(jìn)行判斷,那這種通常會(huì)比 shell 腳本的執(zhí)行效率高 30% 到 50%浩嫌;
- 第四個(gè)是如果使用 tcpSocket 方式進(jìn)行判斷的時(shí)候檐迟,如果遇到了 TLS 的服務(wù),那可能會(huì)造成后邊 TLS 里面有很多這種未健全的 tcp connection码耐,那這個(gè)時(shí)候需要自己對(duì)業(yè)務(wù)場(chǎng)景上來判斷追迟,這種的鏈接是否會(huì)對(duì)業(yè)務(wù)造成影響。
三骚腥、問題診斷
接下來給大家講解一下在 K8s 中常見的問題診斷敦间。
應(yīng)用故障排查-了解狀態(tài)機(jī)制
首先要了解一下 K8s 中的一個(gè)設(shè)計(jì)理念,就是這個(gè)狀態(tài)機(jī)制束铭。因?yàn)?K8S 的設(shè)計(jì)是面向狀態(tài)機(jī)的廓块,它里面通過 yaml 的方式來定義的是一個(gè)期望到達(dá)的一個(gè)狀態(tài),而真正這個(gè) yaml 在執(zhí)行過程中會(huì)由各種各樣的 controller來負(fù)責(zé)整體的狀態(tài)之間的一個(gè)轉(zhuǎn)換纯露。
Phase | 描述 |
---|---|
Pending | Kubernetes 已經(jīng)創(chuàng)建并確認(rèn)該 Pod剿骨。此時(shí)可能有兩種情況:Pod 還未完成調(diào)度(例如沒有合適的節(jié)點(diǎn)),正在從 docker registry 下載鏡像 |
Running | 該 Pod 已經(jīng)被綁定到一個(gè)節(jié)點(diǎn)埠褪,并且該 Pod 所有的容器都已經(jīng)成功創(chuàng)建浓利。其中至少有一個(gè)容器正在運(yùn)行,或者正在啟動(dòng)/重啟 |
Succeeded | Pod 中的所有容器都已經(jīng)成功終止钞速,并且不會(huì)再被重啟 |
Failed | Pod 中的所有容器都已經(jīng)終止贷掖,至少一個(gè)容器終止于失敗狀態(tài):容器的進(jìn)程退出碼不是 0,或者被系統(tǒng) kill |
Unknown | 因?yàn)槟承┪粗蚩视铮荒艽_定 Pod 的狀態(tài)苹威,通常的原因是 master 與 Pod 所在節(jié)點(diǎn)之間的通信故障 |
比如說上面的圖,實(shí)際上是一個(gè) Pod 的一個(gè)生命周期驾凶。剛開始它處在一個(gè) pending 的狀態(tài)牙甫,那接下來可能會(huì)轉(zhuǎn)換到類似像 running,也可能轉(zhuǎn)換到 Unknown调违,甚至可以轉(zhuǎn)換到 failed窟哺。然后,當(dāng) running 執(zhí)行了一段時(shí)間之后技肩,它可以轉(zhuǎn)換到類似像 successded 或者是 failed且轨,然后當(dāng)出現(xiàn)在 unknown 這個(gè)狀態(tài)時(shí),可能由于一些狀態(tài)的恢復(fù),它會(huì)重新恢復(fù)到 running 或者 successded 或者是 failed 旋奢。
其實(shí) K8s 整體的一個(gè)狀態(tài)就是基于這種類似像狀態(tài)機(jī)的一個(gè)機(jī)制進(jìn)行轉(zhuǎn)換的泳挥,而不同狀態(tài)之間的轉(zhuǎn)化都會(huì)在相應(yīng)的 K8s對(duì)象上面留下來類似像 Status 或者像 Conditions 的一些字段來進(jìn)行表示。
像下面這張圖其實(shí)表示的就是說在一個(gè) Pod 上面一些狀態(tài)位的一些展現(xiàn)至朗。
比如說在 Pod 上面有一個(gè)字段叫 Status屉符,這個(gè) Status 表示的是 Pod 的一個(gè)聚合狀態(tài),在這個(gè)里面爽丹,這個(gè)聚合狀態(tài)處在一個(gè) pending 狀態(tài)筑煮。
然后再往下看,因?yàn)橐粋€(gè) pod 里面有多個(gè) container粤蝎,每個(gè) container 上面又會(huì)有一個(gè)字段叫 State真仲,然后 State 的狀態(tài)表示當(dāng)前這個(gè) container 的一個(gè)聚合狀態(tài)。那在這個(gè)例子里面初澎,這個(gè)聚合狀態(tài)處在的是 waiting 的狀態(tài)秸应,那具體的原因是因?yàn)槭裁茨兀渴且驗(yàn)樗溺R像沒有拉下來碑宴,所以處在 waiting 的狀態(tài)软啼,是在等待這個(gè)鏡像拉取。然后這個(gè) ready 的部分呢延柠,目前是 false祸挪,因?yàn)樗@個(gè)進(jìn)行目前沒有拉取下來,所以這個(gè) pod 不能夠正常對(duì)外服務(wù)贞间,所以此時(shí) ready 的狀態(tài)是未知的贿条,定義為 false。如果上層的 endpoint 發(fā)現(xiàn)底層這個(gè) ready 不是 true 的話增热,那么此時(shí)這個(gè)服務(wù)是沒有辦法對(duì)外服務(wù)的整以。
再往下是 condition,condition 這個(gè)機(jī)制表示是說:在 K8s 里面有很多這種比較小的這個(gè)狀態(tài)峻仇,而這個(gè)狀態(tài)之間的聚合會(huì)變成上層的這個(gè) Status公黑。那在這個(gè)例子里面有幾個(gè)狀態(tài),第一個(gè)是 Initialized摄咆,表示是不是已經(jīng)初始化完成凡蚜?那在這個(gè)例子里面已經(jīng)是初始化完成的,那它走的是第二個(gè)階段吭从,是在這個(gè) ready 的狀態(tài)朝蜘。因?yàn)樯厦鎺讉€(gè) container 沒有拉取下來相應(yīng)的鏡像,所以 ready 的狀態(tài)是 false影锈。
然后再往下可以看到這個(gè) container 是否 ready芹务,這里可以看到是 false,而這個(gè)狀態(tài)是 PodScheduled鸭廷,表示說當(dāng)前這個(gè) pod 是否是處在一個(gè)已經(jīng)被調(diào)度的狀態(tài)枣抱,它已經(jīng) bound 在現(xiàn)在這個(gè) node 之上了,所以這個(gè)狀態(tài)也是 true辆床。
那可以通過相應(yīng)的 condition 是 true 還是 false 來判斷整體上方的這個(gè)狀態(tài)是否是正常的一個(gè)狀態(tài)佳晶。而在 K8s 里面不同的狀態(tài)之間的這個(gè)轉(zhuǎn)換都會(huì)發(fā)生相應(yīng)的事件,而事件分為兩種: 一種叫做 normal 的事件讼载,一種是 warning 事件轿秧。大家可以看見在這第一條的事件是有個(gè) normal 事件,然后它相應(yīng)的 reason 是 scheduler咨堤,表示說這個(gè) pod 已經(jīng)被默認(rèn)的調(diào)度器調(diào)度到相應(yīng)的一個(gè)節(jié)點(diǎn)之上菇篡,然后這個(gè)節(jié)點(diǎn)是 cn-beijing192.168.3.167 這個(gè)節(jié)點(diǎn)之上。
再接下來一喘,又是一個(gè) normal 的事件驱还,表示說當(dāng)前的這個(gè)鏡像在 pull 相應(yīng)的這個(gè) image。然后再往下是一個(gè) warning 事件凸克,這個(gè) warning 事件表示說 pull 這個(gè)鏡像失敗了议蟆。
以此類推,這個(gè)地方表示的一個(gè)狀態(tài)就是說在 K8s 里面這個(gè)狀態(tài)機(jī)制之間這個(gè)狀態(tài)轉(zhuǎn)換會(huì)產(chǎn)生相應(yīng)的事件萎战,而這個(gè)事件又通過類似像 normal 或者是 warning 的方式進(jìn)行暴露咐容。開發(fā)者可以通過類似像通過這個(gè)事件的機(jī)制,可以通過上層 condition Status 相應(yīng)的一系列的這個(gè)字段來判斷當(dāng)前這個(gè)應(yīng)用的具體的狀態(tài)以及進(jìn)行一系列的診斷蚂维。
應(yīng)用故障排查-常見應(yīng)用異常
本小節(jié)介紹一下常見應(yīng)用的一些異常戳粒。首先是 pod 上面,pod 上面可能會(huì)停留幾個(gè)常見的狀態(tài)鸟雏。
Pod 停留在 Pending
第一個(gè)就是 pending 狀態(tài)享郊,pending 表示調(diào)度器沒有進(jìn)行介入。此時(shí)可以通過 kubectl describe pod 來查看相應(yīng)的事件孝鹊,如果由于資源或者說端口占用炊琉,或者是由于 node selector 造成 pod 無法調(diào)度的時(shí)候,可以在相應(yīng)的事件里面看到相應(yīng)的結(jié)果又活,這個(gè)結(jié)果里面會(huì)表示說有多少個(gè)不滿足的 node苔咪,有多少是因?yàn)?CPU 不滿足,有多少是由于 node 不滿足柳骄,有多少是由于 tag 打標(biāo)造成的不滿足团赏。
Pod 停留在 waiting
那第二個(gè)狀態(tài)就是 pod 可能會(huì)停留在 waiting 的狀態(tài),pod 的 states 處在 waiting 的時(shí)候耐薯,通常表示說這個(gè) pod 的鏡像沒有正常拉取舔清,原因可能是由于這個(gè)鏡像是私有鏡像丝里,但是沒有配置 Pod secret;那第二種是說可能由于這個(gè)鏡像地址是不存在的体谒,造成這個(gè)鏡像拉取不下來杯聚;還有一個(gè)是說這個(gè)鏡像可能是一個(gè)公網(wǎng)的鏡像,造成鏡像的拉取失敗抒痒。
Pod 不斷被拉取并且可以看到 crashing
第三種是 pod 不斷被拉起幌绍,而且可以看到類似像 backoff 。這個(gè)通常表示說 pod 已經(jīng)被調(diào)度完成了故响,但是啟動(dòng)失敗傀广,那這個(gè)時(shí)候通常要關(guān)注的應(yīng)該是這個(gè)應(yīng)用自身的一個(gè)狀態(tài),并不是說配置是否正確彩届、權(quán)限是否正確伪冰,此時(shí)需要查看的應(yīng)該是 pod 的具體日志。
Pod 處在 Runing 但是沒有正常工作
第四種 pod 處在 running 狀態(tài)樟蠕,但是沒有正常對(duì)外服務(wù)糜值。那此時(shí)比較常見的一個(gè)點(diǎn)就可能是由于一些非常細(xì)碎的配置,類似像有一些字段可能拼寫錯(cuò)誤坯墨,造成了 yaml 下發(fā)下去了寂汇,但是有一段沒有正常地生效,從而使得這個(gè) pod 處在 running 的狀態(tài)沒有對(duì)外服務(wù)捣染,那此時(shí)可以通過 apply-validate-f pod.yaml 的方式來進(jìn)行判斷當(dāng)前 yaml 是否是正常的骄瓣,如果 yaml 沒有問題,那么接下來可能要診斷配置的端口是否是正常的耍攘,以及 Liveness 或 Readiness 是否已經(jīng)配置正確榕栏。
Service 無法正常的工作
最后一種就是 service 無法正常工作的時(shí)候,該怎么去判斷呢蕾各?那比較常見的 service 出現(xiàn)問題的時(shí)候扒磁,是自己的使用上面出現(xiàn)了問題。因?yàn)?service 和底層的 pod 之間的關(guān)聯(lián)關(guān)系是通過 selector 的方式來匹配的式曲,也就是說 pod 上面配置了一些 label妨托,然后 service 通過 match label 的方式和這個(gè) pod 進(jìn)行相互關(guān)聯(lián)。如果這個(gè) label 配置的有問題吝羞,可能會(huì)造成這個(gè) service 無法找到后面的 endpoint兰伤,從而造成相應(yīng)的 service 沒有辦法對(duì)外提供服務(wù),那如果 service 出現(xiàn)異常的時(shí)候钧排,第一個(gè)要看的是這個(gè) service 后面是不是有一個(gè)真正的 endpoint敦腔,其次來看這個(gè) endpoint 是否可以對(duì)外提供正常的服務(wù)。
四恨溜、應(yīng)用遠(yuǎn)程調(diào)試
本節(jié)講解的是在 K8s 里面如何進(jìn)行應(yīng)用的遠(yuǎn)程調(diào)試符衔,遠(yuǎn)程調(diào)試主要分為 pod 的遠(yuǎn)程調(diào)試以及 service 的遠(yuǎn)程調(diào)試找前。還有就是針對(duì)一些性能優(yōu)化的遠(yuǎn)程調(diào)試。
應(yīng)用遠(yuǎn)程調(diào)試 - Pod 遠(yuǎn)程調(diào)試
在集群中的應(yīng)用出現(xiàn)問題是判族,可通過 kubectl exec 進(jìn)入容器命令行終端進(jìn)行問題診斷:
# Pod 中只有一個(gè)容器時(shí)
kubectl exec -it pod-name /bin/bash
# Pod中有多個(gè)容器時(shí)
kubectl exec -it pod-name -c container-name /bin/bash
比如說可以通過 exec 的方式進(jìn)入一個(gè) pod纸厉。像這條命令里面,通過 kubectl exec-it pod-name 后面再填寫一個(gè)相應(yīng)的命令五嫂,比如說 /bin/bash,表示希望到這個(gè) pod 里面進(jìn)入一個(gè)交互式的一個(gè) bash肯尺。然后在 bash 里面可以做一些相應(yīng)的命令,比如說修改一些配置则吟,通過 supervisor 去重新拉起這個(gè)應(yīng)用槐臀,都是可以的。
那如果指定這一個(gè) pod 里面可能包含著多個(gè) container氓仲,這個(gè)時(shí)候該怎么辦呢水慨?怎么通過 pod 來指定 container 呢?其實(shí)這個(gè)時(shí)候有一個(gè)參數(shù)叫做 -c敬扛,如上面第二條命令所示晰洒。-c 后面是一個(gè) container-name,可以通過 pod 在指定 -c 到這個(gè) container-name啥箭,具體指定要進(jìn)入哪個(gè) container谍珊,后面再跟上相應(yīng)的具體的命令,通過這種方式來實(shí)現(xiàn)一個(gè)多容器的命令的一個(gè)進(jìn)入急侥,從而實(shí)現(xiàn)多容器的一個(gè)遠(yuǎn)程調(diào)試砌滞。
應(yīng)用遠(yuǎn)程調(diào)試 - Servic 遠(yuǎn)程調(diào)試
那么 service 的遠(yuǎn)程調(diào)試該怎么做呢?service 的遠(yuǎn)程調(diào)試其實(shí)分為兩個(gè)部分:
- 第一個(gè)部分是說我想將一個(gè)服務(wù)暴露到遠(yuǎn)程的一個(gè)集群之內(nèi)坏怪,讓遠(yuǎn)程集群內(nèi)的一些應(yīng)用來去調(diào)用本地的一個(gè)服務(wù)贝润,這是一條反向的一個(gè)鏈路;
- 還有一種方式是我想讓這個(gè)本地服務(wù)能夠去調(diào)遠(yuǎn)程的服務(wù)铝宵,那么這是一條正向的鏈路打掘。
在反向列入上面有這樣一個(gè)開源組件,叫做 Telepresence鹏秋,它可以將本地的應(yīng)用代理到遠(yuǎn)程集群中的一個(gè) service 上面胧卤,使用它的方式如下所示:
telepresence --swap-deployment $Deployment_Name
首先將 Telepresence 的一個(gè) Proxy 應(yīng)用部署到遠(yuǎn)程的 K8s 集群里面。然后將遠(yuǎn)程單一個(gè) deployment swap 到本地的一個(gè) application拼岳,使用的命令就是 Telepresence-swap-deployment 然后以及遠(yuǎn)程的 DEPLOYMENT_NAME枝誊。通過這種方式就可以將本地一個(gè) application 代理到遠(yuǎn)程的 service 之上、可以將應(yīng)用在遠(yuǎn)程集群里面進(jìn)行本地調(diào)試惜纸,這個(gè)有興趣的同學(xué)可以到 GitHub 上面來看一下這個(gè)插件的使用的方式叶撒。
第二個(gè)是如果本地應(yīng)用需要調(diào)用遠(yuǎn)程集群的服務(wù)時(shí)候绝骚,可以通過 port-forward 的方式將遠(yuǎn)程的應(yīng)用調(diào)用到本地的端口之上。比如說現(xiàn)在遠(yuǎn)程的里面有一個(gè) API server祠够,這個(gè) API server 提供了一些端口压汪,本地在調(diào)試 Code 時(shí)候,想要直接調(diào)用這個(gè) API server古瓤,那么這時(shí)止剖,比較簡(jiǎn)單的一個(gè)方式就是通過 port-forward 的方式,例如:
kubectl port-forward svc/app -n app-namespace
它的使用方式是 kubectl port-forward落君,然后 service 加上遠(yuǎn)程的 service name穿香,再加上相應(yīng)的 namespace,后面還可以加上一些額外的參數(shù)绎速,比如說端口的一個(gè)映射皮获,通過這種機(jī)制就可以把遠(yuǎn)程的一個(gè)應(yīng)用代理到本地的端口之上,此時(shí)通過訪問本地端口就可以訪問遠(yuǎn)程的服務(wù)纹冤。
開源的調(diào)試工具 - kubectl-debug
最后再給大家介紹一個(gè)開源的調(diào)試工具洒宝,它也是 kubectl 的一個(gè)插件,叫 kubectl-debug萌京。我們知道在 K8s 里面雁歌,底層的容器 runtime 比較常見的就是類似像 docker 或者是 containerd,不論是 docker 還是 containerd知残,它們使用的一個(gè)機(jī)制都是基于 Linux namespace 的一個(gè)方式進(jìn)行虛擬化和隔離的将宪。
通常情況下 ,并不會(huì)在鏡像里面帶特別多的調(diào)試工具橡庞,類似像 netstat telnet 等等這些 较坛,因?yàn)檫@個(gè)會(huì)造成應(yīng)用整體非常冗余。那么如果想要調(diào)試的時(shí)候該怎么做呢扒最?其實(shí)這個(gè)時(shí)候就可以依賴類似于像 kubectl-debug 這樣一個(gè)工具丑勤。
kubectl-debug 這個(gè)工具是依賴于 Linux namespace 的方式來去做的,它可以 datash 一個(gè) Linux namespace 到一個(gè)額外的 container吧趣,然后在這個(gè) container 里面執(zhí)行任何的 debug 動(dòng)作法竞,其實(shí)和直接去 debug 這個(gè) Linux namespace 是一致的。這里有一個(gè)簡(jiǎn)單的操作强挫,給大家來介紹一下:
這個(gè)地方其實(shí)已經(jīng)安裝好了 kubectl-debug岔霸,它是 kubectl 的一個(gè)插件。所以這個(gè)時(shí)候俯渤,你可以直接通過 kubectl-debug 這條命令來去診斷遠(yuǎn)程的一個(gè) pod呆细。像這個(gè)例子里面,當(dāng)執(zhí)行 debug 的時(shí)候八匠,實(shí)際上它首先會(huì)先拉取一些鏡像絮爷,這個(gè)鏡像里面實(shí)際上會(huì)默認(rèn)帶一些診斷的工具趴酣。當(dāng)這個(gè)鏡像啟用的時(shí)候,它會(huì)把這個(gè) debug container 進(jìn)行啟動(dòng)坑夯。與此同時(shí)會(huì)把這個(gè) container 和相應(yīng)的你要診斷的這個(gè) container 的 namespace 進(jìn)行掛靠岖寞,也就說此時(shí)這個(gè) container 和你是同 namespace 的,類似像網(wǎng)絡(luò)站柜蜈,或者是類似像內(nèi)核的一些參數(shù)仗谆,其實(shí)都可以在這個(gè) debug container 里面實(shí)時(shí)地進(jìn)行查看。
像這個(gè)例子里面淑履,去查看類似像 hostname隶垮、進(jìn)程、netstat 等等鳖谈,這些其實(shí)都是和這個(gè)需要 debug 的 pod 是在同一個(gè)環(huán)境里面的,所以你之前這三條命令可以看到里面相關(guān)的信息阔涉。
如果此時(shí)進(jìn)行 logout 的話缆娃,相當(dāng)于會(huì)把相應(yīng)的這個(gè) debug pod 殺掉,然后進(jìn)行退出瑰排,此時(shí)對(duì)應(yīng)用實(shí)際上是沒有任何的影響的贯要。那么通過這種方式可以不介入到容器里面,就可以實(shí)現(xiàn)相應(yīng)的一個(gè)診斷椭住。
此外它還支持額外的一些機(jī)制崇渗,比如說我給設(shè)定一些 image,然后類似像這里面安裝了的是 htop京郑,然后開發(fā)者可以通過這個(gè)機(jī)制來定義自己需要的這個(gè)命令行的工具宅广,并且通過這種 image 的方式設(shè)置進(jìn)來。那么這個(gè)時(shí)候就可以通過這種機(jī)制來調(diào)試遠(yuǎn)程的一個(gè) pod些举。
總結(jié)
- 關(guān)于 Liveness 和 Readiness 的指針跟狱。Liveness probe 就是保活指針户魏,它是用來看 pod 是否存活的驶臊,而 Readiness probe 是就緒指針,它是判斷這個(gè) pod 是否就緒的叼丑,如果就緒了关翎,就可以對(duì)外提供服務(wù)。這個(gè)就是 Liveness 和 Readiness 需要記住的部分鸠信;
- 應(yīng)用診斷的三個(gè)步驟:首先 describe 相應(yīng)的一個(gè)狀態(tài)纵寝;然后提供狀態(tài)來排查具體的一個(gè)診斷方向;最后來查看相應(yīng)對(duì)象的一個(gè) event 獲取更詳細(xì)的一個(gè)信息星立;
- 提供 pod 一個(gè)日志來定位應(yīng)用的自身的一個(gè)狀態(tài)店雅;
- 遠(yuǎn)程調(diào)試的一個(gè)策略政基,如果想把本地的應(yīng)用代理到遠(yuǎn)程集群,此時(shí)可以通過 Telepresence 這樣的工具來實(shí)現(xiàn)闹啦,如果想把遠(yuǎn)程的應(yīng)用代理到本地沮明,然后在本地進(jìn)行調(diào)用或者是調(diào)試,可以用類似像 port-forward 這種機(jī)制來實(shí)現(xiàn)窍奋。