蘑菇街基于Docker的私有云實踐

jopen 9年前發布 | 35K 次閱讀 Docker
 

【編者的話】本次主要想分享一下過去一年時間里,我們在建設基于Docker的私有云實踐過程中,曾經遇到過的問題,如何解決的經驗,還有我們的體會和思考,與大家共勉。

內容

很高興今天能在這里分享一下蘑菇街在生產環境中使用Docker的一些經歷和經驗。蘑菇街的私有云項目是2014年圣誕節期間上線的,從無到有,經過了半年多的發展,經歷了3次大促,已經逐漸形成了一定的規模。

架構

集群管理

大家知道,Docker自身的集群管理能力在當時條件下還很不成熟,因此我們沒有選擇剛出現的Swarm,而是用了業界最成熟的 OpenStack,這樣能同時管理Docker和KVM。我們把Docker當成虛擬機來跑,是為了能滿足業務上對虛擬化的需求。今后的思路是微服務化,把應用進行拆分,變成一個個微服務,實現PaaS基于應用的部署和發布。

通過OpenStack如何管理Docker?我們采用的是OpenStack+novadocker+Docker的架構模式。 novadocker是StackForge上一個開源項目,它做為nova的一個插件,通過調用Docker的RESTful接口來控制容器的啟停等動作。

我們在IaaS基礎上自研了編排調度等組件,支持應用的彈性伸縮、灰度升級等功能,并支持一定的調度策略,從而實現了PaaS層的主要功能。

同時,基于Docker和Jenkins實現了持續集成(CI)。Git中的項目如果發生了git push等動作,便會觸發Jenkins Job進行自動構建,如果構建成功便會生成Docker Image并push到鏡像倉庫。基于CI生成的Docker Image,可以通過PaaS的API或界面,進行開發測試環境的實例更新,并最終進行生產環境的實例更新,從而實現持續集成和持續交付。

網絡和存儲

網絡方面,我們沒有采用docker默認提供的NAT網絡模式,NAT會造成一定的性能損失。通過OpenStack,我們支持Linux bridge和openvswitch,不需要啟動iptables,docker的性能接近物理機的95%。

容器的監控

監控方面,我們自研了container tools,實現了容器load值的計算,替換了原有的top,free,iostat,uptime等命令。這樣業務方在容器內使用常用命令時看到的是容器的值,而不是整個物理機的。目前我們正在移植lxcfs到我們的平臺上。

我們還在宿主機上增加了多個閾值監控和報警,比如關鍵進程監控,日志監控,實時pid數量,網絡連接跟蹤數,容器oom報警等等。

## 冗災和隔離性 ##

冗災和隔離性方面,我們做了大量的冗災預案和技術準備。我們能夠在不啟動docker daemon的情況下,離線恢復docker中的數據。同時,我們支持docker的跨物理機冷遷移,支持動態的CPU擴容/縮容,網絡IO磁盤IO的限速。

## 遇到的問題及解決方法 ##

接近一年不到的產品化和實際使用中我們遇到過各種的問題,使用Docker的過程也是不斷優化Docker,不斷定位問題,解決問題的過程。

我們現在的生產環境用的是CentOS6.5。曾經有個業務方誤以為他用的docker容器是物理機,在docker容器里面又裝了一個docker,瞬間導致內核crash,影響了同一臺物理機的其他docker容器。

經過事后分析是2.6.32-431版本的內核對network namespace支持不好引起的,在docker內創建bridge會導致內核crash。upstream修復了這個bug,從2.6.32-431升級到2.6.32-504后問題解決。

還有一個用戶寫的程序有bug,創建的線程沒有及時回收,容器中產生了大量的線程,最后在宿主機上都無法執行命令或者ssh登陸,報的錯是"bash: fork: Cannot allocate memory",但通過free看空閑的內存卻是足夠的。

經過分析,發現是內核對pid的隔離性支持不完善,pid_max(/proc/sys/kernel/pid_max)是全局共享的。當一個容器中的pid數目達到上限32768,會導致宿主機和其他容器無法創建新的進程。最新的4.3-rc1才支持對每個容器進行pid_max限制。

我們還觀察到docker的宿主機內核日志中會產生亂序的問題。經過分析后發現是由于內核中只有一個log_buf緩沖區,所有printk打印的日志先放到這個緩沖區中,docker host以及container上的rsyslogd都會通過syslog從kernel的log_buf緩沖區中取日志,導致日志混亂。通過修改 container里的rsyslog配置,只讓宿主機去讀kernel日志,就能解決這個問題。

除此之外,我們還解決了device mapper的dm-thin discard導致內核crash等問題。

體會和思考

最后分享一下我們的體會和思考,相比KVM比較成熟的虛擬化技術,容器目前還有很多不完善的地方,除了集群管理,網絡和存儲,最重要的還是穩定性。影響穩定性的主要還是隔離性的不完善造成的,一個容器內引起的問題可能會影響整個系統。

容器的memcg無法回收slab cache,也不對dirty cache量進行限制,更容易發生OOM問題。還有,procfs上的一些文件接口還無法做到per-container,比如pid_max。

另外一點是對容器下的運維手段和運維經驗的沖擊。有些系統維護工具,比如ss,free,df等在容器中無法使用了,或者使用的結果跟物理機不一致,因為系統維護工具一般都會訪問procfs下的文件,而這些工具或是需要改造,或是需要進行適配。

雖然容器還不完善,但是我們還是十分堅定的看好容器未來的發展。Kubernetes/Mesos,Hyper,criu,runc等容器相關的開源軟件,都是我們關注的重點。

最后,以后大家想了解更多的話,可以關注我們的 技術博客 ,今天的分享就這些,謝謝大家。

==============================================

Q&A

Q:請問容器間的負載均衡是如何做的?

A: 容器間的負載均衡,更多是PaaS和SaaS層面的。我們的P層支持4層和7層的動態路由,通過域名的方式,或者名字服務來暴露出對外的接口。我們能夠做到基于容器的灰度升級,和彈性伸縮。

Q:請問你們的Openstack是運行在Centos 6.5上的嗎?

A: 是的,但是我們針對OpenStack和Docker依賴的包進行了升級。我們維護了內部的yum源。

Q:我想問下你們openstack的 cinder swift 底層存儲是用什么技術實現的?”

A: 我們還沒有在生產環境上正式集成cinder和swift,線下正在預研的是和Ceph的集成。

Q:請問容器IP是靜態編排還是動態獲取的?

A: 這個跟運維所管理的網絡模式有關,我們內部的網絡沒有DHCP服務,因此對于IaaS層,容器的IP是靜態分配的。對于PaaS層來說,如果有DHCP服務,容器的App所暴露出來IP和端口就可以做到動態的。

Q:請問你們當時部署的時候有沒有嘗試過用Ubuntu?有沒有研究過兩個系統間的區別?另外請問你們在Openstack上是怎樣對這些虛擬機監控的?

A: 我們沒有嘗試過Ubuntu,因為公司生產環境上用的是CentOS。我們的中間件團隊負責公司機器的監控,我們和監控團隊配合,將監控的agent程序部署到宿主機和每個容器里,這樣就可以當成虛擬機來進行監控。

當然,容器的數據是需要從cgroups里來取,這部分提取數據的工作,是我們來實現的。

Q:容器間的網絡選型有什么建議?據說采用虛擬網卡比物理網卡有不小的性能損失?docker自帶的weaves和ovs能勝任嗎?

A: 容器的網絡不建議用默認的NAT方式,因為NAT會造成一定的性能損失。之前我的分享中提到過,不需要啟動iptables,docker的性能接近物理機的95%。docker的weaves底層應該還是采用了網橋或者openvswitch。建議可以看一下novadocker的源碼,這樣會比較容易理解。

Q:靜態ip通過lxc實現的嗎?

A: 靜態ip的實現是在novadocker的novadocker/virt/docker/vifs.py中實現的。實現的原理就是通過ip命令添加 veth pair,然后用ip link set/ip netns exec等一系列命令來實現的。設置的原理和weaves類似。

Q:容器內的進程gdb你們怎么弄的?把gdb打包到容器內嗎?

A: 容器內的gdb不會有問題的,可以直接yum install gdb。

Q:共享存儲能直接mount到容器里嗎?

A: 雖然沒試過,但這個通過docker -v的方式應該沒什么問題。

Q:不啟動docker daemon的情況下,離線恢復docker中的數據是咋做到的?

A: 離線恢復的原理是用dmsetup create命令創建一個臨時的dm設備,映射到docker實例所用的dm設備號,通過mount這個臨時設備,就可以恢復出原來的數據。

Q:docker的跨物理機冷遷移,支持動態的CPU擴容/縮容,網絡IO磁盤IO的限速,是怎么實現的,能具體說說嗎?

A:docker的冷遷移是通過修改novadocker,來實現OpenStack遷移的接口,具體來說,就是在兩臺物理機間通過docker commit,docker push到內部的registry,然后docker pull snapshot來完成的。

動態的CPU擴容/縮容,網絡IO磁盤IO的限速主要是通過novadocker來修改cgroups中的cpuset, iops, bps,還有TC的參數來實現的。

Q:請問你們未來會不會考慮使用magnum項目,還是會選擇swarm?

A:這些都是我們備選的方案,可能會考慮swarm。因為magnum底層還是調用了kubernetes這樣的集群管理方案,與其用magnum,不如直接選擇swarm或者是kubernetes。當然,這只是我個人的看法。

Q:你們的業務是基于同一個鏡像么?如果是不同的鏡像,那么計算節點如何保證容器能夠快速啟動?

A:運維會維護一套統一的基礎鏡像。其他業務的鏡像會基于這個鏡像來制作。我們在初始化計算節點的時候就會通過docker pull把基礎鏡像拉到本地,這也是很多公司通用的做法,據我了解,騰訊,360都是類似的做法。

Q:如果基礎鏡像需要打補丁的話?如何做?

A:基礎鏡像需要打補丁,那其他依賴的也是需要升級的,這個我們沒有什么好的辦法,也想問一下大家是怎么做的。

Q:做熱遷移,有沒有考慮繼續使用傳統共享存儲的來做?

A: 分布式存儲和共享存儲都在考慮范圍內,我們下一步,就計劃做容器的熱遷移。

Q:請問你們是直接講公網IP綁定到容器嗎?還是通過其他方式映射到容器的私有IP,如果是映射如何解決原本二層的vlan隔離?

A:因為我們是私有云,不涉及floating ip的問題,所以你可以認為是公網IP。VLAN的二層隔離完全可以在交換機上作。我們用openvswitch劃分不同的vlan,就實現了docker容器和物理機的網絡隔離。

Q:Device mapper dm-thin discard問題能說的詳細些嗎?

A:4月份的時候,有兩臺宿主機經常無故重啟。首先想到的是查看/var/log/messages日志,但是在重啟時間點附近沒有找到與重啟相關的信息。而后在/var/crash目錄下,找到了內核crash的日志vmcore-dmesg.txt。日志的生成時間與宿主機重啟時間一致,可以說明宿主機是發生了kernel crash然后導致的自動重啟。“kernel BUG at drivers/md/persistent-data/dm-btree-remove.c:181!”。 從堆棧可以看出在做dm-thin的discard操作(processprepareddiscard),雖然不知道引起bug的根本原因,但是直接原因是discard操作引發的,可以關閉discard support來規避。

我們將所有的宿主機配置都禁用discard功能后,再沒有出現過同樣的問題。

在今年CNUTCon的大會上,騰訊和大眾點評在分享他們使用Docker的時候也提到了這個crash,他們的解決方法和我們完全一樣。

Q:閾值監控和告警那塊,有高中低多種級別的告警嗎?如果當前出現低級告警,是否會采取一些限制用戶接入或者砍掉當前用戶正在使用的業務?還是任由事態發展?

A:告警這塊,運維有專門的PE負責線上業務的穩定性。當出現告警時,業務方和PE會同時收到告警信息。如果是影響單個虛擬機的,PE會告知業務方,如果嚴重的,甚至可以及時下掉業務。我們會和PE合作,讓業務方及時將業務遷移走。

Q:你們自研的container tools有沒有開源,github上有沒有你們的代碼?如何還沒開源,后期有望開源嗎?關于監控容器的細粒度,你們是如何考慮的?

A:雖然我們目前還沒有開源,單我覺得開源出來的是完全沒問題的,請大家等我們的好消息。關于監控容器的細粒度,主要想法是在宿主機層面來監控容器的健康狀態,而容器內部的監控,是由業務方來做的。

Q:請問容器的layer有關心過層數么?底層的文件系統是ext4么?有優化策略么?

A:當然有關心,我們通過合并鏡像層次來優化docker pull鏡像的時間。在docker pull時,每一層校驗的耗時很長,通過減小層數,不僅大小變小,docker pull時間也大幅縮短。

Q:容器的memcg無法回收slab cache,也不對dirty cache量進行限制,更容易發生OOM問題。----這個緩存問題你們是怎么處理的?

A:我們根據實際的經驗值,把一部分的cache當做used內存來計算,盡量逼近真實的使用值。另外針對容器,內存報警閾值適當調低。同時添加容器oom的告警。如果升級到centos7,還可以配置kmem.limit_in_bytes來做一定的限制。

Q:能詳細介紹下你們容器網絡的隔離?

A:訪問隔離,目前二層隔離我們主要用vlan,后面也會考慮vxlan做隔離。 網絡流控,我們是就是使用OVS自帶的基于port的QoS,底層用的還是TC,后面還會考慮基于flow的流控。

Q:請問你們這一套都是用的centos6.5嗎?這樣技術的實現。是運維還是開發參與的多?

A:生產環境上穩定性是第一位的。centos6.5主要是運維負責全公司的統一維護。我們會給運維在大版本升級時提建議。同時做好虛擬化本身的穩定性工作。

Q:請問容器和容器直接是怎么通信的?網絡怎么設置?

A:你是指同一臺物理機上的嗎?我們目前還是通過IP方式來進行通信。具體的網絡可以采用網橋模式,或者VLAN模式。我們用openvswitch支持VLAN模式,可以做到容器間的隔離或者通信。

Q:你們是使用nova-api的方式集成dcoker嗎?docker的高級特性是否可以使用?如docker-api,另外為什么不使用heat集成docker?

A:我們是用novadocker這個開源軟件實現的,novadocker是StackForge上一個開源項目,它做為nova的一個插件,替換了已有的libvirt,通過調用Docker的RESTful接口來控制容器的啟停等動作。

使用heat還是nova來集成docker業界確實一直存在爭議的,我們更多的是考慮我們自身想解決的問題。Heat本身依賴的關系較為復雜,其實業界用的也并不多,否則社區就不會推出Magnum了。

Q:目前你們有沒有容器跨DC的實踐或類似的方向?

A:我們已經在多個機房部署了多套集群,每個機房有一套獨立的集群,在此之上,我們開發了自己的管理平臺,能夠實現對多集群的統一管理。同時,我們搭建了docker registry v1,內部準備升級到docker registry v2,能夠實現docker鏡像的跨DC mirror功能。

Q:我現在也在推進DOCKER的持續集成與集群管理,但發現容器多了管理也是個問題,比如容器的彈性管理與資源監控,Kubernetes/Mesos哪個比較好一些,如果用在業務上,那對外的域名解析如何做呢,因為都是通過宿主機來通信,而它只有一個對外IP?

A: 對于Kubernetes和Mesos我們還在預研階段,我們目前的P層調度是自研的,我們是通過etcd來維護實例的狀態,端口等信息。對于7層的可以通過nginx來解析,對于4層,需要依賴于naming服務。我們內部有自研的naming服務,因此我們可以解決這些問題。對外雖然只有一個IP,但是暴露的端口是不同的。

Q:請問你們有考慮使用 hyper hypernetes嗎? 實現容器與宿主機內核隔離 同時保證啟動速度?

A:Hyper我們一直在關注,hyper是個很不錯的想法,未來也不排除會使用hyper。其實我們最希望hyper實現的是熱遷移,這是目前docker還做不到的。

Q:問個基礎問題,請問你們宿主機一般用的什么配置?獨立主機還是云服務器?

A:我們有自己的機房,用的是獨立的服務器,物理機。

Q:容器跨host通信使用哪一種解決方案?

A: 容器跨host就必須使用3層來通信,也就是IP,容器可以有獨立的IP,或者宿主機IP+端口映射的方式來實現。我們目前用的比較多的還是獨立ip的方式,易于管理。

Q:感覺貴公司對docker的使用比較像虛擬機,為什么不直接考慮從容器的角度來使用,是歷史原因么?

A:我們首先考慮的是用戶的接受程度和改造的成本。從用戶的角度來說,他并不關心業務是跑在容器里,還是虛擬機里,他更關心的是應用的部署效率,對應用本身的穩定性和性能的影響。從容器的角度,一些業務方已有的應用可能需要比較大的改造。比如日志系統,全鏈路監控等等。當然,最主要的是對已有運維系統的沖擊會比較大。容器的管理對運維來說是個挑戰,運維的接受是需要一個過程的。

當然,把docker當成容器來封裝應用,來實現PaaS的部署和動態調度,這是我們的目標,事實上我們也在往這個方向努力。這個也需要業務方把應用進行拆分,實現微服務化,這個需要一個過程。

Q:其實我們也想用容器當虛擬機使用。你們用虛擬機跑什么中間件?我們想解決測試關鍵對大量相對獨立環境weblogic的矛盾?

A:我們跑的業務有很多,從前臺的主站Web,到后端的中間件服務。我們的中間件服務是另外團隊自研的產品,實現前后臺業務邏輯的分離。

Q:貴公司用OpenStack同時管理docker和KVM是否有自己開發web配置界面?還是單純用API管理?

A:我們有自研的web管理平臺,我們希望通過一個平臺管理多個集群,并且對接運維,日志,監控等系統,對外暴露統一的API接口。

Q:上面分享的一個案例中,關于2.6內核namespace的bug,這個低版本的內核可以安裝docker環境嗎?docker目前對procfs的隔離還不完善,你們開發的container tools是基于應用層的還是需要修改內核?

A:安裝和使用應該沒問題,但如果上生產環境,是需要全面的考慮的,主要還是穩定性和隔離性不夠,低版本的內核更容易造成系統crash或者各種嚴重的問題,有些其實不是bug,而是功能不完善,比如容器內創建網橋會導致crash,就是network namespace內核支持不完善引起的。

我們開發的container tools是基于應用的,不需要修改內核。

Q:關于冗災方面有沒有更詳細的介紹,比如離線狀態如何實現數據恢復的?

A:離線狀態如何實現恢復數據,這個我在之前已經回答過了,具體來說,是用dmsetup create命令創建一個臨時的dm設備,映射到docker實例所用的dm設備號,通過mount這個臨時設備,就可以恢復出原來的數據。其他的冗災方案,因為內容比較多,可以再另外組織一次分享了。你可以關注一下 http://mogu.io/ ,到時候我們會分享出來。

Q:貴公司目前線上容器化的系統,無狀態為主還是有狀態為主,在場景選擇上有什么考慮或難點?

A:互聯網公司的應用主要是以無狀態的為主。有狀態的業務其實從業務層面也可以改造成部分有狀態,或者完全不狀態的應用。不太明白你說的場景選擇,但我們盡量滿足業務方的各種需求。

對于一些本身對穩定性要求很高,或對時延IO特別敏感,比如redis業務,無法做到完全隔離或者無狀態的,我們不建議他們用容器。

=============================================================

以上內容根據2015年11月03日晚微信群分享內容整理。分享人: 郭嘉 ,蘑菇街平臺技術部高級工程師,虛擬化組責任人。2014年加入蘑菇街,目前主要專注于蘑菇街的私有云建設,關注Docker,KVM,OpenStack,Kubernetes等領域。DockOne每周都會組織定向的技術分享,歡迎感興趣的同學加微信: liyingjiesx ,進群參與,您有想聽的話題可以給我們留言。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!