溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Kubernetes 部署微服務(wù)項目踩坑經(jīng)驗分享

發(fā)布時間:2020-07-27 22:50:45 來源:網(wǎng)絡(luò) 閱讀:402 作者:yzy121403725 欄目:云計算

導(dǎo)讀

本文給你分享我在K8S生產(chǎn)環(huán)境上部署微服務(wù)項目遇到的問題:

1、限制了容器資源,還經(jīng)常被殺死?

2、滾動更新之健康檢查重要性

3、滾動更新之流量的丟失

先說一下第一個問題,限制容器資源,還經(jīng)常去殺死的原因?


就是說部署的java應(yīng)用,不一會就重啟了,其實重啟就是在重建了,這就意味著你的pod是不健康的,然后k8s重新再幫你去拉取了,這樣的話就要去找問題去排查了,說白了其實就是被殺死了,可以通過describe去查看一下事件,一般都會能看到,由于健康狀態(tài)檢查沒通過,然后再去拉取的,因為是java應(yīng)用,由于堆內(nèi)存溢出,然后被kill掉,在日志最后一行會出現(xiàn)一個kill的字段,看一下它重啟的原因,之前我遇到的是它的堆內(nèi)存沒限制住,它本身有jvm,jvm主要有內(nèi)存做交換數(shù)據(jù)的,它堆內(nèi)存主要是性能設(shè)計的一個體現(xiàn),所以他的堆內(nèi)存很容易就會超出,超出之后呢,很可能會被k8s殺死掉,
為什么k8s會kill它,因為它超出了限制,默認容器會使用宿主機所有的資源,如果不做資源限制,會影響整個宿主機,然后整個宿主機資源不夠會實現(xiàn)飄移,會轉(zhuǎn)移到其他主機上,然后再異常,可能會起到一種雪崩的效應(yīng),所以一般我們都是要做資源限制的,難道這個限制,限制不了java應(yīng)用嗎?其實它是限制不住的,雖然k8s部署應(yīng)用還是很方便的,但是部署java應(yīng)用還是不兼容的,比如它不能識別當(dāng)前java容器的限制,就是不能識別我們指定的限制,也就是你在yaml去限制的,容器的堆內(nèi)存沒有限制,它就會超出這個限制,如果超出這個limits的限制,k8s就會把它殺掉,k8s自身它有這個策略,如果超出這個容量的限制,就會幫你殺掉,再幫你拉起。

面對java這樣的堆內(nèi)存稍微有一點流量突發(fā),就可能資料利用率就上來了,所以這個幅度還是比較大的,這樣就會導(dǎo)致k8s殺掉,然后再拉起,這樣循環(huán),可能一天幾百次的這樣效果。

說到這個問題,怎么來解決docker的資源限制,其實這個資源限制還是用的這個docker來做的,只不過k8s把他轉(zhuǎn)換成了,只不過k8s去調(diào)用接口去做一些限制,其實就是怎么讓docker去識別java堆內(nèi)存的限制,來解決這個問題。
來解決這個問題有兩種方案,也就是為這個java再配置堆內(nèi)存的使用,Java -Xmx最大的堆內(nèi)存使用,一個是-Xms是初始的堆內(nèi)存使用。

一般都設(shè)置一個最大的堆內(nèi)存使用,如果不設(shè)置超出這個設(shè)置會不斷使用宿主機的一個內(nèi)存,而導(dǎo)致物理內(nèi)存不夠用,而出現(xiàn)堆內(nèi)存溢出的現(xiàn)象,這個很普遍,我們就用這個java -Xmx就是當(dāng)快用滿時,它會有一個垃圾回收,再進行循環(huán)的使用,這樣能保證這個java應(yīng)用穩(wěn)定的運行,所有我們在yaml去配置資源限制肯定是不夠的,我們必須為這個java去設(shè)置這個堆內(nèi)存,我們不可能手動的在Dockerfile去寫這個吧,一般在dockerfile去傳入這個值,在yaml文件里設(shè)置一個變量:

env:
?- name: JAVA_OPTS

? ? value: “-Xmx1g “

下面就是我們之前配置的容器資源的一些限制這個變量就會就會傳入pod里面,也就是這個構(gòu)建鏡像的容器里,也就是起到容器CMD 命令下去傳入$JAVA_OPTS的變量,它會調(diào)用我們系統(tǒng)的系統(tǒng)變量,這個系統(tǒng)變量已經(jīng)賦予它值了,所以它能直接飲用這個變量了,去起到這個應(yīng)用,從而設(shè)置這個堆內(nèi)存大小,這個值建議要比limlts要小一點,小個10%吧,因為超過這個limits限制就會殺死,再拉取了。
一般設(shè)置好,重建一下鏡像,進入容器中去查看一下進程就可以看到,其他的也是這么設(shè)置的。

第二個問題,滾動更新之健康檢查的重要性

滾動更新是k8s的默認策略,一般咱們部署到k8s之后第一個會使用到的,當(dāng)你配置了健康檢查時,滾動更新會根據(jù)probe的狀態(tài)來判斷是不是繼續(xù)的更新允許接入流量,也就是你當(dāng)前的應(yīng)用是不是提供服務(wù),這樣你滾動更新的過程中,才會確保你是不是有可用的節(jié)點,保證一個平滑的升級,所以這是滾動更新設(shè)置的一個之初,那健康狀態(tài)檢查是很重要的!

健康狀態(tài)檢查在滾動更新啟動什么作用呢?

列入一個副本,啟動之后提供業(yè)務(wù)需要一分鐘才能提供服務(wù),比如java啟動比較慢,如果沒有健康狀態(tài)檢查,來確保他是不是準備好,就直接認為它準備好了,這期間啟動起來,一分鐘之內(nèi)它是無法提供服務(wù)的,所以新來的流量肯定是無法處理的,這是第一種情況,第二種情況,由于人為的配置錯誤,比如連接不上數(shù)據(jù)庫了,或者連接不上其他地方了,或者配置文件哪里寫錯了,那觸發(fā)一個滾動更新,那這個pod呢全部滾動更新完成了,結(jié)果都是由問題的,這樣的話,新副本都把舊副本替換掉了,這樣的話,生產(chǎn)環(huán)境中后果很嚴重的,很多服務(wù)都會無法提供了,所以在配置滾動更新的時候,健康狀態(tài)檢查一定要配上,那配上了健康狀態(tài)檢查之后,新的副本檢查完成之后才會轉(zhuǎn)發(fā)新的流量,如果它沒有通過它不會全部替換的,也就是它不會繼續(xù)更新了,因為它是有一個可用節(jié)點的限制,如果可用節(jié)點達不到這個數(shù),就不會繼續(xù)更新。

健康狀態(tài)檢查有兩種類型:

  • readinessProbe:就緒檢查,也就是你的Pod檢查失敗,如果是http,可以通過一個頁面去探測,判斷這個返回狀態(tài)碼,如果探測這個本地的端口不通的話,它不會讓它加入service后面,因為service作為你整個的統(tǒng)一訪問入口嘛,如果它不通過的話,新的流量也不會轉(zhuǎn)發(fā)給它,這就是就緒檢查,如果健康狀態(tài)不通過不會給你轉(zhuǎn)發(fā)新的流量,另外就是initialDelaySeconds:60,就是檢查60秒,因為一般java應(yīng)用啟動也就是一分鐘左右,還有一個periodSeconds:10,也就是沒通過10秒鐘在做一次。

  • livenessProbe:存活檢查,也就是檢查失敗它會殺死容器,根據(jù)你重啟策略,一般是重建,再給你新拉取一個容器,再判斷有沒有準備好,判斷的方法也是根據(jù)端口的探測這些的,或者特可以用其他兩種方法,http,exec,所以一般這兩個都要配置上,就緒檢查呢就是不為你分配新的流量,存活檢查就是去幫你重新拉取。


這兩種檢查也有不同的探測方式,比如http,探測一個url,還有tcp socket,端口的探測,還有一個執(zhí)行shell命令,執(zhí)行一個shell命令,判斷一個返回值。

最后一個問題滾動更新之丟失的流量

一般現(xiàn)象就是連接拒絕,響應(yīng)錯誤,調(diào)用不到。
滾動更新是關(guān)閉現(xiàn)有的pod,再起一新的pod,關(guān)閉現(xiàn)有的其實是就是刪除了一個pod,然后apiserver會通知給kubelet,然后kubelet會關(guān)閉這個容器,然后從service后端摘掉,就不分發(fā)新的流量了,然后移除掉,然后再告訴kube-proxy,你可以處理新的轉(zhuǎn)發(fā)規(guī)則了,然后調(diào)度到節(jié)點上,其實這也是一個pod的下線周期。
另外再轉(zhuǎn)發(fā)的過程中,轉(zhuǎn)發(fā)新的pod時間段里,它是有間隔的,關(guān)閉pod之后會有一個等待時間,在這個時間呢,可能還會接入一些新的流量,但是它的服務(wù)已經(jīng)不再處理新的請求了,所以會導(dǎo)致連接拒絕了,怎么去解決這個問題呢,實際上readiness探針在整個過程中并起到關(guān)鍵的作用,一旦endpoint收到pod 的刪除事件后,這已經(jīng)就與readiness探測結(jié)果不相關(guān)了。

怎么保證它優(yōu)雅的去處理呢?
其實之需要在
關(guān)閉這個pod 時加個休眠的時間,其實就可以解決這個問題了,在關(guān)閉和啟動都是有一個鉤子存在的,所有可以在關(guān)閉容器前,執(zhí)行這個鉤子,鉤子這個定義一個shell,也可以定義一個http請求,也就是支持者兩種類型,也就是在container同級,env這里。
休眠5秒也就是你關(guān)閉的容器不會馬上退出,然后休眠5秒鐘,再去關(guān)閉著應(yīng)用,這5秒能夠足夠讓kube-proxy刷新這個規(guī)則,這樣的話,就不會將新加入的流量轉(zhuǎn)發(fā)到這個剛關(guān)閉的pod上,增加這個鉤子就能暫緩你關(guān)閉pod的時間,從而讓kube-proxy增加刷新規(guī)則的時間。如下:

lifecycle :
?preStop:
? exec:
? ? ?command :
? ? ? ? ?- sh
? ? ? ? ?- -c
? ? ? ? ?- “sleep 5”

這樣,你不需要修改你應(yīng)用的代碼,就能解決該問題了。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI