tcpip路由技术卷一_减少与开发的撕战,结合容器化技术轻松重构运维平台
荔枝微服務(wù)化進(jìn)程較早,目前已有上千個服務(wù)模塊,先前的運(yùn)維平臺漸漸無法滿足微服務(wù)架構(gòu)下運(yùn)維管理的需求,于是決定從2018年開始重構(gòu)運(yùn)維平臺,結(jié)合容器化技術(shù),讓開發(fā)人員盡可能無感知遷移的同時享受容器化帶來的諸多好處。
本次將主要為大家介紹我們項目發(fā)布系統(tǒng)重構(gòu)過程中,技術(shù)選型的考慮以及實(shí)踐過程中遇到的一些問題和解決方案。
一、背景
荔枝后端微服務(wù)化進(jìn)程較早,目前已有上千個服務(wù)模塊,絕大多數(shù)是Java。得益于良好的規(guī)范,舊的運(yùn)維平臺實(shí)現(xiàn)了一套簡單的自動化部署流程:
對接Jenkins進(jìn)行編譯打包和版本標(biāo)記
把指定版本的jar包,配置文件,啟動腳本一起發(fā)布到指定的機(jī)器上裸機(jī)運(yùn)行
通過對Java進(jìn)程的管理來完成重啟,關(guān)閉應(yīng)用等運(yùn)維操作
但是隨著開發(fā)人員,項目數(shù)量,請求量的增加,舊的運(yùn)維平臺逐漸暴露出以下一些問題:
Java實(shí)例部署所需資源沒有清晰的統(tǒng)計和系統(tǒng)層面的隔離,僅僅依賴于啟動腳本中的JVM參數(shù)來進(jìn)行內(nèi)存的約束,新增實(shí)例或新上項目時,往往需要運(yùn)維人員靠“感覺”指定部署的機(jī)器,沒有有效地分配機(jī)器資源,項目之間資源爭用會導(dǎo)致性能問題。
雖然大多數(shù)應(yīng)用依賴的環(huán)境只有JDK 7和JDK 8,但一些JDK的小版本差異,以及一些自研發(fā)Java agent的使用,使得簡單地指定JAVA_HOME目錄的方式很難有效地管理運(yùn)行環(huán)境。
開發(fā)人員的服務(wù)器權(quán)限需要回收。一個服務(wù)器上可能運(yùn)行多個不同部門的項目,相關(guān)開發(fā)人員誤操作可能會導(dǎo)致其他項目被影響。
上述問題雖然也可以通過一些技術(shù)和規(guī)范約束來解決,但天生就是為了解決環(huán)境依賴和資源管理的容器技術(shù)是當(dāng)下最合適的方案。
二、技術(shù)選型
核心組件方面,Docker和Kubernetes是當(dāng)下最成熟的開源容器技術(shù)。我們對強(qiáng)隔離沒有太多的需求,所以沒有使用KVM等虛擬機(jī)方案,直接在裸機(jī)上部署Kubernetes。
分布式存儲方面,容器化的項目大多是無狀態(tài)的云原生應(yīng)用,沒有分布式存儲的需求。極少數(shù)項目需要分布式存儲的場合,我們會把已有的MFS集群掛載到宿主機(jī),由宿主機(jī)掛載到容器里提供簡單的分布式存儲。
容器本地數(shù)據(jù)卷方面,使用Docker默認(rèn)的OverlayFS 2。
我們服務(wù)器操作系統(tǒng)主要是CentOS,DeviceMapper在生產(chǎn)環(huán)境必須使用direct-lvm模式,該模式需要獨(dú)立數(shù)據(jù)設(shè)備,對已有的SA自動化管理有一些影響。而OverlayFS 2在Linux內(nèi)核4.17以上已經(jīng)比較穩(wěn)定,也不需要太多復(fù)雜的配置,開箱即用。
日志收集方面,我們已有一套基于ELK的收集方案,對應(yīng)用日志也有一定約束(必須將日志打印到指定目錄下)。
傳統(tǒng)的基于控制臺輸出的Docker日志方案需要修改應(yīng)用的日志輸出配置,并且海量的控制臺日志輸出也會影響dockerd的性能,所以我們通過掛載日志數(shù)據(jù)盤的方式即可解決問題。
監(jiān)控方面,原有的監(jiān)控設(shè)施是Zabbix,但在Kubernetes監(jiān)控設(shè)施上Zabbix的方案顯然沒有親兒子Prometheus成熟和開箱即用。所以在Kubernetes的監(jiān)控方面,我們以Prometheus+Granfana為核心,使用kube-state-metrics采集Kubernetes運(yùn)行數(shù)據(jù)。
相比于Heapster,kube-state-metrics是Kubernetes生態(tài)的一部分,從Kubernetes的資源角度去采集數(shù)據(jù),維度更多,信息更全面。
最后是比較重要的Kubernetes網(wǎng)絡(luò)方面,我們使用了比較新的網(wǎng)絡(luò)方案kube-router。kube-router是基于三層Routing和BGP的路由方案,其優(yōu)點(diǎn)如下:
比Flannel等在數(shù)據(jù)包上再封裝一層通信協(xié)議(常見是VXLAN)的網(wǎng)絡(luò)實(shí)現(xiàn)性能上更優(yōu)秀。
比同樣是基于BGP和三層路由的Calico來說更輕量簡單,易于部署。
Macvlan技術(shù)會使宿主機(jī)網(wǎng)絡(luò)和Pod網(wǎng)絡(luò)隔離,不太符合我們的需求。
在開啟Service Proxy模式后可以取代默認(rèn)組件kube-proxy,Service Proxy的實(shí)現(xiàn)是IPVS,在性能上和負(fù)載均衡策略上靈活度更高(在Kubernetes 1.8后kube-proxy也有IPVS的實(shí)現(xiàn)支持,但到現(xiàn)在還是實(shí)驗性質(zhì))。
當(dāng)然kube-router也存在一些不足:
項目比較新,現(xiàn)在最新的還是v0.2.5,使用過程=踩坑。
節(jié)點(diǎn)間網(wǎng)絡(luò)必須二層可達(dá),不像Calico提供了IPIP的解決方案。
依賴于iptables,網(wǎng)絡(luò)要求高的場景Netfilter本身會成為瓶頸。
對于Pod IP的分配,Pod之間網(wǎng)絡(luò)的ACL實(shí)現(xiàn)較為簡單,無法應(yīng)付安全要求高的場景。
基于三層路由的CNI解決方案:
三、業(yè)務(wù)落地實(shí)踐
搭好Kubernetes只是一個開始,我們這次重構(gòu)有個很重要的目標(biāo)是盡可能讓業(yè)務(wù)開發(fā)方無感知無修改地把項目遷移到Kubernetes上,并且要保證實(shí)例部署和容器部署同時并行過度。
理想的項目應(yīng)該有Dockerfile聲明自己的運(yùn)行環(huán)境,有Jenkinsfile解決編譯打包,有對應(yīng)的Deployment和Service來告訴Kubernetes如何部署,但現(xiàn)實(shí)很骨干,我們有上千個項目,對應(yīng)上千個Jenkins編譯打包項目,逐一地修改顯然不太現(xiàn)實(shí)。
自動化運(yùn)維的前提是標(biāo)準(zhǔn)化,好在項目規(guī)范比較嚴(yán)謹(jǐn),符合了標(biāo)準(zhǔn)化這個充分條件。
重新設(shè)計后的部署流程如下圖所示:
構(gòu)建方面,項目統(tǒng)一使用同一個Dockerfile模板,通過變更基礎(chǔ)鏡像來解決一些不同環(huán)境項目(比如需要使用JDK 7)的問題。
基于Kubernetes Job和dind技術(shù),我們開發(fā)了一個構(gòu)建worker來實(shí)現(xiàn)從Jenkins拉取編譯后的應(yīng)用包并打包成鏡像的流程,這樣Jenkins打出來的應(yīng)用可以同時用在實(shí)例部署和容器部署上。
在運(yùn)維后臺上即可完成版本的構(gòu)建:
部署方面,項目的部署配置分成兩方面。
資源配置一般不經(jīng)常修改,所以僅僅只是在運(yùn)維平臺上修改記錄。經(jīng)常變更的版本變更和實(shí)例數(shù)變更則與部署操作綁定。
將Kubernetes復(fù)雜的對象封裝成擴(kuò)展成原有項目對象的資源配置參數(shù),執(zhí)行部署時,根據(jù)項目資源配置,版本和實(shí)例數(shù)生成對應(yīng)的Deployment和Service,調(diào)用Kubernetes API部署到指定的Kubernetes集群上。
如果項目有在運(yùn)維平臺上使用靜態(tài)配置文件,則使用ConfigMap存儲并掛載到應(yīng)用Pod里。
在運(yùn)維平臺上提供Pod列表展示,預(yù)發(fā)環(huán)境debug應(yīng)用、灰度發(fā)布、狀態(tài)監(jiān)控和webshell,方便開發(fā)觀察應(yīng)用運(yùn)行情況,調(diào)試和日志查看,同時也避免開發(fā)SSH到生產(chǎn)環(huán)境服務(wù)器上,回收了服務(wù)器權(quán)限。
在應(yīng)用從實(shí)例部署遷移到容器部署的過程中主要遇到以下幾個問題:
1、Kubernetes集群內(nèi)的Pod和集群外業(yè)務(wù)的通信問題。
為了風(fēng)險可控,實(shí)例部署和容器部署之間將會存在很長一段時間的并行階段,應(yīng)用方主要使用Dubbo做微服務(wù)治理,Kubernetes集群內(nèi)的Pod和集群外業(yè)務(wù)的通信就成為問題了。
kube-router是基于三層Routing實(shí)現(xiàn),所以通過上層路由器指定Pod IP段的靜態(tài)路由,或?qū)覤GP動態(tài)交換路由表來解決問題。
2、JVM堆內(nèi)存配置問題導(dǎo)致OOMKill的問題。
因為JVM的內(nèi)存不止有Xmx配置的堆內(nèi)存,還有Metaspace或PermSize,以及某些如Netty等框架還有堆外內(nèi)存,把Xmx的配置等同于容器內(nèi)存配置幾乎是一定會出現(xiàn)OOMKiil,所以必須放寬容器內(nèi)存限制。
以我們的經(jīng)驗來說,容器內(nèi)存比Xmx多20%左右一般可以解決問題,但也有部分例外,需要額外配置。
3、Pod啟動失敗難以排查的問題。
有一些Pod一啟動就失敗,輸出的日志難以分析問題。我們構(gòu)建和部署的描述文件都是運(yùn)維平臺動態(tài)生成的,很難使用傳統(tǒng)docker run目標(biāo)鏡像的方式進(jìn)行調(diào)試。
所以我們在運(yùn)維平臺上提供了debug容器的功能,新建一個和原有deployment一樣的debug部署,僅去掉健康檢查相關(guān)的參數(shù)和修改command參數(shù)使pod運(yùn)行起來,業(yè)務(wù)開發(fā)方即可通過webshell控制臺進(jìn)入Pod調(diào)試應(yīng)用。
四、未來
開發(fā)經(jīng)常需要使用的一些調(diào)試工具比如Vim、Arthas之類的,現(xiàn)在我們是打包到基礎(chǔ)鏡像中提供,但這樣不僅增加了鏡像的體積,而且需要重新打包新的鏡像。目前看到比較好的解決方案是起一個調(diào)試用的容器并加到指定Pod的namespace中,但還需二次開發(fā)集成到webshell中。
跨機(jī)房Kubernetes集群調(diào)度。當(dāng)現(xiàn)有資源無法滿足峰值需求時,借助公有云來擴(kuò)展系統(tǒng)是比較好的選擇,我們希望借助Kubernetes多集群調(diào)度功能做到快速擴(kuò)容到公有云上。
峰值流量的自動擴(kuò)容和縮容,Kubernetes提供的HPA策略較為簡單,我們希望能從更多的維度來計算擴(kuò)容和縮容的數(shù)量,做到精準(zhǔn)的控制。
Q1:容器的Pod網(wǎng)絡(luò)和外部網(wǎng)絡(luò)全部打通嗎,如何實(shí)現(xiàn)的?
A1:因為kube-router是基于三層路由,所以只要在頂層交換上指定Pod IP的靜態(tài)路由即可,比如宿主機(jī)是192.168.0.1,該宿主機(jī)上的pod ip range是10.0.0.1/24,那只要在交換機(jī)或需要訪問Pod的外部主機(jī)上添加路由10.0.0.1/24 via 192.168.0.1 ...即可。
Q2:你們?nèi)绾稳ケWCio的隔離?
A2:目前網(wǎng)絡(luò)和硬盤的io沒有做隔離,暫時還沒有這方面的剛需。kube-router對網(wǎng)絡(luò)IO這方面控制比較弱。硬盤IO方面Docker支持IOPS控制,但Kubernetes我還不太清楚是否支持。
Q3:Job和dind如何配合去實(shí)現(xiàn)打包鏡像的呢?
A3:首先是dind技術(shù),通過掛載宿主機(jī)的docker client和docker sock,可以實(shí)現(xiàn)在容器內(nèi)調(diào)用宿主機(jī)的Docker來做一些事情,這里我們主要就用于build。Kubernetes的Job則是用于執(zhí)行這個構(gòu)建worker的方式,利用Kubernetes的Job來調(diào)度構(gòu)建任務(wù),充分利用測試集群的空閑資源。
Q4:你們Kubernetes里面 統(tǒng)一配置是用的ConfigMap還是集成了第三方工具,例如Disconf。你們在Kubernetes中,APM用的是什么呢?Pinpoint還是Sky還是Jeager?還是其他?
A4:過去的項目配置文件是放運(yùn)維平臺上的,所以只要ConfigMap掛進(jìn)去就可以了。后來新的項目開始采用攜程的Apollo,Kubernetes上就只要通過ENV把Apollo的一些相關(guān)敏感信息傳給Pod即可。APM方面因為我們是Java棧所以使用的skywalking,也是開篇提到的Java agent技術(shù)。
Q5:Macvlan和IPvlan性能非常好,幾乎沒有損耗,但默認(rèn)都是容器和宿主機(jī)網(wǎng)絡(luò)隔離的,但是也有解決方案,你們這邊是沒有考慮還是使用了一些解決方案發(fā)現(xiàn)有問題又放棄的?如果是后者,有什么問題讓你們選擇放棄?
A5:Macvlan之類的方式需要交換機(jī)層面上做一些配置打通VLAN,并且性能上并不會比基于三層的解決方案要高非常多,權(quán)衡之下我們還是選擇比較易用的基于三層的方案,甚至為了易用而選擇了更為激進(jìn)的kube-router。
Q6:容器的多行日志收集如何解決?或者是,很多業(yè)務(wù)日志需要上下文關(guān)系,但是ELK只能查詢到單條,這種情況怎么處理呢?
A6:容器多行日志的問題只存在于標(biāo)準(zhǔn)輸出里,我們應(yīng)用的日志是輸出到指定目錄下的,Filebeat有一些通用的多行日志解決方案。因為日志是存放在ES里的,所以可以通過調(diào)ES接口拿到某個Pod一個時間段里的日志,在UI上把它展示出來即可。
Q7:請問用的存儲是什么?如何集成的?存儲架構(gòu)是怎樣的?有考慮過Ceph嗎?
A7:只有極少部分項目需要接分布式存儲,并且對存儲的管理,IOPS限制等沒有硬性要求,所以我們把已有的MFS集群掛載到宿主機(jī),再掛到容器里來實(shí)現(xiàn)。
Q8:Jenkins的Slave是用Pod Template創(chuàng)建的嗎?Slave是Job共享還是需要時自動創(chuàng)建?
A8:Jenkins還是傳統(tǒng)的master-slave單機(jī)部署模式,因為版本比較舊連Kubernetes Slave都不支持,所以我們只是調(diào)用了Jenkins的API來完成這個部署的過程。
Q9:請問鏡像大小是否有做優(yōu)化?生產(chǎn)中有用alpine之類的base鏡像嗎?
A9:暫時沒有,我們鏡像的大小大約在100-300M之間。而且比起鏡像大小的優(yōu)化,運(yùn)行環(huán)境的穩(wěn)定和調(diào)試的便利更為重要。鏡像有分層的策略,即使是很大的鏡像,只要每次版本部署時更新的是最底層的鏡像就不會導(dǎo)致每次都要拉取完整鏡像。
作者:陳偲軼,荔枝研發(fā)中心DevOps工程師
來源:Docker訂閱號(ID:dockerone)
dbaplus社群歡迎廣大技術(shù)人員投稿,投稿郵箱:editor@dbaplus.cn
想了解更多運(yùn)維實(shí)操演練
靈活解決項目實(shí)施疑難?
不妨來DAMS學(xué)點(diǎn)獨(dú)家技能
↓↓掃碼可了解更多詳情及報名↓↓
2019 DAMS中國數(shù)據(jù)智能管理峰會-上海站
總結(jié)
以上是生活随笔為你收集整理的tcpip路由技术卷一_减少与开发的撕战,结合容器化技术轻松重构运维平台的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sqoop数据倾斜_北京卓越讯通大数据岗
- 下一篇: zenmap nmap输出无显示_液晶显