阿里工程師開(kāi)發(fā)了一款免費(fèi)工具,提升Kubernetes應(yīng)用開(kāi)發(fā)效率
對(duì)于使用了Kubernetes作為應(yīng)用運(yùn)行環(huán)境的開(kāi)發(fā)者而言,在同一個(gè)集群中我們可以使用命名空間(Namespace)快速創(chuàng)建多套隔離環(huán)境,在相同命名空間下,服務(wù)間使用Service的內(nèi)部DNS域名進(jìn)行相互訪問(wèn)。 基于Kubernetes強(qiáng)大的隔離以及服務(wù)編排能力,可以實(shí)現(xiàn)一套定義編排(YAML)多處部署的能力。
不過(guò),一般來(lái)說(shuō)Kubernetes使用的容器網(wǎng)絡(luò)與開(kāi)發(fā)者的所在的辦公網(wǎng)絡(luò)直接并不能直接連通。 因此,如何高效的利用Kubernetes進(jìn)行服務(wù)間的聯(lián)調(diào)測(cè)試,成為在日常開(kāi)發(fā)工作中一道繞不開(kāi)的坎。本文我們就來(lái)聊一聊,如何加速基于Kubernetes的研發(fā)效率。
使用自動(dòng)流水線
為了能夠讓開(kāi)發(fā)者能夠更快的將修改的代碼部署到集群測(cè)試環(huán)境中,一般來(lái)說(shuō)我們會(huì)引入持續(xù)交付流水線,將代碼的編譯,鏡像的打包上傳以及部署通過(guò)自動(dòng)化的方式來(lái)解決。如下所示:
從一定程度上來(lái)說(shuō),這種方式可以避免開(kāi)發(fā)人員進(jìn)行大量重復(fù)性的工作。但是,雖然整個(gè)過(guò)程自動(dòng)化了,但是開(kāi)發(fā)人員也不得不每次進(jìn)行代碼變更之后都需要等待流水線的運(yùn)行。對(duì)于開(kāi)發(fā)人員來(lái)說(shuō),每次代碼變更后等待流水線運(yùn)行或許已經(jīng)成為整個(gè)開(kāi)發(fā)任務(wù)過(guò)程中體驗(yàn)最糟糕的部分。
打破網(wǎng)絡(luò)限制,本地聯(lián)調(diào)
理想狀態(tài)下是開(kāi)發(fā)者可以直接在本地啟動(dòng)服務(wù),并且這個(gè)服務(wù)就可以無(wú)縫的和遠(yuǎn)程的kubernetes集群中的各個(gè)其它服務(wù)實(shí)現(xiàn)互相調(diào)用。需要解決兩個(gè)問(wèn)題:
- 我依賴了其它的服務(wù):運(yùn)行在本地的代碼可以直接通過(guò)podIP,clusterIP甚至是Kubernetes集群內(nèi)的DNS地址訪問(wèn)到部署在集群中的其它應(yīng)用,如下圖左;
- 其它的服務(wù)依賴了我:運(yùn)行在Kubernetes集群中的其它應(yīng)用可以在不做任何改變的情況下訪問(wèn)我到運(yùn)行的本地的代碼,如下圖右。
要實(shí)現(xiàn)剛才說(shuō)的兩種本地聯(lián)調(diào)方式,主要需要解決以下3個(gè)問(wèn)題:
- 本地網(wǎng)絡(luò)與Kubernetes集群網(wǎng)絡(luò)直接的連通問(wèn)題
- 在本地實(shí)現(xiàn)Kubernetes中內(nèi)部服務(wù)的DNS解析;
- 如果將對(duì)集群中其它Pod訪問(wèn)的流量轉(zhuǎn)移到本地;
云效開(kāi)發(fā)者工具KT
為了簡(jiǎn)化在Kubernetes下進(jìn)行聯(lián)調(diào)測(cè)試的復(fù)雜度,云效在SSH隧道網(wǎng)絡(luò)的基礎(chǔ)上并結(jié)合Kubernetes特性構(gòu)建了一款面向開(kāi)發(fā)者的免費(fèi)輔助工具KT(點(diǎn)擊前往下載),如下所示:
當(dāng)本地運(yùn)行的服務(wù)C’希望能夠直接訪問(wèn)集群中default命名空間下的Service A和Service B時(shí),運(yùn)行如下命令:
- $ ktctl -namespace=default
KT會(huì)自動(dòng)在集群中部署SSH/DNS代理容器,并構(gòu)建本地到Kubernetes集群的虛擬專(zhuān)用網(wǎng)絡(luò)并通過(guò)DNS代理實(shí)現(xiàn)集群服務(wù)DNS域名解析,在運(yùn)行KT之后,開(kāi)發(fā)者的本地程序可以直接像運(yùn)行在集群中的服務(wù)一樣通過(guò)service名字調(diào)用集群中部署的其它應(yīng)用:
而如果希望集群中的其它Pod(比如圖中的PodD和PodE)能夠通過(guò)ServiceC訪問(wèn)到本地運(yùn)行的程序C‘,通過(guò)如下命令,指定需要替換的目標(biāo)Deployment以及指定本地服務(wù)端口:
- #-swap-deployment指定需要替換的目標(biāo)Deployment
- # -expose 指定本地服務(wù)運(yùn)行的端口
- ktctl -swap-deployment c-deployment -expose=8080
KT在構(gòu)建虛擬專(zhuān)用網(wǎng)絡(luò)的同時(shí),還會(huì)自動(dòng)通過(guò)代理容器接管集群原有的PodC實(shí)例,并直接轉(zhuǎn)發(fā)的本地的8080端口。實(shí)現(xiàn)集群應(yīng)用聯(lián)調(diào)本地。
經(jīng)過(guò)上述兩個(gè)命令,開(kāi)發(fā)者就可以真正的使用云原生的方式來(lái)開(kāi)發(fā)調(diào)試Kubernetes中的應(yīng)用了。
工作原理
下面解析KT的工作原理,如果你已經(jīng)迫不及待的想嘗試KT的功能,可以直接前往下載KT工具。
KT主要由兩部分組成:
- 在本地運(yùn)行的命令行工具ktctl
- 運(yùn)行在集群中的SSH/DNS代理容器。
在工作原理上KT實(shí)際上是結(jié)合Kubernetes自身能力實(shí)現(xiàn)的一個(gè)基于SSH的網(wǎng)絡(luò)。這這部分,筆者將詳細(xì)介紹云效Kubernetes開(kāi)發(fā)者工具KT的工作原理:
打通SSH協(xié)議通道
在Kubernetes命令行工具kubectl中內(nèi)置的port-forward命令可以幫助用戶建立本地端口到Kubernetes集群中特定Pod實(shí)例端口間的網(wǎng)絡(luò)轉(zhuǎn)發(fā)。
當(dāng)我們?cè)诩褐胁渴鹨粋€(gè)包含sshd服務(wù)的容器后,通過(guò)port-forward可以將容器的SSH服務(wù)端口映射到本地:
- # 將對(duì)本地2222端口轉(zhuǎn)發(fā)到kt-porxy實(shí)例的22端口
- $ kubectl port-forward deployments/kt-proxy 2222:22
- Forwarding from 127.0.0.1:8080 -> 8080
- Forwarding from [::1]:8080 -> 8080
在運(yùn)行端口轉(zhuǎn)發(fā)后,就可以直接通過(guò)本地的2222端口通過(guò)SSH協(xié)議進(jìn)入到Kubernetes集群的kt-proxy實(shí)例中。從而打通本地與集群之間的SSH網(wǎng)絡(luò)鏈路。
本地動(dòng)態(tài)端口轉(zhuǎn)發(fā)
在打通SSH網(wǎng)絡(luò)之后,我們就可以利用SSH通道實(shí)現(xiàn)本地到集群的網(wǎng)絡(luò)請(qǐng)求,其中最基本的方式就是使用SSH動(dòng)態(tài)端口轉(zhuǎn)發(fā)的能力。
使用如下命令,通過(guò)本地2000運(yùn)行的代理,可以將網(wǎng)絡(luò)請(qǐng)求通過(guò)集群中運(yùn)行的kt-proxy容器進(jìn)行轉(zhuǎn)發(fā),從而實(shí)現(xiàn)本地到集群網(wǎng)絡(luò)請(qǐng)求的轉(zhuǎn)發(fā):
- # ssh -D [本地網(wǎng)卡地址:]本地端口 name@ip -p映射到kt-proxy的22端口的本地端口
- ssh -D 2000 root@127.0.0.1 -p2222
在啟用SSH動(dòng)態(tài)端口轉(zhuǎn)發(fā)后,通過(guò)設(shè)置http_proxy環(huán)境變量后,即可直接在命令行中訪問(wèn)集群網(wǎng)絡(luò):
- # export http_proxy=socks5://127.0.0.1:ssh動(dòng)態(tài)端口轉(zhuǎn)發(fā)的代理端口
- export http_proxy=socks5://127.0.0.1:2000
不過(guò)原生SSH動(dòng)態(tài)端口轉(zhuǎn)發(fā)也有一定的限制那就是無(wú)法直接使用UDP協(xié)議,這里我們選擇了一個(gè)替代方案sshuttle. 如下命令所示:
- # export http_proxy=socks5://127.0.0.1:ssh動(dòng)態(tài)端口轉(zhuǎn)發(fā)的代理端口
- export http_proxy=socks5://127.0.0.1:2000
- sshuttle --dns --to-ns 172.16.1.36 -e 'ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null' -r root@127.0.0.1:2222 172.16.1.0/16 172.19.1.0/16 -vv
sshuttle工具在SSH協(xié)議之上構(gòu)建了一個(gè)簡(jiǎn)易的虛擬專(zhuān)用網(wǎng)絡(luò),同時(shí)支持DNS協(xié)議轉(zhuǎn)發(fā)。
因此,接下來(lái)的問(wèn)題就是實(shí)現(xiàn)一個(gè)自定義的DNS服務(wù)即可,而該服務(wù)在KT中是直接內(nèi)置在KT代理鏡像中。
遠(yuǎn)程端口轉(zhuǎn)發(fā)
在本地到集群的鏈路打通之后。 接下來(lái)需要解決的就是從集群到本地的訪問(wèn)鏈路。這部分,我們會(huì)使用到SSH的遠(yuǎn)程端口轉(zhuǎn)發(fā)能力,如下所示,指定所有對(duì)kt-proxy的8080端口的網(wǎng)絡(luò)請(qǐng)求都會(huì)通過(guò)SSH隧道直接轉(zhuǎn)發(fā)到本地的8080端口:
- # ssh -R 8080:localhost:8080 root@127.0.0.1 -p2222
- ssh -R 8080:localhost:8080 root@127.0.0.1 -p2222
因此,在KT的實(shí)現(xiàn)過(guò)程之中,結(jié)合Kubernetes基于標(biāo)簽的松耦合能力,我們只需要克隆原有應(yīng)用實(shí)例的YAML描述,并將容器替換為kt-proxy即可。從而將對(duì)集群中原有應(yīng)用的請(qǐng)求通過(guò)SSH遠(yuǎn)程端口轉(zhuǎn)發(fā)到本地。
綜上,通過(guò)利用Kubernetes原生能力以及適度的擴(kuò)展,開(kāi)發(fā)者可以快速在本地利用KT打破本地網(wǎng)絡(luò)與Kubernetes網(wǎng)絡(luò)之間的界限,大大提升使用Kubernetes進(jìn)行聯(lián)調(diào)測(cè)試的效率。
小結(jié)
工具承載了對(duì)特定問(wèn)題的解決方案,而工程技術(shù)實(shí)踐則是對(duì)其價(jià)值的放大。阿里巴巴云效平臺(tái),致力于為開(kāi)發(fā)者提供一站式的企業(yè)研發(fā)與協(xié)作服務(wù),并將阿里多年的軟件工程實(shí)踐以一種更加開(kāi)發(fā)的形態(tài)反饋技術(shù)社區(qū),歡迎更多的技術(shù)開(kāi)發(fā)者入駐。