容器私有云和持续发布都要解决哪些基础问题 第一集
生活随笔
收集整理的這篇文章主要介紹了
容器私有云和持续发布都要解决哪些基础问题 第一集
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
鄭昀編著,文字資料來自于張帆、白俊華、劉飛宇以及網絡資料 創建于2015/10/21 最后更新于2015/10/29 關鍵詞:Docker,容器,持續集成,持續發布,CI,私有云
本文檔適用人員:廣義上的技術人員 提綱:集裝箱還是卷掛載? Host Networking 還是 Bridge Networking? 容器要固定IP嗎? 容器內部如何獲取宿主機的IP? 待續
? 首先,你要明白容器并不是虛擬機,雖然它可以解決虛擬機能夠解決的問題,同時也能夠解決虛擬機由于資源要求過高而無法解決的問題,但它真的不是虛擬機。以往我們的開發、配置管理、部署發布、監控報警思路都要跟著變。 其次,一開始注定只有一少部分工程遷移到容器私有云上,既然還有大多數應用服務還在虛擬機或物理機上,那么它們之間如何通訊就成了一個必須解決的問題。 那么,我們在構建基于容器的私有云以及相應的持續發布時,遇到并解決了哪些問題呢?
? 我們再來看一下 Docker 的 Logo,它隱含天機: ? 一艘鯨魚大船,載著無數集裝箱。操作系統就是這艘貨輪,每一個容器就是一個集裝箱,交付運行環境如同海運。大家知道嗎,集裝箱的英文單詞就是 container! 集裝箱有什么好處? 規格標準,在港口和船上可以層疊擺放,節省大量空間, 可以進行快速裝卸,并可從一種運輸工具方便地換裝到另一種運輸工具, 途中轉運不用移動箱內貨物,就可以直接換裝, 貨物的裝滿和卸空很方便。 那么,上面的選擇題如何回答呢? 觸控科技運維負責人蕭田國認為,把代碼放在宿主機上,讓容器通過卷組映射來讀取,不建議采用這種方案,原因是,將代碼拆分出容器,這違背了 Docker 的集裝箱原則:
none:關閉了 container 內的網絡連接。容器有獨立的 Network namespace,但并沒有對其進行任何網絡設置,如分配 veth pair 和網橋連接,配置 IP 等。 bridge:通過 veth 接口來連接其他 container。這是 docker 的默認選項。 host:允許 container 使用 host 的網絡堆棧信息。容器和宿主機共享 Network namespace。 container:使用另外一個 container 的網絡堆棧信息。kubernetes 中的 pod 就是多個容器共享一個 Network namespace。 ? 我們需要從中選一個作為我們的網絡方案,實際上只有 bridge 和 host 兩種模式可選。(想了解這四個參數,請翻到附錄B之 Network settings。) 在 docker 默認的網絡環境下,單臺主機上的容器可以通過 docker0 網橋直接通信,如下圖(圖作者馮明振)所示: 而不同主機上的容器之間只能通過在主機上做端口映射進行通信。這種端口映射方式對集群應用來說極不方便。(出處8)我們重點要解決這個問題。 先看一下其他學生怎么做這道選擇題的:
先說一下 host 模式。 容器的網絡直接和外部網絡打通,解決了不同 slave 物理機之間容器互聯互通的問題,減少了 NAT 轉換的損耗,但需要自行來維護容器的 IP 地址和端口,否則會沖突,這增加了管理上的復雜度。請考慮這個場景:在同一個 slave 物理機上運行兩個 80 端口 Nginx 容器的情況,除非分配兩個不同的 IP 地址,這種方案我們之前在 shipyard 方案中使用過。 新浪微博在《大規模Docker集群助力微博迎接春晚峰值挑戰》一文中曾經介紹過: Docker 部署被詬病最多就是網絡,平臺目前采用的是 host 模式,為什么沒有采用 NAT 或者 Bridge 呢?由于涉及的技術細節比較繁冗,這里僅分享一些踩過的坑。例如 NAT 使用 iptables 底層流量轉發依靠內核 netfilter 模塊,其默認僅保持 65536 個鏈接,在服務有大量鏈接的場景下,會出現大量拒絕鏈接的現象。再如 Bridge 的 MAC 地址默認是選擇其子接口中最先的一個,這樣就會導致一個宿主機下多個容器啟停時出現網絡瞬斷。還有很多問題不一一列舉,平臺未來計劃采用 vlanif 的方案來解決容器網絡部署難題。 再看 bridge 模式,它是 docker 默認的網絡模式,為了解決容器間互通問題,通常有兩種解決方案: 采用 SDN(軟件定義網絡) 技術,如 flannel,weave 等,直接將容器內網打通;? 采用 NAT(網絡地址轉換) 技術,直接使用 slave 主機的 IP 地址互通。? 我們認為,bridge 模式加 NAT 方式,是當前 mesos+marathon 支持的最好的模式(采用的是 container port,host port,service port 的對應關系)。我們的容器云主要構建于 mesos+marathon 之上,封裝了我們的業務邏輯,采用一些方式解決了容器與現存非容器架構之間的互通問題,?如 consul 的服務注冊和發現機制,dubbo 的應用注冊和發現機制等。? 最終我們選擇了 Bridge Networking。
這樣的話,需要在容器啟動后在宿主機上運行 pipework 來設置容器的 ip,這樣就增加了自動化的難度。 我們的考慮是,第一,容器應該是無狀態的,分配固定 IP 違背了這個理念,第二,Docker 剛出來一兩年,還在飛速發展中,現在你改了內核代碼,將來它大版本升級,你怎么跟隨?第三,使用固定 IP 很大程度上是為了讓技術人員能像以前一樣直接登錄虛擬機操作,但我們的持續集成管理平臺里使用 webconsole 也能登到容器里面操作。 我們的實踐是:首先,我們內部調用都走內部域名,有專門的 DNS Server,其次,我們很早以前就引入了服務治理框架 Dubbo,基本做到了服務的注冊和發現。再次,我們在容器云里引入了 consul 的注冊和發現服務,配合 slave 節點上的 registrator 容器,以及 haproxy 和 consul-template 組件,實現了完整的容器服務的注冊和發現架構。?? 第一,dubbo 能幫我們解決什么容器問題: 進駐容器云后 java 工程之間的調用:直接將物理機的 ip 和容器 java 工程對外提供的隨機端口,注冊到 dubbo 里。例如, 容器 javaA 要調用容器 javaB,容器 javaB 已經將它對外提供的 ip 和隨機端口注冊到了 dubbo 里,容器 javaA 可以從 dubbo 里找到容器 javaB 相關的信息直接調用。 第二,dubbo 不能解決的問題有: 我們的線上還有 php 或者其他開發語言的應用,它怎么調用容器化的 java 工程呢?? 容器化的工程如何對外網提供服務 ,如何把它放入 nginx 和 F5中呢?? 基于以上兩個需求、以及同一個工程的容器也要做負載均衡 ,我們引入了 consul ?+ consul-template ?+ registrator + haproxy,來做服務注冊和發現。 實施詳細流程如下: 第一步,每一臺 slave 節點上都會啟動一個 registrator 的容器,該容器檢測 docker 引擎的 unix socket 地址:/var/run/docker.sock,從中獲得該 slave 上所有容器的啟動、停止以及其他運行時相關的信息; 第二步,registrator 容器同時會把它獲取的其他容器的信息(IP、端口等)注冊到 consul 集群中,服務信息如下面的輸出: curl 172.28.128.3:8500/v1/catalog/service/python-micro-service [ ? { ? ? "Node":"host-1", ? ? "Address":"172.28.128.3", ? ? "ServiceID":"registrator:service1:5000", ? ? "ServiceName":"python-micro-service", ? ? "ServiceTags":null, ? ? "ServicePort":49154 ? }] 第三步,consul-template 組件從 consul 中獲得所有容器注冊的服務信息,應用相應的規則(如,區分為鏡像環境和生產環境)后,將容器提供的服務信息寫入 haproxy 中,并 reload haproxy 以生效配置。 第四步,client 端通過 DNS 中注冊的域名指向 haproxy 的地址,訪問到具體提供服務的容器。
附錄C: mesos(資源調度) marathon(服務編排) chronos(分布式計劃任務) docker(容器引擎) consul+registrator(服務注冊和發現) haproxy(負載均衡) prometheus(服務監控) nagios/zabbix(節點監控) salt(節點配置管理) cobbler(節點自動化裝機) ELK(日志收集分析)
本文檔適用人員:廣義上的技術人員 提綱:
? 首先,你要明白容器并不是虛擬機,雖然它可以解決虛擬機能夠解決的問題,同時也能夠解決虛擬機由于資源要求過高而無法解決的問題,但它真的不是虛擬機。以往我們的開發、配置管理、部署發布、監控報警思路都要跟著變。 其次,一開始注定只有一少部分工程遷移到容器私有云上,既然還有大多數應用服務還在虛擬機或物理機上,那么它們之間如何通訊就成了一個必須解決的問題。 那么,我們在構建基于容器的私有云以及相應的持續發布時,遇到并解決了哪些問題呢?
0x00?集裝箱還是卷掛載?
先拋出問題,下面這個選擇題你怎么選:| |
- 從貨運工人角度考慮,整體才是最經濟的。
- 這也導致裝卸復雜度增加。?
- 代碼放到 slave 節點的本地磁盤:那么必須要有一種機制,來確保每臺 slave 上代碼包版本的一致性,而且對于磁盤空間和網絡分發來講也是一種浪費(考慮一下 100 臺 slave,其中可能只有 10 臺需要運行這個版本的代碼)?
- 代碼放到分布式共享文件系統(如 ceph):它倒是解決了數據過度冗余以及一致性的問題,但分布式共享文件系統本身成為了『單點』,雖然可以設置多個副本。它的性能和可靠性都必須得到充分保障才行。?
0x01?Host Networking 還是 Bridge Networking?
網絡基礎
? Docker 現有的網絡模型主要是通過使用 Network namespace、Linux Bridge、iptables、veth pair 等技術實現的。(出處8)- Network namespace:它主要提供了網絡資源的隔離,包括網絡設備、IPv4/IPv6 協議棧、IP 路由表、防火墻、/proc/net 目錄、/sys/class/net 目錄、端口(socket)等。
- Linux Bridge:功能相當于物理交換機,為連在其上的設備(容器)轉發數據幀,如 docker0 網橋。
- Iptables:主要為容器提供 NAT 以及容器網絡安全。
- veth pair:兩個虛擬網卡組成的數據通道。在 Docker 中,用于連接 Docker 容器和 Linux Bridge。一端在容器中作為 eth0 網卡,另一端在 Linux Bridge 中作為網橋的一個端口。
容器的網絡模式
用來設置網絡接口的 docker run --net 命令,它的可用參數有四個:| 公司 | 網絡方案 | 備注 |
| 網易(2014) | tinc+quagga+pipework | Pipework 是對 Docker Bridge 的擴展,它由 200 多行 shell 腳本實現。通過使用 ip、brctl、ovs-vsctl 等命令來為 Docker 容器配置自定義的網橋、網卡、路由等。 |
| CoreOS(2014) | flannel | flannel 屬于隧道方案,UDP 廣播,VxLan。 |
| 大眾點評網(2015) | Bridge Networking 工作在 level 2 的模式,使公共 IP 得以暴露出來,這部分是做了定制的 | |
| 汽車之家(2015) | Bridge Networking | |
| 去哪兒(2015) | Host Networking | 『大吞吐量平臺下,bridge 模式性能測試都偏低,于是選擇了 host 模式』——20150915,徐磊 |
| 芒果TV(2015) | Macvlan | 屬于路由方案?!簭倪壿嫼?Kernel 層來看隔離性和性能最優的方案,基于二層隔離,所以需要二層路由器支持,大多數云服務商不支持,所以混合云上比較難以實現』——20150505,彭哲夫 |
| 新浪微博(2015) | Host Networking |
Docker網絡模型以后如何發展
Libnetwork 是 Docker 官方 2015年初推出的項目,旨在將 Docker 的網絡功能從 Docker 核心代碼中分離出去,形成一個單獨的庫。 Libnetwork 以插件的形式為 Docker 提供網絡功能,使得用戶可以根據自己的需求實現自己的 Driver 來提供不同的網絡功能。 Libnetwork 所要實現的網絡模型基本是這樣的: 用戶可以創建一個或多個網絡(一個網絡就是一個網橋或者一個 VLAN ),一個容器可以加入一個或多個網絡。 同一個網絡中容器可以通信,不同網絡中的容器隔離。 Docker 網絡的發展以后就都在這個項目上了。0x02?容器要固定IP嗎?
默認情況下,當 docker 啟動時,它會在宿主機器上創建一個名為 docker0 的虛擬網絡接口。它會從 RFC 1918 定義的私有地址中隨機選擇一個主機不用的地址和子網掩碼,并將它分配給 docker0。(出處9)所以,容器的 IP 是動態變化的。 于是乎大家一開始接觸 Docker 就紛紛提出給容器分配靜態 IP 的需求。看一下各大公司容器云技術棧對比,幾家歷史包袱較重的公司都選擇不讓上層應用感知到底層是 VM 還是容器,如360/點評/汽車之家,都改了docker 代碼,固定了容器 IP。 docker 官方對此需求的態度是,Docker maintainers prefers a more abstract way to separate user intent from operational intent. Based on this feedback and various other discussions on a flexible ip address management, we feel that having a pluggable IPAM will help a great deal. ? 上一章節里提到的?Pipework?可以做到讓容器有一個可以直接訪問的靜態 IP 地址,just like this:| If you’re using named Docker instances, then adding the IP address 10.40.33.21 to a Docker instance bind is as simple as: pipework br0 bind 10.40.33.21/24If you want to route out of 10.40.33.1, change it to: pipework br0 bind 10.40.33.21/24@10.40.33.1 (出處:https://opsbot.com/advanced-docker-networking-pipework/) |
0x03?容器內部如何獲取宿主機的IP?
容器啟動后,宿主機 IP 會被寫入容器的環境變量里。 容器內的程序可以從環境變量里讀取。 ——未完待續—— 附錄A:參考資源 1,知乎Docker話題,http://www.zhihu.com/topic/19950993; 2,2015,Docker終極指南(原作者German Jaber); 3,2015,Docker持續部署圖文詳解; 4,2015,使用Docker搭建Java Web運行環境; 5,2015,dockone上對代碼放里面還是外面的討論; 6,2013,dockerfile最佳實踐; 7,2015,集群規模下日志處理和網絡方案; 8,2015,Docker網絡詳解及Libnetwork前瞻; 9,docker官網講網絡配置,中文譯稿; 附錄B:術語簡單介紹 Registry/Repository/Image/Tag: Registry 存儲鏡像數據,并且提供拉取和上傳鏡像的功能。Registry 中鏡像是通過 Repository 來組織的,而每個 Repository 又包含了若干個 Image。
|
| Network settings: docker run --net 的四個參數進一步解釋如下: None: 將網絡模式設置為 none 時,這個 container 將不允許訪問任何外部 router。這個 container 內部只會有一個 loopback 接口,而且不存在任何可以訪問外部網絡的 router。 ? Bridge: 默認為 bridge 模式。此時在 host 上面將存在一個 docker0 的網絡接口,同時會針對 container 創建一對 veth 接口。其中一個 veth 接口是在 host 充當網卡橋接作用,另一個 veth 接口存在于 container 的命名空間中,并且指向 container 的 loopback。docker 會自動給這個 container 分配一個 IP,并且將 container 內的數據通過橋接轉發到外部。 如下圖(圖作者馮明振)所示: 容器 eth0 網卡從 docker0 網橋所在的 IP 網段中選取一個未使用的 IP,容器的 IP 在容器重啟的時候會改變。docker0 的 IP 為所有容器的默認網關。容器與外界通信為 NAT。 ? ? Host: 此時,這個 container 將完全共享 host 的網絡堆棧。host 所有的網絡接口將完全對 container 開放。container 的主機名也會存在于 host 的 hostname 中。這時,container 所有對外暴露的 port 和對其它 container 的 link,將完全失效。 ? ? Container: 此時,這個 container 將完全復用另一個 container 的網絡堆棧。 |
目前,我們容器管理集群的技術棧包括以下內容:
窩窩持續集成管理平臺在這些技術的基礎上,實現了我們的集群管理、容器管理、應用管理等業務流程。
歡迎訂閱我的微信訂閱號『老兵筆記』,請掃描二維碼關注: -EOF-總結
以上是生活随笔為你收集整理的容器私有云和持续发布都要解决哪些基础问题 第一集的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV之mixChannels()
- 下一篇: OC数据类型学习