[TOC]
Swarm簡介和使用介紹
1 Swarm介紹
1.1 簡介
Swarm 在 Docker 1.12 版本之前屬于一個獨立的項目,在 Docker 1.12 版本發(fā)布之后,該項目合并到了 Docker 中,成為 Docker 的一個子命令。目前,Swarm 是 Docker 社區(qū)提供的唯一一個原生支持 Docker 集群管理的工具。它可以把多個 Docker 主機組成的系統(tǒng)轉(zhuǎn)換為單一的虛擬 Docker 主機,使得容器可以組成跨主機的子網(wǎng)網(wǎng)絡。
2016年核心團隊發(fā)現(xiàn)中央服務的擴展被限制之后,Swarm 在內(nèi)部被再次重新設(shè)計為Swarm2,使用了去中心化的集群設(shè)計,允許構(gòu)造數(shù)千個節(jié)點的集群;隨后又發(fā)布了SwarmKit(可以作為任規(guī)模的分布式服務的編排工具包),將其合并到了Docker Engine,Docker Swarm在設(shè)計上遵從了可插拔的設(shè)計思想,安裝集群只需要啟動幾個docker就可以完成
Docker三劍客:Docker Swarm、 Docker Machine、 Docker Compose(它們可以無縫的集成)
Docker Machine:預配機器,可以是虛擬機器也可以是物理機器,并可以在若干純物理機器上運行Docker容器 (Docker Engine和Docker Machine介紹)
Docker Compose:用戶可以快速定義Dockerfile,通過簡單但是強大的YAML語法描述行為,并且只需要把這些文件“組合”起來就可以啟動應用程序(Docker-Compose簡介安裝使用)
Docker Swarm:強大的集群工具,讓用戶以為自己管理的是單個巨大的Docker宿主機,而這個宿主機是由很多Docker宿主機組成的
1.2 特性
官網(wǎng)的特性
與Docker Engine集成
使用分散設(shè)計:去中心化設(shè)計,可大規(guī)模部署
聲明式服務模式
彈性服務:通過schedule(調(diào)度器)Constraint(約束條件)affinity(共同關(guān)系)彈性服務
Desired state reconciliation:管理節(jié)點收集集群中所有的信息,進行感知和調(diào)度
多主機聯(lián)網(wǎng):指定overlay 網(wǎng)絡,swarm管理器自動將地址分配給覆蓋網(wǎng)絡上的容器
服務發(fā)現(xiàn):service
負載均衡:使用內(nèi)建DNS Round-Robin實現(xiàn)集群內(nèi)的負載均衡,也支持外部負載均衡
回滾更新:高可用和故障恢復機制意味著用戶可以創(chuàng)建超過一個master的Swarm
Swarm的特性:
1.工作節(jié)點的注冊和發(fā)現(xiàn)
2.管理節(jié)點收集集群中所有的信息
3.管理節(jié)點支持HA
4.管理節(jié)點能感知集群的變化,在節(jié)點掛掉后重新調(diào)度上面的container
5.提供filter和scheduler的調(diào)度策略調(diào)度集群里的容器
1.3 概念
swarm:是一組docker引擎的集群
node:是單個docker引擎的實例,可以在一個物理機上也可以在多個
application:是應用
manager node:部署應用的時候會有一個manager node節(jié)點
Worker nodes:對應的就是Worker nodes
service:然后service是一堆被workder執(zhí)行的任務
replicated services:是負載均衡節(jié)點
global services:則是全局的,在所有節(jié)點上都會執(zhí)行的一個服務
task:一個task就是一個docker的容器,是Swarm的工作單元
- docker swarm:集群管理,子命令有 init, join,join-token, leave, update
- docker node:節(jié)點管理,子命令有 demote, inspect,ls, promote, rm, ps, update
- docker service:服務管理,子命令有 create, inspect, ps, ls ,rm , scale, update
- docker stack/deploy:用于多應用部署,是創(chuàng)建多容器的應用程序,而不是單個容器的二進制結(jié)果
2 使用swarm模式
前提
- 兩臺網(wǎng)絡互通的宿主機
- 安裝1.12或更高版本的docker
- 管理節(jié)點的IP地址
- 開啟宿主機之間的端口(TCP端口2377集群管理端口)
2.1 不使用Docker Machine工具
| 宿主機名稱 | IP |
|---|---|
| master | 192.168.64.55 |
| worker | 192.168.64.56 |
2.1.1 步驟
- 在swarm模式下初始化一個docker引擎的集群
- 添加節(jié)點至swarm中
- 發(fā)布一個應用服務到swarm中
- 當運行起來之后進行swarm管理
2.1.2 創(chuàng)建swarm集群
創(chuàng)建管理節(jié)點
#docker swarm init --advertise-addr <MANAGER-IP>:<PORT>
$docker swarm init --advertise-addr 192.168.64.55:2377
#查看詳情
$docker info
#查看節(jié)點
$docker node ls
添加節(jié)點到集群
#在節(jié)點機器上運行如下命令:docker swarm join --token <TOKEN> <MANAGER-IP>:<PORT>
$docker swarm join --token SWMTKN-1-3s7sfvjom026g3eanmt6zym9uxr4qluixl7imuoap4kxbejyqt-da1u66rfp5aiy35baqou7ve8x 192.168.64.55:2377
#在manager節(jié)點上查看節(jié)點
$docker node ls

2.1.3 發(fā)布服務
#在manager上執(zhí)行如下命令
$docker service create --replicas 1 --name helloBoy alpine ping bilibili.com
-
docker service create命令創(chuàng)建一個 service. -
--name標簽命名service為helloBoy. -
--replicas標簽來詳細聲明1個運行實體. - 參數(shù)
alpine ping bilibili.com定義執(zhí)行pingg bilibili.com作為alpine容器的服務.
#使用docker service ls查看服務
$docker service ls

#使用docker service inspect審查服務
$docker service inspect --pretty helloBoy
#使用docker service ps <SERVICE-ID>查看服務運行在哪個節(jié)點上
$docker service ps helloBoy

#添加更多實例:docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>
$docker service scale helloBoy=5
$docker service ps helloBoy

#刪除service
$docker service rm helloBoy
2.1.4 滾動升級
#發(fā)布redis服務
#--update-parallelism標簽配置服務中同步升級的任務數(shù)量 --update-delay標簽配置一個服務任務或一系列任務升級的時延:并列度為1,延遲10s,就是一個升完,下一個升,就是所謂的滾動升級了
$docker service create --replicas 3 --name redis --update-delay 10s --update-parallelism 1 redis:3.0.6
$docker service ls
$docker service ps redis

#升級開始
$docker service update --image redis:3.0.7 redis
$docker service ls
$docker service ps redis
$docker service inspect --pretty redis

2.1.5 DRAIN節(jié)點
先搞個3.0.6的redis集群
$docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6

#drain pbsslave節(jié)點
#先查看
$docker node inspect --pretty pbsslave
$docker node update --availability drain pbsslave
$docker node inspect --pretty pbsslave

2.1.6 恢復node
$docker node update --availability active pbsslave
$docker node inspect --pretty pbsslave
2.1.7 使用swarm mode路由網(wǎng)格
ingress routing mesh是個大家伙都參與了的網(wǎng)狀網(wǎng),你就這么理解就好了
Port 7946 TCP/UDP for container network discovery,7946是容器的網(wǎng)絡發(fā)現(xiàn)端口,TCP
Port 4789 UDP for the container ingress network,4789是容器的ingress網(wǎng)絡,UDP
#創(chuàng)建一個my-web的servie然后對外暴露8080端口,內(nèi)部監(jiān)聽的是80端口
#然后用的image叫nginx
#訪問node上的8080端口,任何一個node節(jié)點上的,swarm就會自動幫你路由到對應的nginx上去
$docker service create --name my-web --publish 8080:80 --replicas 2 nginx
#對已有的服務
$docker service update --publish-add <PUBLISHED-PORT>:<TARGET-PORT> <SERVICE>
#這兩個是TCP ONLY的命令,相互等價
$docker service create --name dns-cache -p 53:53 dns-cache
$docker service create --name dns-cache -p 53:53/tcp dns-cache
#同時使用TCP和UDP
$docker service create --name dns-cache -p 53:53/tcp -p 53:53/udp dns-cache
#僅僅使用UDP
$docker service create --name dns-cache -p 53:53/udp dns-cache
2.1.8 添加全局的網(wǎng)絡
#添加 overlay網(wǎng)絡,讓service和service之間可以通訊
#管理節(jié)點上,添加overlay網(wǎng)絡my-network
$docker network create --driver overlay my-network
#加--network參數(shù),就可以讓所有節(jié)點都加入這個網(wǎng)絡里去了
$docker service create --replicas 3 --network my-network --name my-web nginx
2.1.9 回滾
#加一個 --rollback參數(shù)
$docker service update --rollback --update-delay 0s my_web
2.2 使用Docker Machine工具
在VirtualBox中使用Docker Machine管理主機
Docker Machine:Docker 三劍客之一,是一個工具,用來在虛擬主機上安裝Docker Engine,并使用 docker-machine命令來管理這些虛擬主機
| 宿主機名稱 | IP |
|---|---|
| manager1 | 192.168.64.72 |
| worker1 | 192.168.64.73 |
2.2.1 安裝Docker Machine
Docker Machine可以安裝在Mac、Windows、Linux上
在macOS和Windows上,當您安裝Docker for Mac,Docker for Windows或Docker Toolbox時,Machine將與其他Docker產(chǎn)品一起安裝。
Linux上需要安裝virtualbox作為驅(qū)動
1) 安裝docker machine
$curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine &&
chmod +x /tmp/docker-machine &&
sudo cp /tmp/docker-machine /usr/local/bin/docker-machine
#查看版本
$docker-machine -v
#查看虛擬機列表
$docker-machine ls
2) docker-machine命令
- help 查看幫助信息
- active 查看活動的Docker主機
- config 輸出連接的配置信息
- create 創(chuàng)建一個Docker主機
- env 顯示連接到某個主機需要的環(huán)境變量
- inspect 輸出主機更新信息
- ip 獲取Docker主機地址
- kill 停止某個Docker主機
- ls 列出所有管理的Docker主機
- regenerate-certs 為某個主機重新成功TLS認證信息
- restart 重啟Docker主機
- rm 刪除Docker主機
- scp 在Docker主機之間復制文件
- ssh SSH到主機上執(zhí)行命令
- start 啟動一個主機
- status 查看一個主機狀態(tài)
- stop 停止一個主機
- upgrade 更新主機Docker版本為最新
- url 獲取主機的URL
以下內(nèi)容是安裝virtualbox,配置使用驅(qū)動virtualbox,執(zhí)行遇到錯誤,可以改成generic作為驅(qū)動,進行集群創(chuàng)建,可以直接調(diào)到2.2.2創(chuàng)建集群開始
3) 安裝驅(qū)動virtualbox
參考:用docker-machine創(chuàng)建虛擬主機
需要給 Docker Machine 提供對應的驅(qū)動,這樣才能夠在上面安裝新的虛擬機,
例如可以安裝:
vmware 的產(chǎn)品 vSphere:
--driver vmwarevsphereVirtualBox:
--driver virtualbox
$docker-machine create --driver virtualbox manager1
#出錯:Please recompile the kernel module and install it by\\n\\n
#被提示The vboxdrv kernel module is not loaded, 啟動一下Virtualbox的Service吧
$/usr/lib/virtualbox/vboxdrv.sh setup
#提示需要安裝gcc和kernel-devel-3.10.0-693.el7.x86_64
$yum install -y gcc make
$yum install -y kernel-devel-3.10.0-693.el7.x86_64
#再次啟動啟動一下Virtualbox的Service
$/usr/lib/virtualbox/vboxdrv.sh setup

#繼續(xù)嘗試
$docker-machine create --driver virtualbox manager1
#出錯:Error with pre-create check: "This computer doesn't have VT-X/AMD-v enabled. Enabling it in the BIOS is mandatory"
#設(shè)置處理器的虛擬化引擎首選模式為"Intel VT-x/EPT 或AMD-V/RVI"及"虛擬化Intel VT-x/EPT 或AMD-V/RVI(V)"

#繼續(xù)嘗試
$docker-machine create --driver virtualbox manager1
#無法建立ssh服務
#重啟virtualbox服務 /usr/lib/virtualbox/vboxdrv.sh restart
錯誤:225
http://bob-zhangyong.blog.163.com/blog/static/176109820163278754727/
用 docker-machine ssh default 無法連接到 虛擬機,提示 exit status 255 錯誤。
猜測原因是 在virtual box 中 取消了 NAT 網(wǎng)絡。
繼續(xù)在網(wǎng)上找資料發(fā)現(xiàn)可以使用-d generic驅(qū)動,制定目標host的IP和用戶
#其他的驅(qū)動
$docker-machine create -d generic --generic-ip-address=192.168.64.72 --generic-ssh-user=root test
$docker-machine create -d generic --generic-ip-address=192.168.64.73 --generic-ssh-user=root test

-d driver #指定基于什么虛擬化技術(shù)的驅(qū)動
--generic-ip-address #指定要安裝宿主機的IP,這里是本地的IP。也就是說,你也可以給別的主機裝Docker,前提是SSH root用戶免交互登錄或私鑰認證
--generic-ssh-user #SSH的用戶
--generic-key-key #指定私鑰來實現(xiàn)免交互登錄
參考:Docker Machine快速安裝Docker環(huán)境(二)
2.2.2 創(chuàng)建集群
首先使用 Docker Machine 創(chuàng)建一個虛擬機作為 manger 節(jié)點
#指定使用generic驅(qū)動,將該機器命名為manager1
$docker-machine create -d generic --generic-ip-address=192.168.64.72 --generic-ssh-user=root manager1
$docker-machine create -d generic --generic-ip-address=192.168.64.73 --generic-ssh-user=root worker1
#查看可用的機器
$docker-machine ls
#查看manager1的環(huán)境變量
$docker-machine env manager1
#復制最后一行,用本機docker客戶端指向manager1的docker(設(shè)置一些 Docker 客戶端使用的環(huán)境變量,從而讓本機的 Docker 客戶端可以與遠程的 Docker 服務器通信)
$eval $(docker-machine env manager1)
#查看當前活躍的機器:*表示目前這臺機器已經(jīng)在使用了
$docker-machine active

#通過ssh到這個節(jié)點并驗證運行的進程來確認設(shè)置信息
$docker-machine ssh manager1 ps aux | grep docker
#本例使用 Docker Machine 來連接虛擬機
#把 manager1 加入集群: --listen-addr 指定監(jiān)聽的 ip 與端口
$docker-machine ssh manager1 docker swarm init --listen-addr 192.168.64.72:2377 --advertise-addr 192.168.64.72
$docker-machine ssh worker1 docker swarm join --token SWMTKN-1-44oi6hca2aej9zf5r6v08yyppysniudl8vjzota23eem9078j0-4hb326sah20vuul4gfbwo5zlj 192.168.64.72:2377

#集群初始化成功,現(xiàn)在我們新建了一個有兩個節(jié)點的“集群”,現(xiàn)在進入其中一個管理節(jié)點查看
$docker-machine ssh manager1 docker node ls

現(xiàn)在每個節(jié)點都歸屬于 Swarm,處在了待機狀態(tài)。manager1 是leader,worker1 是worker
可以繼續(xù)添加虛擬機
$docker-machine create -d generic --generic-ip-address=115.159.192.111 --generic-ssh-user=root smoker
$docker-machine ls
$docker-machine env smoker
$docker-machine ssh smoker docker swarm join --token SWMTKN-1-44oi6hca2aej9zf5r6v08yyppysniudl8vjzota23eem9078j0-4hb326sah20vuul4gfbwo5zlj 192.168.64.72:2377
$$docker-machine ssh manager1 docker node ls

至此使用Docker-machine創(chuàng)建虛擬機完畢,添加了三個節(jié)點,一個manager,連個worker
2.2.3 建立跨主機網(wǎng)絡
#查看網(wǎng)絡,可以看到在swarm上默認已有一個名為ingress的overlay 網(wǎng)絡, 默認在swarm里使用
$docker-machine ssh manager1 docker network ls

#創(chuàng)建一個新的overlay網(wǎng)絡
$docker-machine ssh manager1 docker network create --driver overlay swarm_test
$docker-machine ssh manager1 docker network ls

這樣一個跨主機網(wǎng)絡就搭建好了,但是現(xiàn)在這個網(wǎng)絡只是處于待機狀態(tài),下一節(jié)在這個網(wǎng)絡上部署應用
2.2.4 在跨主機網(wǎng)絡上部署應用
首先我們上面創(chuàng)建的節(jié)點都是沒有鏡像的,因此我們要逐一 pull 鏡像到節(jié)點中
$docker-machine ssh manager1 docker pull nginx
$docker-machine ssh worker1 docker pull nginx
$docker-machine ssh smoker docker pull nginx

上面使用 docker pull 分別在三個個虛擬機節(jié)點拉取 nginx鏡像。接下來要在三個節(jié)點部署一組 Nginx 服務
#部署的服務使用 swarm_test 跨主機網(wǎng)絡
$docker-machine ssh manager1 docker service create --replicas 2 --name helloworld --network=swarm_test nginx
#查看服務狀態(tài)
$docker-machine ssh manager1 docker service ls

#查看 helloworld 服務詳情
$docker-machine ssh manager1 docker service ps helloworld
#看到兩個實例分別運行在兩個節(jié)點

#進入兩個節(jié)點,查看服務狀態(tài)
$docker-machine ssh manager1 docker ps -a
$docker-machine ssh worker2 docker ps -a

記住上面這兩個實例的名稱?,F(xiàn)在我們來看這兩個跨主機的容器是否能互通:
首先使用 Machine 進入 manager1 節(jié)點,然后使用 docker exec -i 命令進入 helloworld.1 容器中 ping 運行在 worker2 節(jié)點的 helloworld.2 容器
$docker-machine ssh manager1 docker exec -i helloworld.2.f6uumx0l2veyx6xr7sag46cg1 ping
然后使用 Machine 進入 worker2 節(jié)點,然后使用 docker exec -i 命令進入 helloworld.2 容器中 ping 運行在 manager1 節(jié)點的 helloworld.1 容器
$docker-machine ssh worker2 docker exec -i helloworld.1.uvun0qur61ickqedh5ijzyfk7 ping helloworld.2.f6uumx0l2veyx6xr7sag46cg1
出錯:

理論上是可以ping通的,這里假設(shè)他兩ping通了
此測試結(jié)論:兩個跨主機的服務集群里面各個容器是可以互相連接的
2.2.5 Swarm 自動服務發(fā)現(xiàn)
以上是Swarm 集群的部署方法,現(xiàn)在來搭建一個可訪問的 Nginx 集群。體驗最新版的 Swarm 所提供的自動服務發(fā)現(xiàn)與集群負載功能
#首先刪掉上一節(jié)我們啟動的helloworld服務
$docker-machine ssh manager1 docker service rm helloworld
#然后在新建一個服務,提供端口映射參數(shù),使得外界可以訪問這些 Nginx 服務
$docker-machine ssh manager1 docker service create --replicas 2 --name helloworld -p 7080:80 --network=swarm_test nginx
#查看服務運行狀態(tài)
$docker-machine ssh manager1 docker service ls
不知你有沒有發(fā)現(xiàn),雖然我們使用 --replicas 參數(shù)的值都是一樣的,但是上一節(jié)中獲取服務狀態(tài)時,REPLICAS 返回的是 0/2,現(xiàn)在的 REPLICAS 返回的是 2/2
同樣使用 docker service ps 查看服務詳細狀態(tài)時(下面輸出已經(jīng)手動調(diào)整為更易讀的格式),可以看到實例的 CURRENT STATE 中是 Running 狀態(tài)的,而上一節(jié)中的 CURRENT STATE 中全部是處于 Preparing 狀態(tài)
#查看服務helloworld列表
$docker-machine ssh manager1 docker service ps helloworld

這就涉及到 Swarm 內(nèi)置的發(fā)現(xiàn)機制了,目前 Docker 1.12 中 Swarm 已經(jīng)內(nèi)置了服務發(fā)現(xiàn)工具,我們不再需要像以前使用 Etcd 或者 Consul 這些工具來配置服務發(fā)現(xiàn)。對于一個容器來說如果沒有外部通信但又是運行中的狀態(tài)會被服務發(fā)現(xiàn)工具認為是 Preparing 狀態(tài),本小節(jié)例子中因為映射了端口,因此有了 Running 狀態(tài)。
2.2.6 Swarm 集群負載
現(xiàn)在我們來看 Swarm 另一個有趣的功能,當我們殺死其中一個節(jié)點時,會發(fā)生什么。
#首先 kill 掉 worker1 的實例
$docker-machine ssh worker1 docker kill helloworld.1.x5uzksc1ej6xb05zz8y9ttbs5
#查看服務狀態(tài)
$docker-machine ssh manager1 docker service ps helloworld
可以看到即使我們 kill 掉其中一個實例,Swarm 也會迅速把停止的容器撤下來,同時在節(jié)點中啟動一個新的實例頂上來。這樣服務依舊還是兩個實例在運行

2.2.7 scale 命令
添加更多實例可以使用 scale 命令
$docker-machine ssh manager1 docker service scale helloworld=3

想減少實例數(shù)量,一樣可以使用 scale 命令
$docker-machine ssh manager1 docker service scale helloworld=2
參考
1 Swarm容器編排與Docker原生集群---電子工業(yè)出版社
5 Swarm入門
2017-12-11-Boy