日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
兩年云原生落地實踐在運維和開發(fā)側(cè)踩過的六個坑

兩年云原生落地實踐在運維和開發(fā)側(cè)踩過的六個坑

作者:應(yīng)闊浩 李建宇 等 2022-12-21 11:37:34

新聞

云計算 云原生落地之路并不是一帆風(fēng)順的,無論是在運維側(cè)還是研發(fā)側(cè),我們都走過不少冤枉路,下面把曾經(jīng)遇到的“坑”匯總到一起,分享給在云原生之路探索的你。

運維側(cè)的教訓(xùn)

運維側(cè)最核心的目標(biāo)就是保障 Kubernetes 集群的穩(wěn)定性,在搭建 Kubernetes 集群的過程中,我們遇到了 2 個比較嚴(yán)重的問題,一個是容器產(chǎn)生僵尸進(jìn)程,另一個是內(nèi)核 Bug 引起的 Kubelet 負(fù)載飆升。

1.1 容器產(chǎn)生僵尸進(jìn)程

Web 終端僵尸進(jìn)程是困擾我們很久的問題,表現(xiàn)為當(dāng)研發(fā)人員重啟 Pod 時,發(fā)現(xiàn)集群中存在偶發(fā)的一些狀態(tài)為 Not Ready 的節(jié)點,非常詭異,百思不得其解。后來發(fā)現(xiàn)原來是過多的 Bash 進(jìn)程觸發(fā)了 containerd-shim 的一個 Bug 所致。讓我們一起來剖析問題的前因后果。

問題描述

在集群正常運行過程中,運維人員隔一段時間就會收到集群節(jié)點 Not Ready 的告警,當(dāng) Not Ready 狀態(tài)持續(xù)一段時間后,Kubernetes 集群為了保持服務(wù)的高可用就會自動觸發(fā)保護(hù)機制,進(jìn)行整機遷移。

導(dǎo)致節(jié)點狀態(tài)變?yōu)?Not Ready 的原因有很多,經(jīng)排查發(fā)現(xiàn),狀態(tài)變?yōu)?Not Ready 的 Node 上存在一些處于 terminating 狀態(tài)的 Pod,這些 Pod 的狀態(tài)一直停留在 terminating,無法正常終止。同時,在 Node 上執(zhí)行 docker ps 命令,發(fā)現(xiàn)命令無法正常輸出,一直在等待 Docker 返回結(jié)果。由于 Kubelet 同樣依賴 Docker 相關(guān)命令探測容器狀態(tài),就會導(dǎo)致 Kubelet 內(nèi)部的健康檢查超時,進(jìn)而引發(fā) Node 狀態(tài)被標(biāo)記為 Not Ready。為什么 docker ps 命令會卡死呢?經(jīng)過進(jìn)一步排查發(fā)現(xiàn),所有出現(xiàn)問題的 Node 上均存在僵尸進(jìn)程,并且這些僵尸進(jìn)程均是由這些持續(xù)處于 terminating 狀態(tài)的 Pod 所創(chuàng)建。

問題原因

為了便于開發(fā)人員調(diào)試和實時查看容器日志,發(fā)布平臺提供了 Web 終端功能,讓研發(fā)人員可以在瀏覽器中直接進(jìn)入容器,并執(zhí)行各種命令。

Web 終端通過 WebSocket 技術(shù)連接一個后端服務(wù),該后端服務(wù)會調(diào)用 API Server 提供的 exec API(通過 client-go 實現(xiàn)),在容器中啟動一個 Bash 進(jìn)程,并將該 Bash 進(jìn)程的標(biāo)準(zhǔn)輸入、輸出流與 WebSocket 連接到一起,最終實現(xiàn)了基于 Web 技術(shù)的終端。

問題就出現(xiàn)在這個 Bash 進(jìn)程上,由于該進(jìn)程并不是由容器父進(jìn)程(Pid 0)派生的,而是由 containerd-shim 派生出來的,如圖 17-1 所示,因此當(dāng)容器被關(guān)閉時,Bash 進(jìn)程無法收到容器父進(jìn)程發(fā)送的退出信號,需要等待 Kubelet 通知 containerd-shim,由 containerd-shim 發(fā)送 killall 指令給容器內(nèi)的所有進(jìn)程,并等待這些進(jìn)程退出。

圖 17-1 Bash 僵尸進(jìn)程原理圖

containerd-shim 在實現(xiàn)這一步時,使用了一個長度為 32 的阻塞 Channel(Golang 的一種數(shù)據(jù)結(jié)構(gòu))來偵聽子進(jìn)程的退出事件,如果子進(jìn)程較多,觸發(fā)的退出事件會充滿整個 Channel,進(jìn)而觸發(fā) containerd-shim 出現(xiàn)死鎖,無法正確回收子進(jìn)程,從而導(dǎo)致產(chǎn)生了僵尸進(jìn)程。而在 containerd-shim 發(fā)生死鎖后,Kubelet 一旦運行 docker inspect 命令查看該容器狀態(tài),對應(yīng)的線程便會掛起,最終導(dǎo)致 Node 進(jìn)入 Not Ready 狀態(tài)。

解決方案

定位到問題后,解決問題的核心思路是減少 containerd-shim 下派生的子進(jìn)程 Bash 的數(shù)量上,我們通過 4 步來解決該問題。

  1. 優(yōu)化 Web 終端代碼,在用戶關(guān)閉瀏覽器窗口后(WebSocket 連接斷開),模擬發(fā)送 CTRL+C 和 exit 命令給 Bash 進(jìn)程,觸發(fā) Bash 進(jìn)程主動退出,如圖 17-2 所示。
  2. 設(shè)置 Web 終端的超時時間,在 Web 終端空閑 10 分鐘后(WebSocket 上沒有數(shù)據(jù)傳輸),觸發(fā)其主動退出。
  3. 如果用戶使用了 Vim 等會搶占終端輸入流的命令,便無法使用第 1 步的方法退出 Bash 進(jìn)程,我們在每臺 Node 上添加了定時任務(wù),主動清理存活 30 分鐘以上的 Bash 進(jìn)程。
  4. 盡量避免使用 exec 類型的探針,而是使用 HTTP 探針替代,exec 探針同樣是在 containerd-shim 下派生子進(jìn)程,也容易造成子進(jìn)程過多。

圖17-2通過exit命令主動關(guān)閉終端進(jìn)程

1.2 內(nèi)核 Bug 引起的 Kubelet 負(fù)載飆升

問題描述

在測試階段發(fā)現(xiàn),當(dāng)集群運行一段時間后,研發(fā)人員在發(fā)布新應(yīng)用時 Pod 的創(chuàng)建非常緩慢,Web 終端連接超時,Prometheus 獲取數(shù)據(jù)經(jīng)常丟失,集群宿主機 CPU 負(fù)載飆升。

問題分析

從 Pod 創(chuàng)建的過程開始排查,我們使用 kubectl describe 命令查看 Pod 的創(chuàng)建過程,發(fā)現(xiàn)從 Pod 資源對象的創(chuàng)建到調(diào)度到具體 Node 的耗時很短,說明調(diào)度器沒有問題。而在 Pod 調(diào)度完成后,Kubelet 拉取鏡像和創(chuàng)建容器等動作耗時較長,我們懷疑是 Kubelet 的問題,經(jīng)查看發(fā)現(xiàn) Kubelet 使用的 CPU 時間片偶爾會達(dá)到 400%左右,系統(tǒng)調(diào)用占比較高,最高達(dá)到 40%,隨后開始對 Kubelet 進(jìn)行 CPU 性能分析。

GitHub 上有相同的問題, ?https://github.com/google/cadvisor/issues/1774?

紅帽官方也有此 Bug 的討論地址為 https://bugzilla.redhat.com/show_bug.cgi?id=1795049

博文很長,總結(jié)要點如下。

在 Kubernetes 集群中,網(wǎng)絡(luò)延遲會升高到 100ms。這是由于內(nèi)核做了太多的工作(在 memcg_stat_show 中)導(dǎo)致網(wǎng)絡(luò)依賴出現(xiàn)軟中斷。文章中的例子和我們遇到的場景類似,都

是因為 cAdvisor 從/sys/fs/cgroup/memory/memory.stat 中獲取監(jiān)控數(shù)據(jù)引發(fā)的。

解決方案

  1. 使用 shell 命令檢查耗時,如果耗時大于 1s,甚至超過 10s,那么可以判定當(dāng)前系統(tǒng)的內(nèi)核存在上面描述的 Bug。
  2. 使用 shell 命令/proc/sys/vm/drop_caches>可以減緩網(wǎng)絡(luò)延時,但治標(biāo)不治本。
  3. 禁止 Kubelet 使用 cAdvisor 收集 Cgroup 信息,這樣會失去部分監(jiān)控數(shù)據(jù)。
  4. 升級內(nèi)核版本。

其中方案 1、2、3 屬于臨時方案,推薦使用方案 4,升級內(nèi)核版本,我們將內(nèi)核版本升級到 4.19.113-300.el7.x86_64 后,就避免了這個問題。

開發(fā)側(cè)的教訓(xùn)

除了運維側(cè)踩了很多坑,開發(fā)側(cè)同樣也遇到了不少棘手的問題。

2.1 運營問題(使用方式和習(xí)慣的改變)

在平臺推廣初期,盡管新平臺相較老平臺在各方面都有了很大程度的提升,但平臺的推廣并沒有收到令人滿意的效果。這里主要存在開發(fā)習(xí)慣、遷移成本以及對于一個新產(chǎn)品的不信任等因素,因此,基礎(chǔ)架構(gòu)團隊經(jīng)過深入的用戶調(diào)研和分析后,決心大力運營平臺推廣,主要從技術(shù)手段和人力手段兩個維度并行展開。

在技術(shù)層面,針對老平臺提供一鍵遷移代碼倉庫、一鍵托管配置文件等效率工具,幫助用戶低成本地從老平臺遷移到新平臺,避免因為煩瑣的操作而耗費用戶的耐心。

在人力層面,為公司的每個業(yè)務(wù)技術(shù)團隊分配專人進(jìn)行推進(jìn),手把手協(xié)助業(yè)務(wù)團隊做應(yīng)用遷移。這一步看似低效,在實際執(zhí)行中效果非常好。人與人、面對面的溝通,更容易建立業(yè)務(wù)線技術(shù)團隊對新平臺的信任,幫助他們初步遷移幾個應(yīng)用后,后續(xù)的遷移均是由各個業(yè)務(wù)線研發(fā)人員自主進(jìn)行的,實際消耗時間成本并不高。同時,在手把手幫助業(yè)務(wù)線遷移的過程中,可以從用戶視角觀察產(chǎn)品交互效果,這個過程也幫助我們找到了很多平臺存在的缺陷,大大促進(jìn)了平臺的進(jìn)一步優(yōu)化。

2.2 IP 白名單訪問控制

在應(yīng)用進(jìn)行容器化部署的過程中,也暴露出了現(xiàn)有架構(gòu)不合理的地方,比如在解決訪問鑒權(quán)問題時,過度依賴 IP 白名單。IP 白名單是一種低成本且能初步滿足需求的鑒權(quán)機制,但存在不靈活、不易擴展等問題,例如很容易出現(xiàn)上游應(yīng)用部署實例進(jìn)行變更或者擴容時,下游應(yīng)用沒有及時修改 IP 白名單,導(dǎo)致訪問被拒絕,從而引發(fā)線上故障。同時 IP 白名單也不是一種足夠安全的鑒權(quán)機制,尤其是 IP 可能會被回收并重新分配給其他應(yīng)用使用,這時如果沒有及時回收原有 IP 上的授權(quán),很有可能引發(fā)權(quán)限泄漏。

在應(yīng)用進(jìn)行容器化改造后,由于我們直接使用的是原生的網(wǎng)絡(luò)方案,在容器被重新調(diào)度后,容器的 IP 會發(fā)生改變,這樣便無法沿用 IP 白名單鑒權(quán)機制。為此我們從訪問方以及服務(wù)提供方兩個方向入手,制定了 3 個階段的改造方案。

第一階段,添加代理層。我們在訪問方與服務(wù)提供方二者之間,部署了一套 Nginx 代理服務(wù)器,將 Kubernetes Ingress 的 IP 作為服務(wù)提供方的上游客戶端地址,配置進(jìn)入 Nginx 相應(yīng)域名的上游客戶端。對訪問方進(jìn)行改造,將原始服務(wù)提供方的域名替換為代理服務(wù)器的域名。改造后,從服務(wù)提供方視角觀察到的訪問方 IP 變?yōu)榇矸?wù)器的 IP,這時將代理服務(wù)器的 IP 配置進(jìn)服務(wù)提供方的 IP 白名單后,無論訪問方的 IP 如何變化,都不會被服務(wù)提供方的 IP 白名單限制了。

第二階段,提供服務(wù)方改造。在第一階段實施完成后,雖然訪問方實現(xiàn)了容器化改造,但在服務(wù)提供方留下了安全漏洞,只要獲取新加入的代理層 IP,即可將自己偽裝成剛剛完成容器化改造的應(yīng)用,并以該應(yīng)用的身份調(diào)用服務(wù)提供方。在第二階段,我們要對服務(wù)提供方進(jìn)行改造,讓其支持 API Key、對稱簽名等與 IP 無關(guān)的訪問控制機制,以抵御代理層引入的安全風(fēng)險。

第三階段,訪問方改造。在服務(wù)提供方完成與 IP 無關(guān)的訪問控制機制后,訪問方應(yīng)隨之做改造,以支持新的訪問控制方式。這時訪問方就可以將服務(wù)提供方的地址從代理服務(wù)器切換回服務(wù)提供方的真實地址了。在經(jīng)過一段時間的驗證后,訪問方即可將代理服務(wù)器的 IP 從 IP 白名單列表中移除,最終完成整個改造方案。

2.3 流量平滑遷移

在平臺推廣初期,除去試水的新應(yīng)用,很大一批應(yīng)用是從老發(fā)布平臺遷移到容器化平臺上的。在遷移過程中,我們必須幫助用戶將老平臺的流量平滑、逐步遷移到新平臺上。

我們通過在原有 Nginx 代理中,添加 Kubernetes Ingress IP 的方式,進(jìn)行一段時間的灰度發(fā)布,逐漸調(diào)高 Kubernetes 流量的權(quán)重,直至將 100%的流量遷移至 Kubernetes。在切換初期,我們并不會直接調(diào)整 DNS,而是將 Ingress IP 加入域名的上游客戶端,例如以下 Nginx 配置代碼片段。

其中 10.16.55.*段是應(yīng)用的原始服務(wù)節(jié)點,而 10.216.15.96 與 10.216.15.196 是 Ingress 的 IP 地址,將 Ingress IP 加入域名的上游客戶端中后,流量就可以根據(jù)我們配置的 weight 參數(shù)再均攤到多個節(jié)點中。通過逐步增大 Ingress 節(jié)點的 weight 值,將應(yīng)用原節(jié)點的 weight 值降為 0,再持續(xù)運行一段時間后,即可將 DNS 直接配置解析到 Ingress 中,完成流量的最終切換。

在切換過程中,有以下需要注意的問題。

  • 在遷移過程中,新需求上線時,業(yè)務(wù)線研發(fā)需要在新/老兩個平臺上同時上線,切記不能忘記更新原有平臺的應(yīng)用代碼。
  • 由于額外添加了一層代理,外部觀察到的容器響應(yīng)時間會比實際的高,這時需要從應(yīng)用本身去觀測性能指標(biāo),并與老平臺的應(yīng)用進(jìn)行對比。
  • 額外的代理層除了會對響應(yīng)時間造成影響,還會額外記錄一份響應(yīng)日志,即訪問會在原 Nginx 服務(wù)器上記錄一次,同時在 Ingress 服務(wù)器上也記錄一次。在遷移過程中,很難完全排查這部分統(tǒng)計誤差。

2.4 上線后的分支要不要刪除?

Aone Flow 分支模型雖然靈活,但會在代碼倉庫中創(chuàng)建大量短生命周期的分支,有兩種分支需要進(jìn)行定期清理。

第一種是發(fā)布分支。每次有特性分支從發(fā)布分支退出時,就會導(dǎo)致相應(yīng)環(huán)境的發(fā)布分支被重新創(chuàng)建,如圖 17-3 所示。

圖17-3特性分支退出并重建發(fā)布分支

在特性分支(feature/001)退出后,我們會創(chuàng)建新的發(fā)布分支(release/daily/20211105),這時舊發(fā)布分支(release/daily/20211102)的生命周期便結(jié)束了,特性分支(feature/002)的后續(xù)提交均會合并到新的發(fā)布分支(release/daily/20211105)上,此時舊發(fā)布分支便可以被安全地刪除。

注意,雖然刪除發(fā)布分支一般不會導(dǎo)致代碼丟失,但如果在該發(fā)布分支上解決過代碼合并沖突,這部分解決合并沖突的工作需要在新的發(fā)布分支上重新進(jìn)行一次。如果之前發(fā)生沖突時,是在特性分支上解決的,就無需重復(fù)進(jìn)行沖突的解決了。這也是遇到分支沖突時,推薦在特性分支上解決沖突的原因。

第二種需要清理的分支是特性分支。在特性分支被發(fā)布到正式環(huán)境,并且合并到主干分支后,即可標(biāo)記特性分支為可以被刪除。與發(fā)布分支重建后,老發(fā)布分支可被立刻刪除不同,我們對特性分支采取了延遲刪除的策略,每周將歷史上已經(jīng)處于凍結(jié)狀態(tài)的特性分支進(jìn)行清理。

為什么不立刻刪除已經(jīng)上線的特性分支呢?這是因為雖然特性分支已經(jīng)被合并到主干分支,但可能在上線后發(fā)現(xiàn)代碼存在 Bug,需要進(jìn)行及時修復(fù),這時最高效的方式是在引入 Bug 的特性分支上進(jìn)行代碼修改,并立刻進(jìn)行回歸測試,然后重新上線修復(fù)。但特性分支在上線后,狀態(tài)會被標(biāo)記為已凍結(jié),無法重新上線,這時發(fā)布平臺可以從已凍結(jié)的特性分支中快速復(fù)制并得到一個新的分支,進(jìn)行上線修復(fù)。如果我們在特性分支上線后,立刻刪除該特性分支,就無法做到這一點了。

自如官方深度復(fù)盤云原生落地全過程,云原生和DevOps實踐標(biāo)準(zhǔn)讀物,沈劍、孫玄、喬新亮、史海峰等17位專家力薦.

會額外記錄一份響應(yīng)日志,即訪問會在原Nginx服務(wù)器上記錄一次,同時在Ingress服務(wù)器上也記錄一次。在遷移過程中,很難完全排查這部分統(tǒng)計誤差。

3.上線后的分支要不要刪除?

Aone Flow分支模型雖然靈活,但會在代碼倉庫中創(chuàng)建大量短生命周期的分支,有兩種分支需要進(jìn)行定期清理。

第一種是發(fā)布分支。每次有特性分支從發(fā)布分支退出時,就會導(dǎo)致相應(yīng)環(huán)境的發(fā)布分支被重新創(chuàng)建,如圖17-3所示。

圖17-3特性分支退出并重建發(fā)布分支

在特性分支(feature/001)退出后,我們會創(chuàng)建新的發(fā)布分支(release/daily/20211105),這時舊發(fā)布分支(release/daily/20211102)的生命周期便結(jié)束了,特性分支(feature/002)的后續(xù)提交均會合并到新的發(fā)布分支(release/daily/20211105)上,此時舊發(fā)布分支便可以被安全地刪除。

注意,雖然刪除發(fā)布分支一般不會導(dǎo)致代碼丟失,但如果在該發(fā)布分支上解決過代碼合并沖突,這部分解決合并沖突的工作需要在新的發(fā)布分支上重新進(jìn)行一次。如果之前發(fā)生沖突時,是在特性分支上解決的,就無需重復(fù)進(jìn)行沖突的解決了。這也是遇到分支沖突時,推薦在特性分支上解決沖突的原因。

第二種需要清理的分支是特性分支。在特性分支被發(fā)布到正式環(huán)境,并且合并到主干分支后,即可標(biāo)記特性分支為可以被刪除。與發(fā)布分支重建后,老發(fā)布分支可被立刻刪除不同,我們對特性分支采取了延遲刪除的策略,每周將歷史上已經(jīng)處于凍結(jié)狀態(tài)的特性分支進(jìn)行清理。

為什么不立刻刪除已經(jīng)上線的特性分支呢?這是因為雖然特性分支已經(jīng)被合并到主干分支,但可能在上線后發(fā)現(xiàn)代碼存在Bug,需要進(jìn)行及時修復(fù),這時最高效的方式是在引入Bug的特性分支上進(jìn)行代碼修改,并立刻進(jìn)行回歸測試,然后重新上線修復(fù)。但特性分支在上線后,狀態(tài)會被標(biāo)記為已凍結(jié),無法重新上線,這時發(fā)布平臺可以從已凍結(jié)的特性分支中快速復(fù)制并得到一個新的分支,進(jìn)行上線修復(fù)。如果我們在特性分支上線后,立刻刪除該特性分支,就無法做到這一點了。


名稱欄目:兩年云原生落地實踐在運維和開發(fā)側(cè)踩過的六個坑
鏈接URL:http://m.5511xx.com/article/coijgih.html