SWARM大法好——Docker1.12 引擎使用體驗

背景

憑借敏捷開發部署理念的推行,相信對于很多人來說docker這項容器技術已經并不陌生,Docker 1.12引擎發布了快兩個月,新引擎中包含了許多特性。諸如: Swarm模式,容器集群的健康檢查,節點的身份加密,docker Service API調用,容器啟動的過濾匹配方式(constraint), docker的內建路由,以及支持在多平臺系統上運行docker(MAC、Windows、AWS、AZURE),以及一些插件升級等等. 特性之多,就連Docker 自己的產品經理也表示這次的新版本可能是公司有史以來變化最大的一次產品發布。

很長一段時間里,docker在集群模式的管理上一直廣受外界詬病。Docker服務自身只能在單臺host上進行操作,官方并沒有真正意義上的集群管理方案。直到現在1.12的出現, 引擎在多主機、多容器的集群管理上才有了進一步的改進和完善,版本自身內嵌了swarm mode集群管理模式。

本文主要是介紹一下swarm 集群管理模式的新特性,以及如何該模式下如何實現集群的搭建和服務部署。

Swarm cluster 模式新特性介紹

1. 批量創建服務

1.12引擎中多了docker service命令,和之前的docker run命令類似,但不同的是它能同時對多主機中的容器進行管理操作。下面就以1臺manager節點,5臺worker節點的swarm集群來闡述這些特性。

首先看下容器的創建:

$ docker network create -d overlay mynet

$ docker service create –replicas 3 –name frontend –network mynet –publish 80:80/tcp frontend_image:latest

$ docker service create –name redis –network mynet redis:latest

建立容器之前先創建一個overlay的網絡,用來保證在不同主機上的容器網絡互通的網絡模式,后面兩條命令用來在同一個名叫mynet的overlay網絡里新建三個相同的web容器副本,和一個 redis副本,并且每個web容器都提供統一的端口映射關系。就像這樣:


2. 強大的集群的容錯性

既然是集群,當然難免會出現某幾個節點故障的情況:

當三個web副本中的其中兩臺web節點宕機后,cluster會根據自己的服務注冊發現機制,以及之前設定的值–replicas 3,在集群中剩余的空閑節點上,重新拉起兩個web副本。不難看出,docker service其實不僅僅是批量啟動服務這么簡單,而是在集群中定義了一種狀態。Cluster會持續檢測服務的健康狀態并維護集群的高可用性。

新節點的分布示意圖如下:

3. 服務節點的可擴展性

Swarm Cluster不光只是提供了優秀的高可用性,同時也提供了節點彈性擴展的功能。當web這個容器組想動態擴展至六個節點個數時,只需執行$ docker service scale frontend=6就能立刻復制出三個新的副本出來。

眼尖的朋友可能注意到了,所有擴展出來的新web副本節點都run在原先的web節點下面,如果有需求想在每臺節點上都run一個相同的副本有沒有辦法呢?答案也是肯定的:

$ docker service create –mode=global –name extend_frontend frontend_image:latest

一條命令分分鐘搞定!

4. 調度機制

Docker1.12的調度機制也值得一提。

所謂的調度其主要功能是cluster的server端去選擇在哪個服務器節點上創建并啟動一個容器實例的動作。它是由一個裝箱算法和過濾器組合而成。每次通過過濾器(constraint)啟動容器的時候,swarm cluster 都會調用調度機制篩選出匹配約束條件的服務器,并在這上面運行容器。

還是拿剛剛那個例子來說,再加上–constraint參數,就能指定容器只run在服務器硬盤是SSD的節點上(前提是加入到cluster的節點,在啟動daemon時,本身需要加上參數 --label com.example.storage=”ssd”):

$ docker service create –replicas 3 –name frontend –network mynet –publish 80:80/tcp –constraint engine.labels.com.example.storage=ssd frontend_image:lastest

搭建一個swarm集群

有了以上這些介紹,我們對swarm cluster 的一些新特性應該有了初步的了解 ,下面再看一個模擬網站rolling_update的實例,相信這也是許多平時做版本發布的devops們真正想要看到的東西。

1. 搭建一個swarm集群

準備三臺機器

Node1:192.168.133.129

Node2:192.168.133.137

Node3:192.168.133.139

在構建一個swarm cluster前,需在cluster節點的防火墻上放行2377/tcp(cluster 管理端口)、7946/udp(節點間通信端口)、4789/udp(overlay 網絡端口)

首先在node1上運行 $docker swarm init 去啟動一臺cluster manager節點,然后在任意需要添加進集群的節點上運行docker swarm join –token *** 192.168.133.129:2377 就能將節點加入到cluser(加入到集群里的節點身份可在后面自由設置成worker或manager)。現在swarm cluster的節點就像下面的圖一樣,箱子都準備好了,就差貨物往里面裝了。

通過$docker node ls能看到所有swarm節點的運行狀態:

P.S.Swarm cluster的創建過程包含以下三個步驟:

發現Docker集群中的各個節點,收集節點狀態、角色信息,并監視節點狀態的變化

初始化內部調度(scheduler)模塊

創建并啟動API監聽服務模塊

一旦創建好這個cluster,就可以用命令docker service批量對集群內的容器進行操作。搭建cluster只有兩步,是不是非常酷?

2. 制作一個演示用的demo鏡像

鏡像中存放一個python寫的簡單的http web服務:env.py,目的是顯示容器的containerID:

from flask import Flask

import os

app = Flask(__name__)

@app.route("/")

def env():

return os.environ["HOSTNAME"]

app.run(host="0.0.0.0")

3. 用swarm mode創建service task

有了這個鏡像,然后通過docker service create命令去創建一個名叫test的task:

$ docker service create --name test -p 5000:5000 demo python env.py

用docker ps看一眼

欸?為什么沒有起來呢?再用docker service ls 查看task的狀態:

注意這個REPOLICAS的值,0/1說明docker create 已經創建了一個副本但是還沒有起來,稍等一會再運行一遍命令:

補充:

一些情況下已經運行了容器,可是運行docker ps在本機還是看不到容器,為什么呢?

其實,docker 會根據當前每個swarm節點的負載判斷,在負載最優的節點運行這個task任務,用docker service ps + taskID 可以看到任務運行在哪個節點上。

好了container已經起來了并且運行在node1上

用瀏覽器打開地址能看到容器對應的ID:

4. 增加service節點

有了單個容器實例之后,下一步再嘗試下動態擴展實例個數

$ docker service scale test=6

Node1:

Node2

Node3

一條命令讓現在swarm cluster里三臺節點,每臺都運行了兩個test副本實例。

此時你是不是已經留意到,一個天然的HA集群出現了。docker會把對每個host的http請求依據輪詢算法,均勻地發送到每個task副本上。

5. 模擬其中一個swarm cluster節點離線的情況

正常來講讓一個swarm cluster中的一個node退出集群的方式,是在要推出的節點上運行$ docker swarm leave命令,但是為了讓實驗更瘋狂,我在node3上直接stop docker的daemon

再去剩余兩個節點上任意一個查看task狀態:

原本在node3上運行的兩個test任務:test3、test4,分別在node1和node2兩臺host上被來起來了。整個副本遷移的過程無需人工干預,遷移后原本的集群的load balance依舊好使!

負載均衡和服務發現

測試中只是每個host節點中的containers之間實現了負載均衡,生產環境在做rolling_update時,必須確保持在同一時刻,至少有一個容器能正常提供服務。

那么問題來了,有沒有辦法能自定義檢測到每個節點中應用的運行狀態,如果其中一個服務運行不正常,則立即通知前面做反向代理的HTTP服務器,讓它自動摘除不正常的節點,等到節點修復后又重新自動注冊節點信息到負載均衡器上呢?并且全程沒有人工干預。

答案是肯定的。這里介紹兩種實現服務注冊發現的方式:

1. docker1.12內置的服務注冊發現機制

講到docker的服務發現機制之前,不得不提overlay網絡,這個特性最早出現在docker1.9版本發布的功能特性中,他的特點就是能夠使不同宿主機上的容器進行網絡互通。

而在此之前,如果要做到位于不同主機的容器之間通信,一般有幾種方法:

使用端口映射:直接把容器的服務端口映射到主機上,主機直接通過映射出來的端口通信

把容器放到主機所在的網段

通過第三方工具flannel,weave 或者 pipework 等,這些方案一般都是通過 SDN 搭建 overlay 網絡達到容器通信的

Docker1.12中依然繼承了這個overlay的網絡模型,并且為自己的服務注冊發現提供了強有力的網絡保障。

Docke的注冊發現原理其實是采用一個分布式的Key-Value Storage作為存儲的抽象層。Docker 1.12 提供了內置的 Discovery 服務, 這樣集群的搭建不需要再依賴外部的 Discovery 服務, 比如 consul 或 etcd。(當然swarm mode下也可以使用這些Discovery 服務,具體的下個小節會詳細介紹)。目前Swarm mode提供了6種discovery機制:Token(默認)、Node、File、Consul、Etcd、Zookeeper。其中有兩種方式的節點需要對配置文件或者其他相關內容進行維護,其他服務發現僅需要通過join命令行來完成。這兩種方式分別是Node和File discovery。

好了繼續實驗,首先創建一個自定義的overlay網絡:

$docker network create -d overlay test

然后在同一個網絡上分別吧應用容器和http服務容器起來:

$ docker service create --name test -p 5000:5000 --replicas 6 –network test demo python env.py

$ docker service create --name nginx --replicas 3 --network test -p 80:80 nginx-2

Nginx容器的default.conf配置如下,其中test:5000對應之前由docker service create出來的test任務,docker 引擎已經將task name對應的ip關系映射成內部的DNS解析。

server {

listen? ? ? 80;

server_name? localhost;

access_log? /var/log/nginx/log/host.access.log? main;

location / {

#? ? root? /usr/share/nginx/html;

#? ? index? index.html index.htm;

proxy_pass http://test:5000;

}

error_page? 500 502 503 504? /50x.html;

location = /50x.html {

root? /usr/share/nginx/html;

}

}

至此全部操作完成,當瀏覽器訪問http://node2后,http請求根據VIP負載均衡算法均勻的分配至3個swarm cluster node上的6個python容器去響應請求,并且無論哪個后端容器掛了,只要三臺docker swarm cluster的節點不同時出事,都不會影響正常 的網站服務。

對于上述的VIP負載均衡算法做下補充說明:docker1.12使用的是linux自身的IPVS作為負載均衡方式。IPVS實則linux內核中一個叫做ip_vs的負載均衡模塊。不同于DNS負載均衡將IP列表順序輪詢,IPVS會將負載均勻的分發到每個容器。IPVS是四層的轉發者,能夠轉發TCP、UDP、DNS并且支持八種負載均衡算法。

2. docker結合外置的配置存儲服務

這類的服務有多種選擇,consul和etcd,zookeeper,這里以consul為例。consul是一款服務注冊發現的軟件,自身是一個key/value的store。在docker1.12發布之前,許多人選擇用它和docker一起結合來提供一個高可擴展性的web服務。

開始實驗前要先修改docker的主配置文件,使用consul替換缺省的docker自身的key/value store中心

ExecStart=/usr/bin/dockerd --registry-mirror=http://057aa18c.m.daocloud.io -H unix:///var/run/docker.sock --cluster-store=consul://192.168.133.137:8500

1)還是在上面演示的幾臺機器中選一臺node2來做consul的server(consul的server最好也配置成cluster的模式,實現consul自己的HA,本文為了快速介紹功能就不搭建了,只起一個節點)。

還需注意一點,本文中選用了一臺業務節點作為配置存儲服務的運行位置,不過通常建議是這種base service能與運行業務容器的節點分開,使用獨立的服務節點,這樣才能確保所有運行業務容器的節點是無狀態的,可以被平等的調度和分配運算任務。

2)$docker run –d --restart=always -h node -p 8500:8500 -p 8600:53/udp progrium/consul -server -bootstrap -advertise 192.168.133.137 -log-level debug

Concul自帶UI,打開192.168.133.137:8500你就能看到,consul啟動后會開啟兩個端口,一個事53/udp,還有一個是8500/tcp,從dashboard上都能看到他們的狀況。


3)啟動 registrator 容器,目的是注冊 docker container 的信息到consul 集群中

$docker run -d --restart=always -v /var/run/docker.sock:/tmp/docker.sock -h 192.168.133.137 gliderlabs/registrator consul://192.168.133.137:8500

4)啟動一個最簡單的http服務器驗證是否已經將自身信息注冊到了consul中,實現了自動發現的功能:

$docker run -d -p 7070:80 --name httpd httpd


5)最后在測試機上安裝 consul-template 來從 consul 獲取數據,更新本地的某個模板配置文件。

安裝consul-template:

$ curl https://releases.hashicorp.com/consul-template/0.15.0/consul-template_0.15.0_linux_amd64.zip -o consul-template.zip && unzip consul-template.zip && mv ./consul-template /usr/bin/

生成模板文件:

$ echo -e '{{range service "httpd"}}\nserver {{.Address}}:{{.Port}}{{end}}' > /tmp/consul.ctmpl

填寫模板:

$consul-template -consul 192.168.133.137:8500 -template "/tmp/consul.ctmpl:/tmp/consul.result" --once

現在再把httpd容器stop掉,重新執行填寫模板的命令。

可以看到注冊進consul的容器信息被填寫進模板當中了! 如果把模板做成nginx的配置文件,就能依據consul來檢測容器是否啟動從而動態更新nginx的配置文件了。

upstream consul_nodes {

server 192.168.133.137:7070;

server 192.168.133.139:7070;

}

location / {

root? html;

index? index.html index.htm;

proxy_pass http://consul_nodes;

}

以上兩種是實現服務注冊發現的方式,都列出來給各位看看,對比之下看得出來在配置的容易程度方面,docker1.12自帶的還是要占有比較明顯的優勢的。

滾動部署

從前docker的舊版本下,容器必須手動藍綠部署,或者手寫腳本實現滾動升級。1.12有了滾動更新以后,我們就不需要把更新規則寫成腳本去實現透明部署。Swarm mode中,服務可以更新逐步節點,并且控制服務的部署之間的延遲到不同的節點集合。如果出現任何錯誤,能夠馬上回滾上一個任務,回到先前版本的服務。

當現在要更新test這個task所引用的鏡像時,可以這么操作:

$docker service update --update-parallelism? 2 --image demo:2.0 --update-delay 10s test

其中--update-parallelism參數用來指定最大同步更新任務數。這意味著我們可以安全透明的更新容器副本。關于透明,當然要確保你的容器是向后兼容的,否則最好銷毀舊的容器,再去更新所有的容器。

然后容器就會每隔10秒跟新2個容器,直至30秒后此次更新操作完畢。


最后提醒一句,docker 1.12的swarm cluster的功能選項是可開始,不是必須選項。原先的單主機運行方式依然保留。但是看到了這些炫酷的新特性你還舍得關閉這個選項嗎?

Docker生態已經逐漸從單純的鏡像生態,衍生到容器集群的管理,docker的前途依舊一片光明。


本文作者:王歡(點融黑幫),目前就職于點融網infra團隊的DevOps team。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,828評論 18 139
  • 其實寫排序算法的博客已經有很多了,其中不乏某些細心的博主去仔細講解各種排序的過程,甚至有使用gif圖來表現排序過程...
    qufl閱讀 2,164評論 0 51
  • 感受自己 很久前,我就不再固定每天寫一篇文章了,自那以后我就只有在心情有所波瀾的時候才會記錄一篇文章。 現在一切都...
    雨過天晴L閱讀 232評論 1 0
  • 湘江的水 南國的風 赤子的心 青春的夢 起起落落 霧靄迷蒙 微風徐徐 梅園暗香
    清山的山閱讀 243評論 0 0
  • 最近聽到莫文蔚的當你老了,又查了原來的詩句,感覺還是很溫暖很好聽的。35歲的時候就初初體會“生老病死”著實是人生中...
    jupitergranit閱讀 182評論 0 0