以Docker為代表的容器技術(shù)已經(jīng)持續(xù)成為話題好幾年了,本以為在沒(méi)有歷史包袱的創(chuàng)業(yè)公司中,Docker應(yīng)該會(huì)成為生產(chǎn)環(huán)境上部署和管理服務(wù)的標(biāo)準(zhǔn)配置,然而近發(fā)現(xiàn)一些友商在得知我們?cè)谏a(chǎn)上使用Docker和Kubernetes之后,居然表現(xiàn)出了一些驚訝。我想對(duì)于這些團(tuán)隊(duì)沒(méi)有采納Docker而是繼續(xù)使用傳統(tǒng)運(yùn)維方案,還是覺(jué)得即使多做一些繁瑣的運(yùn)維工作,也希望對(duì)系統(tǒng)有更多的掌控度。
Docker所依賴的LXC容器技術(shù),早在十多年前就被Google這類大廠使用了,國(guó)內(nèi)的一些大廠也在很早開始投入研發(fā)和使用了,對(duì)他們來(lái)說(shuō),使用容器能夠充分利用計(jì)算資源,節(jié)省硬件開銷。然而對(duì)于小公司來(lái)說(shuō),把10臺(tái)服務(wù)器壓縮到5臺(tái)服務(wù)器并不能幫助公司活下去。
容器技術(shù)真正開始廣泛產(chǎn)生影響是從Docker的誕生開始,Docker剛出來(lái)的時(shí)候,官網(wǎng)上的slogan:“Build Ship Run”,準(zhǔn)確的闡述了Docker的定位,從打包到部署,傳統(tǒng)運(yùn)維的這一套流程,由于語(yǔ)言,環(huán)境,平臺(tái)的不同在各個(gè)公司千差萬(wàn)別,幾乎每個(gè)公司都會(huì)開發(fā)一套自己的發(fā)布系統(tǒng)。有了Docker之后,這些居然都可以標(biāo)準(zhǔn)化了,并且相對(duì)于笨重的虛擬機(jī),Docker幾乎就是一個(gè)進(jìn)程簡(jiǎn)單的包裝,只有很少的額外開銷,啟動(dòng)速度也幾乎相當(dāng)于直接啟動(dòng)應(yīng)用進(jìn)程。
對(duì)于沒(méi)有專職運(yùn)維的即刻團(tuán)隊(duì),很自然的從項(xiàng)目開始就使用Docker來(lái)做服務(wù)的發(fā)布工具了:
由于一個(gè)Docker容器只是一個(gè)(或一組)進(jìn)程的封裝,一個(gè)容器想要向宿主機(jī)之外的網(wǎng)絡(luò)提供服務(wù),就只能綁定宿主機(jī)的端口了,端口的管理也是一件大部分情況下都不希望人去操心的麻煩事,為了避免端口沖突,對(duì)于需要暴露端口的容器,Docker會(huì)隨機(jī)綁定一個(gè)宿主機(jī)端口,這個(gè)時(shí)候我們就需要服務(wù)發(fā)現(xiàn)機(jī)制來(lái)幫助不同機(jī)器上的服務(wù)來(lái)進(jìn)行通信了。
我們使用了一個(gè)簡(jiǎn)單的方案,一套開源的工具:docker-discover和docker-register,它包含兩個(gè)組件:
1.每臺(tái)worker node虛擬機(jī)上運(yùn)行一個(gè)docker-register容器,用來(lái)掃描本地容器,把他們的服務(wù)名(用鏡像名作為服務(wù)名)和端口(包括容器內(nèi)端口和宿主機(jī)端口)注冊(cè)到etcd上。
2.一個(gè)docker-discover容器用來(lái)做中心代理,它內(nèi)部包含了一個(gè)HAProxy,每隔幾秒鐘掃描Etcd上的注冊(cè)服務(wù),并生成配置文件,刷新HAProxy,生成backend配置的模版如下
{% for service in services %} listen {{ service }} bind *:{{services[service].port}} {% for backend in services[service].backends %} server {{ backend.name }} {{ backend.addr }} check inter 2s rise 3 fall 2{% endfor %} {% endfor %}
這個(gè)方案給我們提供了一套系統(tǒng)的幾個(gè)基本功能:應(yīng)用發(fā)布,服務(wù)發(fā)現(xiàn),負(fù)載均衡,進(jìn)程守護(hù),其中應(yīng)用發(fā)布是執(zhí)行腳本去各個(gè)worker node上拉取新鏡像,進(jìn)程守護(hù)則是由Docker daemon的restarts=always來(lái)提供。
除了提供一致的運(yùn)行環(huán)境使服務(wù)的發(fā)布和回滾比較可控,這套簡(jiǎn)單的系統(tǒng)在發(fā)布流程上還是像傳統(tǒng)運(yùn)維一樣需要遠(yuǎn)程執(zhí)行腳本,功能比較簡(jiǎn)單,隨著我們后端系統(tǒng)成長(zhǎng)起來(lái),很快就不夠用了。
Docker本身只是提供了一個(gè)運(yùn)行環(huán)境,除了把服務(wù)跑起來(lái)之外,要讓多個(gè)服務(wù)容器協(xié)同起來(lái)工作,我們還需要一個(gè)容器編排(Orchestration)系統(tǒng),一般來(lái)說(shuō)我們期望編排系統(tǒng)能幫我們實(shí)現(xiàn)幾個(gè)目的:
基本發(fā)布自動(dòng)化功能:
編排過(guò)程包含分配機(jī)器,拉取鏡像,啟動(dòng)/停止/更新容器,存活監(jiān)控,容器數(shù)量擴(kuò)展和收縮
聲明式定義服務(wù)棧:
提供一種機(jī)制,可以用配置文件來(lái)聲明服務(wù)的網(wǎng)絡(luò)端口,鏡像及版本,在需要的時(shí)候通過(guò)配置可再現(xiàn)的創(chuàng)建出一整套服務(wù)。
服務(wù)發(fā)現(xiàn):
提供DNS和負(fù)載均衡,一個(gè)容器啟動(dòng)之后,需要其他服務(wù)能夠訪問(wèn)到它,一個(gè)容器終止運(yùn)行之后,需要保證流量不會(huì)再導(dǎo)向它。
狀態(tài)檢查:
需要持續(xù)監(jiān)控系統(tǒng)是否符合配置中聲明的狀態(tài),比如一臺(tái)宿主機(jī)掛了,需要把上面運(yùn)行的容器在其他健康的節(jié)點(diǎn)上啟動(dòng)起來(lái),如果一個(gè)容器掛了,需要把它重新啟動(dòng)。
從設(shè)計(jì)思路,社區(qū)活躍度等因素來(lái)看,Kubernetes無(wú)疑是編排工具好的選擇,但由于組件較多,學(xué)習(xí)成本并不低,還有墻的因素,在國(guó)內(nèi)甚至安裝都不是件容易的事。
這個(gè)時(shí)候我們發(fā)現(xiàn)Rancher正式發(fā)布了,雖然沒(méi)有kubernetes那么熱門,但它提供了所有我們需要的功能,還有一個(gè)簡(jiǎn)單容易上手的Web UI。在早期我們的機(jī)器和服務(wù)數(shù)量都比較少,又急需一個(gè)編排工具好把有限精力都投入到開發(fā)上,所以迅速的把服務(wù)都遷移到Rancher上了。
準(zhǔn)確的說(shuō),Rancher是一套容器管理打包方案,支持三種編排引擎:Kubernetes,Swarm,還有Rancher自己開發(fā)的Cattle(近好像換成了Mesos)。從功能的完整性和易用性來(lái)看,Rancher甚至可以算得上一個(gè)商業(yè)軟件了,部署極其簡(jiǎn)單,這也是我們選擇它作為入門級(jí)容器管理平臺(tái)的原因。
Rancher組件圖,中小企業(yè)常用的軟件功能都能找到:
后來(lái)圍繞Rancher,也使用了一些Catalog里提供的服務(wù)棧,我們逐步搭建起來(lái)了一套完整的容器運(yùn)維系統(tǒng),包含了日志收集,性能監(jiān)控,配合AWS的Auto Scaling Group,應(yīng)用擴(kuò)展也是很方便的事情。
雖然Rancher非常的易用,但隨著我們后端機(jī)器和項(xiàng)目數(shù)量的增加,它的一些問(wèn)題也暴露出來(lái)了,UI卡頓,發(fā)布速度越來(lái)越慢,1.3之后甚至經(jīng)常出現(xiàn)服務(wù)的預(yù)期狀態(tài)(容器數(shù)量,版本)無(wú)法被保證,卡在發(fā)布中或者完成中狀態(tài),真正讓我們下定決心要遷移的是一次重大故障,疑似網(wǎng)絡(luò)雪崩引起,集群所有機(jī)器都在重復(fù)斷開連接,本來(lái)按一般編排系統(tǒng)的設(shè)計(jì),worker node上的容器之間通過(guò)overlay網(wǎng)絡(luò)通信,node和Rancher server的連接即使斷開也不會(huì)影響已經(jīng)啟動(dòng)的容器運(yùn)行。但在1.3之后的Rancher中,不知是有意設(shè)計(jì)還是bug,worker node重新連接上Rancher server之后,節(jié)點(diǎn)上所有的容器會(huì)被重新schedule,這就導(dǎo)致集群中所有容器都不斷的被銷毀又重新創(chuàng)建。
在Rancher上碰到大大小小的問(wèn)題,我們發(fā)現(xiàn)大部分都很難找到社區(qū)提供的解決方案,我們很可能是不幸比較早踩坑的人,雖然Rancher是開源的,但技術(shù)上的文檔相比使用文檔明顯欠缺很多,想通過(guò)了解他的實(shí)現(xiàn)來(lái)排查問(wèn)題比較困難,也很少有Rancher公司之外的contributor,這點(diǎn)是和Kubernetes很明顯不同的。
和Rancher提供了一整套解決方案不一樣,Kubernetes提供的是一個(gè)框架,對(duì)于Rancher,即使不熟悉其中各個(gè)組件,也可以直接用預(yù)設(shè)的配置安裝,拿來(lái)當(dāng)一個(gè)發(fā)布工具使用,Kubernetes則要求使用者對(duì)他的組件有一定程度了解,社區(qū)提供了很多幫助部署的installer,但使用前都需要不少配置工作。
DevOps同事畫的Kubernetes架構(gòu)圖:
在Rancher上積累了一些容器編排的經(jīng)驗(yàn)之后,我們對(duì)使用Kubernetes做編排也有了一些信心,于是開始遷移到性能更好,社區(qū)更活躍的kubernetes上。
我們將線上服務(wù)一點(diǎn)點(diǎn)從Rancher上把流量切換到Kubernetes集群,起初發(fā)現(xiàn)流量稍微增漲便丟包嚴(yán)重,定位到問(wèn)題是DNS解析緩慢,觀察kernel log發(fā)現(xiàn)宿主機(jī)conntrack count到達(dá)上限,出現(xiàn)丟包。
這里解釋一下iptable里的conntrack:我們?cè)谑褂胕ptable做面向連接的防火墻時(shí),要允許與一個(gè)ip地址建立特定連接,除了讓該連接下的包能進(jìn)來(lái),還要讓回復(fù)的包能出去,由于ip是個(gè)無(wú)狀態(tài)協(xié)議,這個(gè)時(shí)候就需要一個(gè)session表來(lái)記錄有狀態(tài)的連接,conntrack就是用來(lái)記錄這些session的。在微服務(wù)下,服務(wù)間調(diào)用頻繁,會(huì)產(chǎn)生大量DNS查詢,linux默認(rèn)的conntrack_max很容易突破限制,所以在部署有DNS service的機(jī)器上設(shè)置一個(gè)較高的conntrack_max值基本上是必須的。
前面介紹了我們使用容器來(lái)做服務(wù)編排,除了這些,相對(duì)于傳統(tǒng)架構(gòu),使用容器我們還獲得了一整套日志和監(jiān)控的解決方案,比如日志采集,部署在容器中的日志可以直接打印到標(biāo)準(zhǔn)輸出中,Docker本身支持多種logging driver,可以將日志直接發(fā)到Graylog,AWS CloudWatch等日志平臺(tái),也可以讓Fluentd等日志采集工具來(lái)采集Docker默認(rèn)輸出的json-file,相比之下傳統(tǒng)架構(gòu)可能需要在應(yīng)用中使用專門配置的logger輸出到收集系統(tǒng),或者配置專門的采集器去采集不同的日志文件。
小公司對(duì)基礎(chǔ)設(shè)施的投入不足,一般沒(méi)有專人去熟悉Kubernetes這種大型開源項(xiàng)目,但即刻算是一個(gè)對(duì)技術(shù)持開放態(tài)度,愿意讓工程師去踩坑、嘗試的公司。相對(duì)于采用傳統(tǒng)架構(gòu),因?yàn)槿萜骶幣畔到y(tǒng)都是以提高本身的復(fù)雜性來(lái)覆蓋繁瑣的配置和腳本編寫工作,本身復(fù)雜了就會(huì)導(dǎo)致出現(xiàn)問(wèn)題的時(shí)候會(huì)比較難排查。但做過(guò)運(yùn)維工作的應(yīng)該了解,一般自己編寫的腳本很難具有通用性,很可能環(huán)境稍有改變就不能使用了,運(yùn)維是比較枯燥的工作,有了編排系統(tǒng)幫助處理這些,我們可以把更多的精力放到更有意義的工作上。
本站文章版權(quán)歸原作者及原出處所有 。內(nèi)容為作者個(gè)人觀點(diǎn), 并不代表本站贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé),本站只提供參考并不構(gòu)成任何投資及應(yīng)用建議。本站是一個(gè)個(gè)人學(xué)習(xí)交流的平臺(tái),網(wǎng)站上部分文章為轉(zhuǎn)載,并不用于任何商業(yè)目的,我們已經(jīng)盡可能的對(duì)作者和來(lái)源進(jìn)行了通告,但是能力有限或疏忽,造成漏登,請(qǐng)及時(shí)聯(lián)系我們,我們將根據(jù)著作權(quán)人的要求,立即更正或者刪除有關(guān)內(nèi)容。本站擁有對(duì)此聲明的最終解釋權(quán)。