溫馨提示×

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

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

Kubernetes運(yùn)維之微服務(wù)生產(chǎn)環(huán)境采坑分享

發(fā)布時(shí)間:2020-07-02 10:25:08 來源:網(wǎng)絡(luò) 閱讀:934 作者:wx5c1cfd6e22842 欄目:系統(tǒng)運(yùn)維

生產(chǎn)環(huán)境經(jīng)驗(yàn)

1、限制了容器資源,還經(jīng)常被殺死?
2、滾動(dòng)更新之健康檢查重要性
3、滾動(dòng)更新之流量的丟失

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

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

說到這個(gè)問題,怎么來解決docker的資源限制,其實(shí)這個(gè)資源限制還是用的這個(gè)docker來做的,只不過k8s把他轉(zhuǎn)換成了,只不過k8s去調(diào)用接口去做一些限制,其實(shí)就是怎么讓docker去識(shí)別java堆內(nèi)存的限制,來解決這個(gè)問題。
來解決這個(gè)問題有兩種方案,也就是為這個(gè)java再配置堆內(nèi)存的使用
配置java堆內(nèi)存的使用
Java -Xmx最大的堆內(nèi)存使用,一個(gè)是-Xms是初始的堆內(nèi)存使用
一般都設(shè)置一個(gè)最大的堆內(nèi)存使用,如果不設(shè)置超出這個(gè)設(shè)置會(huì)不斷使用宿主機(jī)的一個(gè)內(nèi)存,而導(dǎo)致物理內(nèi)存不夠用,而出現(xiàn)堆內(nèi)存溢出的現(xiàn)象,這個(gè)很普遍,我們就用這個(gè)java -Xmx就是當(dāng)快用滿時(shí),它會(huì)有一個(gè)垃圾回收,再進(jìn)行循環(huán)的使用,這樣能保證這個(gè)java應(yīng)用穩(wěn)定的運(yùn)行,所有我們?cè)趛aml去配置資源限制肯定是不夠的,我們必須為這個(gè)java去設(shè)置這個(gè)堆內(nèi)存,我們不可能手動(dòng)的在Dockerfile去寫這個(gè)吧,一般在dockerfile去傳入這個(gè)值,在yaml文件里設(shè)置一個(gè)變量

env:
  - name: JAVA_OPTS
   value: “-Xmx1g “

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

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

列入一個(gè)副本,啟動(dòng)之后提供業(yè)務(wù)需要一分鐘才能提供服務(wù),比如java啟動(dòng)比較慢,如果沒有健康狀態(tài)檢查,來確保他是不是準(zhǔn)備好,就直接認(rèn)為它準(zhǔn)備好了,這期間啟動(dòng)起來,一分鐘之內(nèi)它是無法提供服務(wù)的,所以新來的流量肯定是無法處理的,這是第一種情況,第二種情況,由于人為的配置錯(cuò)誤,比如連接不上數(shù)據(jù)庫了,或者連接不上其他地方了,或者配置文件哪里寫錯(cuò)了,那觸發(fā)一個(gè)滾動(dòng)更新,那這個(gè)pod呢全部滾動(dòng)更新完成了,結(jié)果都是由問題的,這樣的話,新副本都把舊副本替換掉了,這樣的話,生產(chǎn)環(huán)境中后果很嚴(yán)重的,很多服務(wù)都會(huì)無法提供了,所以在配置滾動(dòng)更新的時(shí)候,健康狀態(tài)檢查一定要配上,那配上了健康狀態(tài)檢查之后,新的副本檢查完成之后才會(huì)轉(zhuǎn)發(fā)新的流量,如果它沒有通過它不會(huì)全部替換的,也就是它不會(huì)繼續(xù)更新了,因?yàn)樗怯幸粋€(gè)可用節(jié)點(diǎn)的限制,如果可用節(jié)點(diǎn)達(dá)不到這個(gè)數(shù),就不會(huì)繼續(xù)更新,健康狀態(tài)檢查有兩種類型,readinessprobe是就緒的檢查,這兩種檢查方式也有不同的方式,比如http,探測(cè)一個(gè)url,還有tcp socket,端口的探測(cè),還有一個(gè)執(zhí)行shell命令,執(zhí)行一個(gè)shell命令,判斷一個(gè)返回值,所以提供者三種健康狀態(tài)檢查的方法,readinessprobe就緒檢查也就是你的Pod檢查失敗,如果是http,可以通過一個(gè)頁面去探測(cè),判斷這個(gè)返回狀態(tài)碼,如果探測(cè)這個(gè)本地的端口不通的話,它不會(huì)讓它加入service后面,因?yàn)閟ervice作為你整個(gè)的統(tǒng)一訪問入口嘛,如果它不通過的話,新的流量也不會(huì)轉(zhuǎn)發(fā)給它,這就是就緒檢查,如果健康狀態(tài)不通過不會(huì)給你轉(zhuǎn)發(fā)新的流量,另外就是initialDelaySeconds:60,就是檢查60秒,因?yàn)橐话鉰ava應(yīng)用啟動(dòng)也就是一分鐘左右,還有一個(gè)periodSeconds:10,也就是沒通過10秒鐘在做一次,然后就是livenessProbe:存活檢查。

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

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

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

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

這樣,你不需要修改你應(yīng)用的代碼,這樣的話,滾動(dòng)更新就不會(huì)轉(zhuǎn)發(fā)即將關(guān)閉的pod上了,所以也能解決這個(gè)相關(guān)的問題了。

向AI問一下細(xì)節(jié)

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

AI