背景html
憑藉敏捷開發部署理念的推行,相信對於不少人來講docker這項容器技術已經並不陌生,Docker 1.12引擎發佈了快兩個月,新引擎中包含了許多特性。諸如: Swarm模式,容器集羣的健康檢查,節點的身份加密,docker Service API調用,容器啓動的過濾匹配方式(constraint), docker的內建路由,以及支持在多平臺系統上運行docker(MAC、Windows、AWS、AZURE),以及一些插件升級等等. 特性之多,就連Docker 本身的產品經理也表示此次的新版本多是公司有史以來變化最大的一次產品發佈。node
很長一段時間裏,docker在集羣模式的管理上一直廣受外界詬病。Docker服務自身只能在單臺host上進行操做,官方並無真正意義上的集羣管理方案。直到如今1.12的出現, 引擎在多主機、多容器的集羣管理上纔有了進一步的改進和完善,版本自身內嵌了swarm mode集羣管理模式。python
本文主要是介紹一下swarm 集羣管理模式的新特性,以及如何該模式下如何實現集羣的搭建和服務部署。linux
Swarm cluster 模式新特性介紹nginx
1. 批量建立服務web
1.12引擎中多了docker service命令,和以前的docker run命令相似,但不一樣的是它能同時對多主機中的容器進行管理操做。下面就以1臺manager節點,5臺worker節點的swarm集羣來闡述這些特性。redis
首先看下容器的建立:算法
$ docker network create -d overlay mynetdocker
$ docker service create –replicas 3 –name frontend –network mynet –publish 80:80/tcp frontend_image:latestflask
$ 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任務:test三、test4,分別在node1和node2兩臺host上被來起來了。整個副本遷移的過程無需人工干預,遷移後本來的集羣的load balance依舊好使!
--- 第二篇 ---
上篇對node一、node二、node3的請求是經過綁host的方式測試的,本期咱們接着往下聊。
負載均衡和服務發現
測試中只是每一個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的前途依舊一片光明。