Docker實踐,來自滬江、滴滴、蘑菇街架構師的交流分享

架構師小組交流會:每期選一個時下最熱門的技術話題進行實踐經驗分享。
第一期主題:容器實踐。Docker 作爲當前最具顛覆性的開源技術之一,其輕量虛擬化、可移植性是CI/CD,DevOps,微服務的重要實現技術。但目前技術還不夠成熟,在生產實踐中會遇到不少坑。本期參與小組交流的是國內較早採用 Docker 實踐的公司。
參與嘉賓:滬江架構師黃凱、滴滴架構師田智偉、蘑菇街架構師張振華、蘑菇街運維架構師向靖、七牛技術總監袁曉沛、扇貝技術總監丁彥

第一輪:自由交流
滬江黃凱:大家好,我是來自滬江的 Java 架構師,我叫黃凱。在加入滬江之前,曾在 HP 和 IBM 的雲計算部門擔任核心開發和架構職位。對 IaaS、Paas、SaaS,尤其是雲存儲有較深入的瞭解。2015 年加入滬江,擔任架構師職位,主導的產品有:課件雲存儲,雲轉碼等等。在這些項目中,我們使用 Mesos 和 Marathon 做 Docker 的編排工具,並開發了一個 Mesos Framework 做雲轉碼的核心框架。

那麼我們爲什麼要使用 Docker,也是機緣巧合。由於我們的服務開始的時候不是特別多,採用的就是一種普通的架構,後來隨着服務的增多,發現部署和運維花的時間太長,我們想使用一些新的方式。開始的時候研究過 Openstack,後來覺得 Openstack 慢慢沒落,於是我們就選中現在使用的 Docker。我們並不把 Docker 當成 VM 在用,而是使用它的原生的,在 Baremetal 上直接安裝 Docker,這樣運行效率比在 VM 運行 Docker 要來的快。課件雲是由很多微服務組成,不光是一些存儲,這種微服務是使用 Docker 部署,就相當於編排,把這些微服務部署上去。轉碼這一塊是使用了 Mesos 框架,和 Docker 沒有特別大的關係,但是轉碼的應用程序,比如說我們現在應用 FFmpeg,這個程序是運行在 Docker 裏面的。

爲什麼要選擇 Marathon?第一,我覺得 Mesos+Marathon 非常的容易理解。我們也研究過 Kubernetes 和其他的一些方法,發現從運維和研究的方面來說的話,Kubernetes 實在是太重而且太複雜,後來選擇了Marathon。我們現在是內部服務使用,兩個部門在使用轉碼集羣,大概是 Baremetal 有 20 臺的物理機。除去我們 API 的一些服務,還有一些第三方組件的服務的話,大概是有 400 多個 Docker 容器在跑。

滴滴田智偉:大家好,我是滴滴代駕事業部架構師,代駕事業部是公司最早嘗試 Docker 虛擬化的事業部。目前主要方向是業務系統及部分中間件的 Docker 化,我們做的時間也不太長,半年多的時間。線上是因爲我們有老的一套發佈系統,集成涉及的部門比較多,所以我們基於原來的發佈系統完成了預發佈環境 Docker 的部署。線下環境基於 Docker+K8s 開發內部的自動化持續交付系統及開發測試環境管理。我們在做開發和測試環境的自動化,另一方面也是做環境管理的,兩套環境。對於項目並行的時候發現原來很多不夠用,原來很多配置是基於端口綁死的情況。現在基於開發 Kubernetes 的話,網絡隔離用了一部分,然後主要是用環境變量這一部分,主要考慮是解決一個配置可以應用到在多個環境的情況,基於這個需求才用它。開發 Kubernetes 基於 Namespace,同一個服務在不同的 Namespace 下,它其實環境變量名可以是相同的,但是IP不同,而這一部分 IP 其實是由開發 Kubernetes 自己去管理的。基於環境變量獲取一些配置的話,比如 IP 地址這種,就可以做到拿一份配置可以打出多套環境。

考慮業務的安全性和穩定性,線上基於純 Docker 的方式在做。我們是基於裸的 Docker 來工作,主要是用資源隔離,沒有藉助調度框架,也沒有自動伸縮。我們是兩步走,一步是驗證 Docker,其次是做開發 Kubernetes 線下使用和預研。爲什麼沒有考慮 Mesos?剛纔跟滬江的同學,我們的考慮是相反的。Mesos 側重點更專一一點,首先不會有模塊的劃分,比如 Kubernetes 有 Replication controller ,Namespace 這種概念,而 Mesos 下幾乎沒有這種概念。我們拿 Kubernetes 主要是做一些編排的功能,而正好開發 Kubernetes 在整個發佈和編排上,體系更全面一點。Mesos 最早是做資源管理,基於 Docker 做一個 Framework 接進來的話,它不是專門爲編排而生。Kubernetes 首先解決我們的問題是,我們可能不需要加多份配置就可以搭多套不同的環境,它就是基於 Namespace 做一個多租戶的概念,會對 Service 做一層隔離,對於動態配置,擴容這一部分暫時我們沒用到,確實用到的一些場景比較少。主要是做不同環境的隔離,並沒有太多使用編排細節上的東西,動態伸縮之類的目前線下沒有太大必要,線上可能會用到。

蘑菇街向靖:大家好,我是子騫,來自蘑菇街的運維架構師。我們接下來會做一個 Paas 平臺,想做 Docker 和結合虛擬機以及我們用到公有云產品,做成一個混合雲的架構平臺。我們現在 Docker 也在用,更多的是當虛擬機用,後面我們想基於 Docker 原生的方式去用,可能會涉及資源調度,服務發現的問題。除了 Docker,我們還會用到公有云,公有云更多是虛擬機的方式提供。出於混合雲,想在資源層做一個抽象,對於上層業務來講它沒有關係,它是跑在 Docker 上,還是雲主機上,還是 KVM 虛擬機上,那麼我想在這上面做一個抽象。另外還有,剛纔我也是提問滴滴架構師的問題,配置怎樣和代碼做隔離,這個也是我考慮的問題。因爲我看 Docker 用了環境變量,通過環境變量做一些配置的參數的傳遞,但是在虛擬機上,特別是在物理機上,通過環境變量的方式,我還在考慮有沒有安全的風險,Docker 可能是一個只讀的,不會被修改的,但是對於虛擬機以及物理機來說,可能會存在被修改的風險。

蘑菇街張振華:大家好,我叫張振華,花名郭嘉,我是 14 年從思科加入蘑菇街。我們算是國內用 Docker 比較早的,我們一開始用 Docker 是 1.3.2 的版本,當時我們採用集羣管理工具還是Openstack,因爲當時 Kubernetes 還不是很成熟。當時也走了一些彎路,比如我們把 Docker 當成虛擬機來用,曾經在線上的規模也達到幾百臺虛擬機幾千個容器,但是我們逐步發現不能把 Docker 當成虛擬機來使用,因此我們做了一個轉型,從去年開始研究 Kubernetes,現在 Kubernetes 加 Docker 的版本開發完成了,準備逐步上線。

我們爲什麼選用 Kubernetes?編排工具的選擇我們也是做過一番調研的,它們沒有誰好誰不好這一說,只能說誰更貼切你的需求。對於我們蘑菇街來說,我們需要解決是資源利用率的問題,和運維的對接,我們需要有預發和線上環境的持續集成持續部署的過程,還有我們需要有對資源的隔離,對部署的快速迭代,包括集羣管理,這些方面,我們覺得 Kubernetes 更加適合於我們。

在網絡方面,我們研究過現在在開源界比較常用的一些方案,但是我們都覺得不太適合,比較 Fannel,Caico 等等,他們一般用的技術都是 Vxlan,或者是用 BGP。因爲我們之前對 Openstack 的網絡是比較有經驗的,然後我們發現有一個項目,具體名字不記得,Neutron 和 Kubernetes 做一個對接,我們在這個項目的基礎上做了 Vlan 的方案,我們的網絡沒有用 Vxlan 來做,而是選擇 Vlan 來做,這樣的話一個 Docker 它可以獲得跟一個物理理同一個網絡平面的 IP,我們的應用程序可以直接對外訪問,因爲我們內部業務有這個需求選擇這個方案。雖然 Docker 內部網絡和外部網絡是通的,但 Docker 還是獨立的一個網段,不需要一層 NAT 的轉換。我們直接走二層的,是在交換機走 Chunk,本來物理機交換機的 Access 口,這樣的話,一臺物理機上面允許跑多個vlan的容器,比如說 A業務和 B業務要走隔離的話,通過網絡的 Vlan 走隔離,它們的數據之間不會有干擾。

Load Balance 我們還沒有涉及到這一塊,Load Balance 我們應該會在 nginx 上做一層。因爲據我瞭解,現在 Kubernetes 這一塊 Proxy 還不是很成熟,這上面還存在一些問題,因此還不敢用 Kubernetes 現有提供的服務。服務發現和註冊這一塊我們還在做開發,這塊會和配置管理中心打通。我們內部也有其他團隊在做這些功能,所以我們會和內部的中間件團隊合作。

七牛雲袁曉沛:大家好,我是七牛雲數據處理技術總監袁曉沛。我們的數據處理業務包括了圖片和視頻的實時在線及異步處理。數據處理的業務量比較大,日均請求量達到百億級。平臺採用容器技術的原因是藉助容器技術快速部署,啓動的特性,數據處理程序可以根據數據處理量快速地彈性伸縮。藉助容器技術內核級別的資源隔離和訪問控制,每個數據處理程序可以運行在一個私有的環境,不被其它程序所幹擾,保證其上運行數據是安全可靠的。而且容器技術是輕量的,它以最小的資源損耗提供資源隔離和訪問控制,而資源特別是計算資源在數據處理中是非常寶貴的。

我們在資源調度上採用的是 Mesos,而二層的業務調度框架則是自己自研的。七牛自身擁有近千臺的物理機,容器是直接運行的物理機上,可以減少虛擬層對資源的消耗,提高資源的利用率。

在網絡上,對於七牛的自定義數據處理服務直接使用的是 Host 模式,而對第三方數據處理服務則使用的是 Bridge 模式,因爲這些程序是用戶自己部署運行的,並不知道用戶是否有開啓其他的端口使用,所以使用的是 Bridge 模式,需要對外使用端口的都需要通過 NAT 進行暴露,這樣服務內部使用了什麼端口並不會對外界環境造成影響,對平臺環境做了非常好的安全隔離。我們是使用 Consul 做註冊中心,支持跨數據中心的服務發現。我們爲什麼自研的調度框架,而不用 Marathon。因爲 Marathon 不支持跨數據中心的內部服務或外部服務的發現,而七牛有多個數據中心,影響整體的調度,其次如果選用 Marathon 的話,根據我們業務的特點,還是要再做一層對 Marathon 的包裝才能作爲 Dora 的調度服務,這樣模塊就會變多,部署運維會複雜。

扇貝丁彥:大家好,我是扇貝的技術總監丁彥,之前在暴走漫畫,先後在暴走漫畫和扇貝設計和主導了基於 Docker 的微服務架構系統,以及數據收集和分析系統。去年來到扇貝,這裏是 Python 的開發環境。後來發現業務增長快,水平擴展一些機器,出現問題需要換個機器等等,都需要非常熟悉業務的少數開發去做。另外公司對預算控制嚴格,機器基本都是滿負荷運作,平時也不可能多開空置的機器,已有的機器還要根據負載情況調整服務分佈情況,所以這種切換服務,增刪服務的操作還是比較頻繁的。因此,我們用了2-3個月的時間將所有的運行環境都切換到 Docker上,這大大提高了我們的運維能力。

Docker 包裝有幾個好處。
第一個好處是,環境升級非常方便。因爲只要pull 一下最新的鏡像,啓動一個 Container,環境就升級了。而如果直接基於公有云的鏡像升級的話就很難,因爲一臺機器上跑哪些服務其實不一定是固定的,並且之前做的鏡像只要有一臺機器是還基於它的話,就刪除不掉的,鏡像數量又有上限。所以docker 非常好地解決了我們的問題。
其次是環境的顆粒度會更小,一臺機器上配好幾個應用的話,往往配着配着,到最後你就不太能精確地記得上面裝的程序或者庫是給哪個應用服務的,應用之間如果依賴有版本的衝突也很難調和。你想做些服務的遷移,把負載比較小的放一起,把負載比較大的抽出來,這個時候就非常痛苦,但你如果用 Docker 包裝後就非常簡單,只要在不同的機器上起不同的 Container,就可以實現這一點。
第三,我們不光用了 Docker,還加入了服務發現,剛剛討論配置管理這些,我們一併做了。Docker 啓動時候,我們自己寫了一些工具,可以自定義Docker啓動參數,包括配置參數,比如說,一些程序要運行的參數,我們主要用兩種方式,一種方式是通過環境變量灌進去,還有一種方式讓程序的啓動腳本支持參數,然後拼接不同的參數灌進去,最終都是落實到Docker的啓動命令上。服務發現是基於 Consul,Docker 的啓動命令是從 Consul 裏取的。首先 Consul有 HTTP 的 API,我們是自己寫的 pip 包,只要 Include 一下這個包就可以了,Docker 的服務啓動後會自動註冊到 Consul。比如要在負載後加一個服務,只需要找到一臺機器,啓動對應的container,剩下的事情它自己會到 Consul,註冊它的參數地址一系列東西,自動把它加進去。所以這些都是自動化的,如果檢測那臺機器/服務掛了,Health Check 也會到 Consul 裏面更新。該增加機器就增加機器,該下線就下線。總體來說,我們的生產環境全部跑在 Docker 上面的,然後區分有狀態和無狀態兩種,有狀態的定死在機器上,無狀態的靈活的自由切換。還有一點,如果是有狀態的容器要定死在機器上的時候,我們一般來說都會採取冗餘的結構,至少保證有兩個在運行,一個掛了,保證整體的服務在運行。其次基於 Docker,我們還做了一套數據蒐集以及分析的機制。數據蒐集是基於日誌來蒐集的,利用 Docker 的 Log driver,把日誌打到 Filter,把結果存在存儲服務上。同時監控也是基於日誌做的。第三部分非生產環境,比如開發環境跟測試環境都是 Docker 做的,因爲我們每一個服務都做了 Image、鏡像,用容器方式跑的。通過參數來決定啓動方式的,我們可以在開發環境以及測試環境採用不同的參數來啓動容器。 通過 Consul 來隔離的,因爲 Consul 的服務發現,開發、生產、測試環境在不同的自動發現框架裏不會相互影響到。目前機器在 120 臺左右,基於雲服務。有些基礎的東西不需要依賴於 Docker,比如說申請雲主機,申請的時候就可以指定它的 CPU 和內存這些服務器資源的配置。所以這部分東西還是屬於 Human schedule,不是完全讓編排的系統自己決定該怎麼樣。

編排工具我們現在在研究進一步,我剛來這工作的時候,所有的服務沒有一個跑在 Docker 上面的,我現在把它遷進來。現在數據增長,已經有一些編排的瓶頸,現在在做調研,可能基於 Swarm,做自動編排的設計。

第二輪話題交流
主持人:容器多的情況下 Kubernetes 存在性能問題,各位在這方面有沒有好的經驗?
扇貝丁彥:我們其實也遇到了這個問題,找不到辦法所以放棄了 Kubernetes。我們也是用公有云,網絡直接依賴公有云的網絡,有可能是因爲公有云造成的,我沒有試過在祼機上試過。

滬江黃凱:Kuberneters 的 Fannel 有一種模式是 Vxlan,它的封裝摺包是做內核裏做的,效率會高一點。容器多就會效率會低是因爲,在 Kubernetes 1.2 的時候,走這樣的一種模式,數據先到內核態中,然後把數據拉回到用戶態,用 Proxy的方式分發給各個容器當中的。其實在Kubernetes 1.3以後,它直接在iptables裏設規則,相當於用戶數據不用跑到用戶態,在內核直接分發出去了,這種效率會非常高。所以可以研究一下Kubernetes新版本。

扇貝丁彥:我們碰到過網絡方面的問題。默認的Docker engine的啓動參數裏面有個iptables,不知道大家有沒有定製化過,如果不定製化這個參數,它默認會幫你建iptables的轉發規則,並會開啓內核的網絡追蹤的模塊。一開始我們沒有注意這件事情,當我們的Nginx遷到Docker的時候,Nginx服務瞬間會掛。後來查原因,是因爲這些參數會開啓網絡追蹤模塊。因爲我們的Nginx流量非常大,當時只有3臺Linux雲主機,分發Http請求的,然後會導致3臺Linux宿主機,內存會被刷破,網絡會出現堵塞。所以我們關掉了 iptables 參數,並採用Host的網絡模型。所以它的容器拿到的IP就是Host的IP。我們一開始也想上一些Kubernetes這些東西,然後發現簡單跑個模型根本跑不起來,所以一開始就放棄了這一套東西,直接搞了個裸的Docker。
 
主持人:關於跨數據中心容器集羣的使用,大家有經驗麼?
滬江黃凱:我們跨數據中心主要是IP分配上的問題,我們現在也在嘗試使用Calico,如果Host網絡是通的話,那麼它的內部網絡也就通了,可以自由劃Vlan,這樣你就可以解決跨Data center的問題。還有一個問題就在跨Data center時,服務註冊與發現的問題。這個問題也困擾我們很久了,我們現在使用Consul做服務註冊與發現。雖然Consul它是官方支持跨Data center,但是我們在使用當中的話會發現註冊的IP,在另外一個註冊中心,它會發現的比較慢,甚至有時候出現IP衝突的時候。
我們的做法是把 Host 的 IP 地址直接用 Environment 的形式注到 Docker 鏡像內部,接下 來 Docker 鏡像要註冊,它就會讀取 app 的 IP,然後發送給 Consul,只要保證 Host 的 IP 和 Docker內部容器的 IP 能夠互通的就行了。如果不能通的話,比如說完全和 Host IP 隔離,那麼起碼有幾臺機器要暴露出去,又比如說,Consul 它本身自己要暴露出去才能訪問到。Host 的 IP 是容器啓動之後注進去的,啓動命令中把 Host 的 IP 地址加在 -e 的後面,容器在啓動之後,它的環境就會有這麼一個 IP。我們用 Mesos 就沒這個問題,但是用 Kubernetes 就有這個問題。Mesos 會自動幫你把這些東西注入容器中去。

滴滴田智偉:其實 Kubernetes 本身也是可以解決這個問題,我們現在在做線下持續交付的時候。定義完 Service 之後,容器會同一個 Namespace 默認加一個系統環境變量。

滬江黃凱:我們試過,在 Pod 啓動之後,Pod 裏容器想訪問 host 的 IP 地址,是沒有辦法做到的。
 
蘑菇街張振華:因爲我們之前也遇到這個問題,然後我們業務方,他們可能有一些程序會獲取本機 IP 地址,如果是內部的 IP 地址,他們程序可能會出現問題,於是我們當時沒有用 Docker 默認的網絡,而是採用 Vlan。

主持人:我們提到好多 Mesos、Kubernetes、網絡,發現沒有提自動伸縮,有沒有項目涉及到容器的自動伸縮?
滬江黃凱:我們滬江是基於 Mesos+Marathon 做了自己的一個服務,它這個服務是幹嘛的呢,就是監測,不停的監測每一個 Docker 的 CPU 和內存的利用率,一旦超過百分之多少以後,就向Marathon發一個命令,說我要擴容,它還可以支持時間點,比如 15 分鐘監測一次,如果在 15 分鐘發現它超過閾值了,就馬上擴容出來,但是縮的話,不是適用於頻繁監控,如果小於 20% 的話就會縮,一旦縮的話會影響線上用戶的請求。怎麼辦呢?我們在縮的時候可以規定它的時間點,比如半夜裏2-3點,訪問量少於多少點時候把它縮掉。我們監測的是 Docker 內部的 CPU 的使用率。就是監測一個服務,它可以監控所有同一服務的 Container,比如一個服務有100個容器,那麼這一百多個 CPU 利用率加起來除於一百,相當於平均的利用率。如果平均利用率超過 80%了,那說明這個集羣到了擴展程度了,它會以一種比例來擴展。針對單個容器,可以設置內存的限制。我們給每一個容器呢,比如它只能用 4 個 CPU,只能用 8G 的內存,或者更小一點的內存,這些都設好,設好之後它自動擴展相同規格的容器。這麼做是因爲 Cgroup 有個問題,當利用率到達了啓動的限制,Cgroup 會把這個容器 kill 掉。這個是不可理喻的問題,所以我們想到用 Load scale 來擴容,不讓他直接死掉。

滴滴田志偉:關於自動擴容,我們線下的時候遇到一個問題,我們最早的時候是用騰訊的公有云,它限制了 NET 的模塊,導致我們最初用 Cgroup 的方案去做,綁定端口。內部使用所有應用,端口是要做分配的,要不然出現端口衝突。然後遇到問題是,在這種情況下,如果要做動態擴容的話,它每次先創建一個,再殺掉一個,導致每次起來的時候就起不來了,因爲端口的問題。服務啓動的時候端口是隨機,會出現衝突問題,因爲用的是 Host 的模式。
 
主持人:關於自動伸縮爲什麼沒有考慮到請求數?因爲如果內存佔用率如果超過一定預支,那麼請求數也可能超過一定預支了。把單個容器所處理的請求數給限定了,那麼它內存自然不會超,然後也不會被幹掉。
滬江黃凱:我個人認爲,第一,請求數很難測,你不知道請求數到多少時要擴容,還不如根據 CPU 到 80%,或者 90% 來的直觀。我們的 API 也是根據 CPU 來算的。你真正是高併發的 API 的話,我也測過,最後我們能夠監測到的,其實還是 CPU 和內存。

扇貝丁彥:我們擴容是根據響應時間,跟請求數類似,請求數定指標不太好定,我們是根據響應時間,比如平時的響應時間是 50 毫秒,當響應時間是 300 毫秒的時候就要擴容了。

主持人:大家對於容器有狀態無狀態有沒有遇到什麼問題?大家一般用容器的本地磁盤還是共享磁盤呢?
滬江黃凱:關於存儲,我們是有一些研究的。現在容器存儲問題分爲兩種,Kubernetes 官方支持一種理念,任何一種存儲都是一個 Volume。Volume 先於 Docker 存在的,而不是 Docker 啓動之後再掛載 Volume。不管是網絡存儲還是本地存儲,全部以卷的形式,掛載在 Pod 裏面或者是宿主機上,以 Driver mapper 來驅動這個 Volume,來讀到你所要的內容。
還有一種情況,就是 Docker 公司主導的存儲模型,任何的存儲都是一種驅動。如果你想用 NFS 或者如 Ceph 這樣分佈式存儲的話,讓 Ceph 開發 Docker 的驅動,Docker run 的時候指定存儲的驅動,Docker storage driver這種方式,外部的存儲在容器內部它展現形式可以是目錄,也可以是掛載卷、塊的形式。如果用塊掛載到容器中,這個容器自己格式化它,或直接讀取它都是可以的。它只不過它是相當於用了一個 Driver 的形式,把你的容器和分佈式存儲建立一個連接而已。對於容器,如果原本綁定塊或 Volume,容器出現故障的話,直接把容器殺掉,再啓動掛在同樣一個 塊或Volume就解決了。優點是直接讀取,而不是通過再轉一層,效率比較高一點。所有存儲都是Volume 的形式理解度比較高一點,所以我們還是贊同於用 Volume 的形式。
有狀態的容器。我知道k8s的新的計劃,如果你沒有用 Kubernetes 最新版本的話,一般來說我們都是容器啓動在固定Host 上,下次啓動還是在這臺 Host 上,它的存儲它的內存,包括一些 log,全部是在這臺 Host 上。還有一種是用最新的版本,有個 PetSet的新kind,Kubernetes 它自己會記錄 Pod 在什麼 Host 上啓動過,不用自己去指定一定要在某一臺 Host 上啓動,這種方法比較智能化,但是不是特別穩定的一種方法,因爲它是剛剛開發出來的新功能。

主持人:數據多副本,假設有一個節點故障的話,是建議它直接把原來的副本重新綁定還是重新起一個新的實例,通過分佈式數據的遷移呢?
滬江黃凱:我個人認爲還是在同一臺機器上起一個新的實例,不要讓它做數據遷移,因爲數據遷移會佔用很多資源。而且如果你的想法是說,所有的分佈式的存儲只是以 Volume 的形式掛載在宿主同上,這也就沒什麼問題了。因爲存儲和 Docker 是完全分開來的。如果只有一個 Volume,存儲的可靠性會得不到保障,所以在 Kubernetes 新版本當中,它會建立一個Volume的kind,也相當於建立 RC kind一樣,是一個 Pod,那這樣由 Kubernetes 來保障這個 Volume 的高可用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章