傳統(tǒng)應(yīng)用容器化遷移的思考
對于傳統(tǒng)應(yīng)用來說,使用和不使用Docker可能并不能直接給企業(yè)帶來好處,相反使用中遇到了問題肯定會(huì)給企業(yè)帶來麻煩。那我們?yōu)槭裁匆褂肈ocker呢?Docker最大的好處是標(biāo)準(zhǔn)化應(yīng)用交付,當(dāng)然隨之提高了工作效率,并節(jié)約了成本,據(jù)國外的統(tǒng)計(jì)使用Docker平均可以提升60%的效率,同時(shí)節(jié)約40%的成本。我們可以把Docker比作一條軟件的生產(chǎn)線,當(dāng)你有了這條生產(chǎn)線后,帶來的效率提升是質(zhì)的飛躍。不過,當(dāng)你在引進(jìn)Docker這條生產(chǎn)線的時(shí)候,你肯定會(huì)有很多的疑慮,比如:
如何能保證現(xiàn)有生產(chǎn)線到Docker的平滑過渡?
如何確保員工能夠快速的上手?
如何合理利用現(xiàn)有的資源,比如數(shù)據(jù)庫、網(wǎng)絡(luò)等?
如何使用新的服務(wù)框架?
如何重新定義軟件層的依賴?
如何處理操作系統(tǒng)的問題?
如何重新定義軟件的生命周期?
傳統(tǒng)應(yīng)用的容器化遷移建議
當(dāng)我們需要遷移一個(gè)應(yīng)用的時(shí)候,首先需要了解一個(gè)應(yīng)用當(dāng)前正在使用的資源有哪些。你需要了解當(dāng)前系統(tǒng)的拓?fù)浣Y(jié)構(gòu),現(xiàn)有的拓?fù)浣Y(jié)構(gòu)是遷移的最好參考,傳統(tǒng)的單體模式下,很多應(yīng)用程序運(yùn)行在一臺(tái)主機(jī)之上,但在微服務(wù)體系下,我們更傾向于通過容器來解耦合,實(shí)際上,并不是所有系統(tǒng)都適合于解耦合,我們的進(jìn)程間通訊是必須要考慮的因素,任何一個(gè)企業(yè)在遷移過程中都不愿意去重新對一個(gè)模塊進(jìn)行重編碼,因?yàn)橛械某绦蚩赡芨揪驼也坏酱a。本文結(jié)合我們的實(shí)際經(jīng)驗(yàn)闡述傳統(tǒng)應(yīng)用在容器化遷移中需要考慮的一些因素。
操作系統(tǒng)
如果你的應(yīng)用是基于Windows系統(tǒng),并且不打算使用Linux,可以直接忽略本文(很多應(yīng)用是可以遷移到Linux的,比如Java、PHP、Python等)。對于進(jìn)程來說,它是只工作在Ring 3還是工作在Ring 0-3是至關(guān)重要的,如果你進(jìn)程涉及到內(nèi)核的操作,需要非常的小心,因?yàn)樗赡軙?huì)引起系統(tǒng)崩潰。我們知道通常system call是會(huì)從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài),所以基本都會(huì)涉及到內(nèi)核操作。我所說的內(nèi)核操作是指你自己寫了相應(yīng)的驅(qū)動(dòng)或者內(nèi)核模塊,因?yàn)槟愕膋ernel代碼肯定是更容易出問題的。因此,我們需要了解容器并不是虛擬機(jī),它本身是一個(gè)進(jìn)程,一個(gè)受到諸多管控的進(jìn)程。即使你的容器里面的內(nèi)核版本很高,但骨子里都是你的Host內(nèi)核。因此,容器的隔離并不會(huì)像虛擬機(jī)一樣徹底,對于一個(gè)虛擬機(jī),即使你的內(nèi)核操作引起的崩潰,也不會(huì)導(dǎo)致其他虛擬機(jī)崩潰,但是,容器則會(huì)和大家一起崩潰。所以,我們應(yīng)當(dāng)盡量通過容器來隔離不涉及內(nèi)核操作的應(yīng)用。如果您不清楚是否涉及內(nèi)核,也不用擔(dān)心,目前基本上95%以上的Linux應(yīng)用都不直接涉及內(nèi)核操作。我們一般的web服務(wù)器,后端服務(wù),基本都不涉及內(nèi)核操作。
CPU
對于單個(gè)應(yīng)用程序,首先需要考慮的是CPU問題,需要幾個(gè)CPU,需要多強(qiáng)的CPU。如果是CPU消耗性的程序,要在不影響其他應(yīng)用情況下,盡可能多的分配CPU。CPU一般是稀缺資源,需要結(jié)合實(shí)際使用的上限值、下限值和均值做規(guī)劃。最好的方法就是利用ps、top、htop等工具進(jìn)行跟蹤,最好能跟蹤一個(gè)軟件運(yùn)行周期,得到軟件的CPU上限和下限。CPU的跟蹤結(jié)果會(huì)左右后續(xù)的容器資源限定值。
內(nèi)存的大小
使用容器的一大目的就是要限定應(yīng)用的資源使用,因此我們需要獲得容器的初始內(nèi)存大小,運(yùn)行中內(nèi)存大小以及最大內(nèi)存。這一部分可以通過vmstat等工具來獲得。需要指出的是,內(nèi)存和CPU都是利用CGroup內(nèi)核技術(shù)進(jìn)行控制的,所以控制的是使用上限,并不是分配以后就專屬于某個(gè)容器。只不過如果你的應(yīng)用使用內(nèi)存超過了上限,程序會(huì)觸發(fā)OOM(out of memory),可能會(huì)被Kill掉,例如你是通過tomcat來封裝應(yīng)用的,由于啟動(dòng)時(shí)候需要使用更多的內(nèi)存,可能會(huì)存在被Kill的可能性。這些都可以通過docker log和系統(tǒng)日志來進(jìn)行查看。
進(jìn)程模型
隨著高級語言的出現(xiàn),熟悉操作系統(tǒng)進(jìn)程模型的人越來越少。父進(jìn)程是什么,子進(jìn)程是什么,進(jìn)程樹是怎么樣的,線程是怎么構(gòu)建的都需要弄清楚。這有助于理解應(yīng)用在一臺(tái)服務(wù)器中所處的位置,以及它能帶來的影響。這一部分是通過ps命令來查看的。
網(wǎng)絡(luò)部分
應(yīng)用使用的是TCP還是UDP,使用了哪些端口,同時(shí)數(shù)據(jù)包的大小是怎么樣的,網(wǎng)絡(luò)的上下行負(fù)載在什么程度。這些可以通過tcpdump、 sar和netstat來獲得,有了這些才能設(shè)計(jì)出容器將要使用的網(wǎng)絡(luò)模型,是橋接、Host、Overlay、自定義還是網(wǎng)絡(luò)插件,每一種容器網(wǎng)絡(luò)都有一定的特點(diǎn),性能和復(fù)雜度也各不相同,我們需要選擇最合適的模型來進(jìn)行規(guī)劃,而不是選擇最復(fù)雜的。
用戶管理及安全
傳統(tǒng)應(yīng)用系統(tǒng)里面可能有自己的一套安全體系,比如ldap、 active directory等,因此這一部分也是需要考慮的,而安全這部分,也需要考慮證書、防火墻等問題。容器可以有效的提升用戶管理的效率,我們可以把ldap做到容器里面,同時(shí)也可以只暴露需要的端口,降低被攻擊的可能性。
日志處理
傳統(tǒng)的應(yīng)用有的可能沒有日志管理,有的可能使用syslog或者rsyslog,然后通過中心日志服務(wù)器來進(jìn)行日志匯總。有了容器以后,我們可以借助諸如Ghostcloud的第三方平臺(tái),集中化收集日志?梢栽赿aemon層面,也可以在容器層面來進(jìn)行收集。有了容器之后,你可以很方便的收集全系統(tǒng)日志,如果你有一個(gè)基于日志的大數(shù)據(jù)平臺(tái),可以在改動(dòng)很小的情況下做分析。
共享存儲(chǔ)及數(shù)據(jù)庫
很多傳統(tǒng)應(yīng)用都會(huì)使用跨主機(jī)的文件服務(wù),比如NFS、CIFS。當(dāng)遷移含有這些服務(wù)的應(yīng)用時(shí),需要添加外部掛在卷。對于MySQL或者M(jìn)ongo等數(shù)據(jù)庫,在遷移的時(shí)候需要考慮是否將數(shù)據(jù)持久化進(jìn)容器,還是通過外部的掛在卷。如果通過外部掛在卷,需要考慮容器的HA。同時(shí),如果你的數(shù)據(jù)庫沒有辦法提供Linux平臺(tái)的支持,你的數(shù)據(jù)庫肯定是不能做遷移的,當(dāng)然如果數(shù)據(jù)庫提供Linux下的客戶端,你可以將數(shù)據(jù)庫和應(yīng)用做一次拆分,再做遷移。對于存儲(chǔ)和磁盤的跟蹤也是必須注意的,Host的RAID怎么做,是否需要支持動(dòng)態(tài)擴(kuò)展,應(yīng)用程序的運(yùn)行目錄大小及層次結(jié)構(gòu),應(yīng)用程序的運(yùn)行時(shí)磁盤操作,應(yīng)用程序的持久化操作以及應(yīng)用的日志及Crash Core都是需要考慮的地方。這一部分,需要一些專業(yè)的知識,同時(shí)借助于strace等跟蹤工具來進(jìn)行分析,這些將決定后續(xù)容器的掛載卷及空間分配,同時(shí)也會(huì)決定容器文件系統(tǒng)設(shè)計(jì)方案。
服務(wù)發(fā)現(xiàn)
傳統(tǒng)企業(yè)或者應(yīng)用可能會(huì)用到諸如ESB的服務(wù)總線,但是隨著開源技術(shù)的出現(xiàn)和微服務(wù)架構(gòu)的興起,我們完全可以借助于開源項(xiàng)目或者第三方服務(wù)來實(shí)現(xiàn),用的比較多的是consul、etcd 和Zookeeper,其中ZK也是使用非常多的高可用中間件,只不過前兩者更專注于服務(wù)發(fā)現(xiàn),后者是一個(gè)通用的組件,并不僅針對服務(wù)發(fā)現(xiàn)。以前企業(yè)里面涉及到服務(wù)發(fā)現(xiàn),很多時(shí)候都需要對微服務(wù)的方式進(jìn)行統(tǒng)一約定,而由于容器本身有一個(gè)外部的daemon引擎,其服務(wù)發(fā)現(xiàn)方式可以通過Registrator內(nèi)置到daemon里面,跟傳統(tǒng)模式也有區(qū)別。
持續(xù)集成
很多傳統(tǒng)應(yīng)用出現(xiàn)的時(shí)候還沒有敏捷、DevOps和CI/CD,但是隨著移動(dòng)互聯(lián)網(wǎng)的高速發(fā)展,軟件的更新越來越頻繁,很多時(shí)候一個(gè)系統(tǒng)需要在一天內(nèi)部署幾十次。通過不斷重復(fù)的部署和測試,可以極大的提高軟件的穩(wěn)定性。Docker的快速啟動(dòng)和鏡像倉庫是天生為CI/CD設(shè)計(jì)的,以前我們啟動(dòng)一個(gè)虛擬機(jī)需要幾分鐘,而啟動(dòng)容器只需要幾秒鐘,有了這種能力以后集群式的和并行的持續(xù)集成才能成為可能。對于持續(xù)集成目前業(yè)界也沒有一個(gè)通用的模式,而且每個(gè)團(tuán)隊(duì)可能習(xí)慣的方式和關(guān)注點(diǎn)都不一樣,因此存在很多定制的地方,有的以鏡像為引導(dǎo),有的以代碼為引導(dǎo),沒有最好的方式,只有最適合團(tuán)隊(duì)的方式;同時(shí),持續(xù)集成的流程也沒有最好的,只有更好的。需要不斷在開發(fā)過程中進(jìn)行優(yōu)化。以前國內(nèi)很多企業(yè)受一些國外廠商的影響,花了巨資去購買流程及其復(fù)雜的流程軟件,其實(shí)現(xiàn)在看來并不都適合國內(nèi)的開發(fā)環(huán)境。一個(gè)簡單的例子就是,由于眾所周知的原因,國內(nèi)訪問外網(wǎng)的速度就很慢,而現(xiàn)在很多開源項(xiàng)目都放在github上,國外很多看似理所當(dāng)然的事情,并不適合國內(nèi)環(huán)境。
..
|