軟件測(cè)試 | K8S容器技術(shù)介紹
Kubernetes 開(kāi)源于 2014 年,是谷歌 10 多年大規(guī)模容器管理系統(tǒng) Borg 的開(kāi)源版本。Kubernetes 這個(gè) 單詞在首字母 K 和尾字母 s 之間有 8 個(gè)字母,因此稱為 K8S。這種稱謂方式和 i18n (internationalization)是一致的,如果做過(guò)本地化國(guó)際化的人應(yīng)該對(duì) i18n 這樣的叫法很熟悉。 對(duì)于一 個(gè)剛剛接觸容器的初學(xué)者來(lái)說(shuō),搞清楚容器編排是什么,搞清楚 K8S 是什么是一件非常不容易的事 情。 編排二字賦予了它非常多的意義。
大多數(shù)人理解 K8S 是容器集群的管理技術(shù),這個(gè)描述是不完整的,如果 K8S 僅僅是一個(gè)管理多臺(tái)節(jié)點(diǎn) 上容器的管理軟件的話,那么業(yè)界直接稱呼為容器集群就好了。而不是像現(xiàn)在這樣稱其為容器編排領(lǐng)域 的事實(shí)標(biāo)準(zhǔn),谷歌和 Linux 也不會(huì)為了它一起創(chuàng)辦了 CNCF 云原生基金會(huì)。 所以 K8S 除了是一個(gè)容 器集群管理軟件外它還提供了針對(duì)容器的網(wǎng)絡(luò),調(diào)度,權(quán)限,資源,安全,硬件等管理和設(shè)計(jì)的能力。 接下來(lái)通過(guò) 2 個(gè)案例來(lái)帶大家體驗(yàn)一下其中的奧妙。
POD 介紹
在實(shí)際介紹 K8S 的容器編排實(shí)例前需要先了解一下 K8S 中最基本的資源類型--POD。 可以說(shuō) POD 是 K8S 中最重要的資源,其他一切的資源都是圍繞著 POD 并為其提供服務(wù)的。
用一句話說(shuō)明 POD 的定義: POD 是由多個(gè)容器組成的邏輯概念,這些容器共同配合對(duì)外提供服務(wù), 同時(shí) POD 也是 K8S 中最小的調(diào)度單位,POD 中的容器必須調(diào)度在同一臺(tái)機(jī)器上不可分割。
這么說(shuō)比較抽象,用一個(gè)實(shí)例來(lái)展示一下 POD 到底是什么。 通過(guò)下載并配置 jenkins 中 K8S 的插件 來(lái)打通兩者之間的通信,使得 jenkins 在運(yùn)行 pipeline 時(shí)可以動(dòng)態(tài)的在 K8S 中創(chuàng)建 POD 并在其中一個(gè) 容器中通過(guò) jnlp 動(dòng)態(tài)的創(chuàng)建并向 jenkins 注冊(cè) slave 節(jié)點(diǎn)(容器), 后續(xù)這個(gè) pipeline 中所有的任務(wù) 都將在這個(gè) POD 中的容器中執(zhí)行。
通過(guò)這樣的機(jī)制實(shí)現(xiàn)了更強(qiáng)大的 jenkins pipeline 的高可用和負(fù)載均衡架構(gòu)。 從此實(shí)現(xiàn)了在 K8S 中可以 動(dòng)態(tài)創(chuàng)建 jenkins 的 slave 節(jié)點(diǎn)運(yùn)行任務(wù)的能力, 并在任務(wù)結(jié)束后回收這些資源。
上面是 jenkins 動(dòng)態(tài)創(chuàng)建 POD 的配置文件,這其中為了更方便說(shuō)明我刪除了很多其他干擾項(xiàng),只留下 了最需要關(guān)注的部分??梢钥吹?containers 字段中定義兩個(gè)容器。其中名字為 jnlp 的容器是由 jenkins 提供用來(lái)與 jenkins 建立通信并注冊(cè) slave 節(jié)點(diǎn)用的。 對(duì) jenkins slave 節(jié)點(diǎn)配置比較熟悉的人對(duì)此應(yīng)該 并不陌生,除了 jnlp 外 jenkins 還支持 ssh 等協(xié)議形式的 slave 通信機(jī)制。
另外一個(gè)名字為 python3 的容器使用的就是官方提供的 python3 鏡像,它的任務(wù)是用來(lái)執(zhí)行測(cè)試任務(wù)。 也就是說(shuō)在這個(gè) POD 中分工是明確的,jnlp 容器負(fù)責(zé)注冊(cè) jenkins slave 節(jié)點(diǎn)并與之保持通信。而 python3 容器擁有 python 的執(zhí)行環(huán)境所以可以在獲取代碼后運(yùn)行諸如 pytest 這樣的測(cè)試任務(wù)。實(shí)際上 如果需要可以定義更多的容器,比如要測(cè)試一款 python sdk 的兼容性的時(shí)候, 可以再定義一個(gè) python2.6 的容器,這樣在 pipeline 中可以通過(guò)切換不同的容器達(dá)到切換運(yùn)行環(huán)境的目的以便測(cè)試 sdk 在 python3 和 python2 上的兼容性。
下面貼一下 jenkins pipeline 中的定義,還是照例刪減了其他干擾項(xiàng)。
通過(guò)上面的 Pipeline 的配置可以看到通過(guò) container 指令,可以在 pipeline 中任意的切換容器(運(yùn)行環(huán) 境)來(lái)完成 Python 的兼容性測(cè)試。這里可能有人可能會(huì)問(wèn)運(yùn)行環(huán)境可以通過(guò)切換容器來(lái)完成,但是各 個(gè)容器之間是怎么共享文件和代碼的呢? 畢竟要執(zhí)行測(cè)試必須先獲取代碼, 那這些容器是怎么獲取代 碼執(zhí)行測(cè)試的,又是通過(guò)什么方式合并每個(gè)容器中的測(cè)試報(bào)告的呢? 這個(gè)問(wèn)題可以抽象成一個(gè) POD 中 的容器是怎么共享文件的。 在學(xué)習(xí) Docker 的時(shí)候知道在啟動(dòng)容器的時(shí)候可以通過(guò)-v 這個(gè)參數(shù)來(lái)將容 器中的某個(gè)目錄或文件掛載到宿主機(jī)上, 而在 POD 中的玩法也類似。 回到上面 Jenkins 啟動(dòng)的 POD 的定義中來(lái):
上面是 POD 中關(guān)于數(shù)據(jù)卷的一段定義, 可以看到 jenkins 創(chuàng)建的 POD 定義中自動(dòng)添加了一個(gè)臨時(shí)的 共享目錄,而 POD 中所有的容器都會(huì)掛載這個(gè)目錄。 通過(guò)這樣的形式達(dá)到了所有容器共享文件的目 的。 而這個(gè)目錄就是 Jenkins 的 Workspace。相信熟悉 Jenkins 的人對(duì)此目錄不會(huì)感到陌生。

實(shí)際上多個(gè)容器間的合作不僅可以共享目錄,也可以共享網(wǎng)絡(luò)或者進(jìn)程名稱空間。 還記得學(xué)習(xí) Docker 的時(shí)候使用的 container 網(wǎng)絡(luò)模式么, 實(shí)際上 POD 中的容器都是默認(rèn)通過(guò) container 模式將網(wǎng)絡(luò)連接 在一起的,很多軟件應(yīng)用比如 mock server,流量復(fù)制,service mesh 都是通過(guò)在 POD 中額外定義一個(gè) proxy 容器劫持業(yè)務(wù)容器的網(wǎng)絡(luò)。
而如果你想使用 jvm-sandbox 這種字節(jié)碼注入工具的話還可以通過(guò)打開(kāi) POD 中 shareProcessNamespace 這個(gè)參數(shù)來(lái)共享進(jìn)程名稱空間,使得 jvm-sandbox 容器中可以看到業(yè)務(wù)容器的 進(jìn)程并以 jvm-attach 的方式進(jìn)行字節(jié)碼注入。 而這種通過(guò)啟動(dòng)多個(gè)容器互相協(xié)作配合的玩法有一個(gè)專 業(yè)名詞叫"side car"。
所以回過(guò)頭來(lái)看看什么是 POD,什么是容器編排? 從這里的角度看 POD 是容器之間的一種協(xié)作模 式,多個(gè)容器組成一個(gè) POD,而一個(gè) POD 提供了多種機(jī)制,包括但不限于共享和限制目錄,網(wǎng)絡(luò),進(jìn) 程,資源等機(jī)制來(lái)讓容器之間的協(xié)作更加順暢, 而這也是容器編排的表現(xiàn)之一, 不僅僅是運(yùn)行, 而 是多個(gè)容器配合在一起更好的運(yùn)行。
接下來(lái)再看一個(gè) K8S 中專門運(yùn)行批處理程序的資源類型:JOB。 通過(guò)介紹 JOB 的機(jī)制再來(lái)體會(huì)一下容 器編排在其他方面的威力。
批處理任務(wù)編排
實(shí)際上多個(gè)容器間的合作不僅可以共享目錄,也可以共享網(wǎng)絡(luò)或者進(jìn)程名稱空間。 還記得學(xué)習(xí) Docker 的時(shí)候使用的 container 網(wǎng)絡(luò)模式么, 實(shí)際上 POD 中的容器都是默認(rèn)通過(guò) container 模式將網(wǎng)絡(luò)連接 在一起的,很多軟件應(yīng)用比如 mock server,流量復(fù)制,service mesh 都是通過(guò)在 POD 中額外定義一個(gè) proxy 容器劫持業(yè)務(wù)容器的網(wǎng)絡(luò)。 而如果你想使用 jvm-sandbox 這種字節(jié)碼注入工具的話還可以通過(guò)打開(kāi) POD 中 shareProcessNamespace 這個(gè)參數(shù)來(lái)共享進(jìn)程名稱空間,使得 jvm-sandbox 容器中可以看到業(yè)務(wù)容器的 進(jìn)程并以 jvm-attach 的方式進(jìn)行字節(jié)碼注入。 而這種通過(guò)啟動(dòng)多個(gè)容器互相協(xié)作配合的玩法有一個(gè)專 業(yè)名詞叫"side car"。 所以回過(guò)頭來(lái)看看什么是 POD,什么是容器編排? 從這里的角度看 POD 是容器之間的一種協(xié)作模 式,多個(gè)容器組成一個(gè) POD,而一個(gè) POD 提供了多種機(jī)制,包括但不限于共享和限制目錄,網(wǎng)絡(luò),進(jìn) 程,資源等機(jī)制來(lái)讓容器之間的協(xié)作更加順暢, 而這也是容器編排的表現(xiàn)之一, 不僅僅是運(yùn)行, 而 是多個(gè)容器配合在一起更好的運(yùn)行。 接下來(lái)再看一個(gè) K8S 中專門運(yùn)行批處理程序的資源類型:JOB。 通過(guò)介紹 JOB 的機(jī)制再來(lái)體會(huì)一下容 器編排在其他方面的威力。
上面定義的是向 K8S 提交一個(gè) job 類型的也即是批處理程序請(qǐng)求的配置文件, 將這個(gè)配置文件保存為 yaml 文件后就可以通過(guò) kubectl 命令行將任務(wù)提交到 K8S 集群中運(yùn)行了, job 會(huì)幫助創(chuàng)建相應(yīng)的 POD 來(lái)完成任務(wù)。 雖然我已經(jīng)對(duì)這段配置做了一定程度的刪減,但仍然有不少的字段類型容易讓新手眼花繚 亂。 不過(guò)本次案例只需關(guān)注幾個(gè)重點(diǎn)的地方,第一個(gè)是在文件中的 template 字段, 它代表了 POD 的 模板, job 通過(guò)此模板來(lái)動(dòng)態(tài)的創(chuàng)建 POD,它定義了本次執(zhí)行測(cè)試的運(yùn)行環(huán)境, 也就是測(cè)試是在 POD 中的容器中執(zhí)行的。 K8S 會(huì)根據(jù)用戶填寫的內(nèi)容來(lái)啟動(dòng) POD。 第二個(gè)需要注意的地方是配置中 最下面的 3 個(gè)字段:
backoffLimit:可容忍的失敗次數(shù)。 穩(wěn)定性測(cè)試是要長(zhǎng)期執(zhí)行的,而任何長(zhǎng)期執(zhí)行的任務(wù)都無(wú)法保 證在運(yùn)行過(guò)程中 100% 的不出問(wèn)題,有些時(shí)候網(wǎng)絡(luò)卡頓或者公司內(nèi)的一些基礎(chǔ)設(shè)施的臨時(shí)中斷都可 能造成測(cè)試的失敗。所以 K8S 會(huì)在任務(wù)失敗時(shí)嘗試進(jìn)行重試(當(dāng)整個(gè)節(jié)點(diǎn)出現(xiàn)異常時(shí),K8S 可以 將容器調(diào)度到其他節(jié)點(diǎn)上重試執(zhí)行,擁有更好的容錯(cuò)能力),而這個(gè)字段可以理解為重試的次數(shù)
parallelism:并行的數(shù)量。 如果你的批處理任務(wù)需要并發(fā)能力,那么 K8S 會(huì)按照這個(gè)字段的數(shù)字 同時(shí)啟動(dòng)多個(gè)容器來(lái)并發(fā)的執(zhí)行。 由于大部分的測(cè)試并發(fā)能力來(lái)源于測(cè)試框架而不是外部軟件, 所以本次測(cè)試在這里填寫為 1 就可以。
completions:任務(wù)成功執(zhí)行 N 次后結(jié)束任務(wù)。 即便是像穩(wěn)定性測(cè)試這種需要長(zhǎng)期運(yùn)行的測(cè)試類 型,它也有結(jié)束測(cè)試的時(shí)候。 所以把這個(gè)參數(shù)設(shè)定為 1000 代表當(dāng)測(cè)試重復(fù)運(yùn)行了 1000 次后就 結(jié)束本次的批處理任務(wù)。
注意:每次測(cè)試運(yùn)行結(jié)束后,K8S 會(huì)銷毀當(dāng)前的容器,并啟動(dòng)一個(gè)一模一樣的新容器來(lái)執(zhí)行新的任務(wù)。 也就是在的案例里如果不出意外的話,前后會(huì)啟動(dòng) 1000 個(gè)容器來(lái)完成本次的穩(wěn)定性測(cè)試。通過(guò)這樣一 個(gè)案例的講解可以體會(huì)一下相比于原生的 Docker 容器,K8S 帶來(lái)了多少額外的能力。在 K8S 中容器只 不過(guò)是程序的運(yùn)行時(shí)環(huán)境而已,除了程序能運(yùn)行起來(lái),K8S 更關(guān)注的是程序怎樣更好的運(yùn)行。通過(guò)上面 針對(duì)配置文件最后 3 個(gè)字段的講解可以看出來(lái) K8S 在嘗試幫助用戶解決更復(fù)雜的程序運(yùn)行問(wèn)題。在本 案例中如果不使用 K8S,用戶需要編寫自己的模塊來(lái)控制測(cè)試用例的重復(fù)執(zhí)行,并發(fā),容錯(cuò)和重試機(jī) 制,也就是說(shuō)用戶需要自己編寫代碼來(lái)對(duì)測(cè)試用例進(jìn)行"編排"。在傳統(tǒng)的容器場(chǎng)景中,很多人都會(huì)把 容器當(dāng)做一個(gè)小型的虛擬機(jī)來(lái)使用--只要程序能在容器里跑起來(lái)就可以了。這種模式并不具備"編排" 的思維能力,真實(shí)的企業(yè)場(chǎng)景下要求的不僅僅是把程序跑起來(lái)就可以了,還關(guān)心容器調(diào)度到什么節(jié)點(diǎn), 什么時(shí)候觸發(fā)和結(jié)束任務(wù),當(dāng)任務(wù)出現(xiàn)異常時(shí)要如何處理,容器和容器之前如何配合以便完成更大的任 務(wù)等等。這便是 K8S 提供的"容器編排"了。希望讀者可以用心體會(huì)"容器編排"這 4 個(gè)字的含義。
接下來(lái)再看一下,如果希望任務(wù)能夠定時(shí)觸發(fā)該怎么辦呢?K8S 中同樣提供了 CronJob 類型的任務(wù),可 以看到在 schedule 字段中可以填寫 cron 表達(dá)式來(lái)定時(shí)啟動(dòng)容器完成的批處理任務(wù)。
實(shí)際上,目前看到的編排能力仍然是 K8S 的冰山一角,K8S 目前已經(jīng)成為了分布式計(jì)算平臺(tái),支持很 多大數(shù)據(jù)和機(jī)器學(xué)習(xí)的計(jì)算框架比如 Spark 和 Flink。 下面是將 Spark 任務(wù)調(diào)度到 K8S 中執(zhí)行的 Demo。
熟悉大數(shù)據(jù)領(lǐng)域的人都知道 Hadoop 是分布式計(jì)算領(lǐng)域中最流行的調(diào)度平臺(tái)。 提交的 Spark 任務(wù)都會(huì) 被調(diào)度到 Hadoop 集群中進(jìn)行調(diào)度,運(yùn)行。 但是 K8S 也同樣具備這樣的能力,通過(guò)下載支持 K8S 的 Spark 安裝包就可以使用 spark-submit 命令將任務(wù)提交到 K8S 上以容器的形態(tài)執(zhí)行,在參數(shù)中可以指定 使用多少個(gè) executor,每個(gè) executor 申請(qǐng)多少資源等等。 這便是 K8S 的魅力,如果你深入了解 K8S 會(huì)發(fā)現(xiàn)更多有趣又好用的功能。
總結(jié)
實(shí)際上除了上面講的能力外,K8S 還包含了非常多的容器編排能力,尤其對(duì)于在線服務(wù)的編排能力上尤 為強(qiáng)大, 但這部分內(nèi)容留待后續(xù)講解。 最后附上一個(gè)最簡(jiǎn)單的 K8S 流程圖幫助大家理解。畢竟 K8S 還是一個(gè)集群管理軟件,上述說(shuō)明的所有案例在提交給 K8S 后, K8S 都會(huì)按照自己的調(diào)度策略將 POD 調(diào)度到一個(gè)合適的節(jié)點(diǎn)上執(zhí)行。

掃描下方可領(lǐng)取更多學(xué)習(xí)資料(無(wú)償哦~)
