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