Docker Swarm是在Docker 1.12版本之後添加的容器集羣管理工具,可以統一管理分佈在不同主機的多個容器。相比起Kubenetes,Docker Swarm無需額外安裝,只要有較新版本的Docker就可以使用。如果你嘗試過搭建Kubenetes,就知道這差別有多大。之前趁著參加Dell EMC的比賽學習實踐了一把Docker Swarm,感覺真不愧是Docker的自帶工具,一如既往的簡單好用。在這裡總結下它用到的一些科技原理和使用方法。
設計架構
因為是集成在Docker之中,由Docker Client向Swarm發送指令。每個Docker engine實例稱為一個Node,既可以是物理機,也可以是虛擬機器。分為manager和worker。worker只負責接收並執行任務,manager在此基礎上還要接收用戶指令,服務調度,服務發現…
另一個重要的概念是service,通常服務是一個大的應用分割出來的小的功能單元(microservice)。比如一個web應用中,nginx是一個service,mysql是一個service,php是一個service。而task,就是指容器中執行的具體命令。
常用命令
在Docker Swarm中經常使用的主要有docker swarm、docker node、docker service、docker stack。
docker swarm
docker node
docker service
docker stack
- 碼頭群
docker swarm
管理swarm,添加節點
Commands:
init Initialize a swarm
join Join a swarm as a node and/or manager
join-token Manage join tokens
leave Leave the swarm
unlock Unlock swarm
unlock-key Manage the unlock key
update Update the swarm
初始化swarm:
docker swarm init --advertise-addr 123.45.67.89(本机IP)
加入swarm:
docker swarm join \
--token SWMTKN-1-0vq435ac9oavqsnxkom9v49fpqbxdawfdl51xuvwelqsb6myj0-8tutrd6ucdf05nqk7xjz81cy7 \
123.45.67.89:2377
- docker節點
docker node
用於管理節點
Commands:
demote Demote one or more nodes from manager in the swarm
inspect Display detailed information on one or more nodes
ls List nodes in the swarm
promote Promote one or more nodes to manager in the swarm
ps List tasks running on one or more nodes, defaults to current node
rm Remove one or more nodes from the swarm
update Update a node
- docker服務
docker service
管理service
Commands:
create Create a new service
inspect Display detailed information on one or more services
logs Fetch the logs of a service or task
ls List services
ps List the tasks of one or more services
rm Remove one or more services
scale Scale one or multiple replicated services
update Update a service
- docker堆棧
docker stack
與docker-compose結合的命令,可以方便地在集羣中部署應用。
Commands:
deploy Deploy a new stack or update an existing stack
ls List stacks
ps List the tasks in the stack
rm Remove one or more stacks
services List the services in the stack
Docker Swarm的命令基本都很簡單,幾乎看一下--help就明白怎麼用了,都不需要再去翻檔案。由於是第一次接觸到分佈式系統,所以又花了些時間瞭解了一下它背後的科技原理。想一想要實現一個這樣的分佈式系統主要需要解决以下幾個問題:
--help
- 容器隨時可能開啟或停止,如何管理容器,怎麼檢測容器的運行狀態。怎麼保證容器隨時可能變化的情况下系統提供的服務仍可用。
- 集羣內的容器容器間需要跨主機通信,在硬編碼IP地址不適用的情况下,如何容器透明地跨主機通信。
- 如何讓多個容器的服務提供一個統一的外界入口。怎麼在集羣內做負載均衡。
服務發現
Docker Swarm內寘了Raft一致性算灋,可以保證分佈式系統的數據保持一致性同步。Etcd,Consul等高可用鍵值存儲系統也是採用了這種算灋。這個算灋的作用簡單點說就是隨時保證集羣中有一個Leader,由Leader接收數據更新,再同步到其他各個Follower節點。在Swarm中的作用表現為當一個Leader節點down掉時,系統會立即選取出另一個Leader節點,由於這個節點同步了之前節點的所有數據,所以可以無縫地管理集羣。Raft的詳細解釋可以參考《The Secret Lives of Data--Raft: Understandable Distributed Consensus》。
跨主機容器通信
Docker Swarm內寘的跨主機容器通信方案是overlay網絡,這是一個基於vxlan協定的網絡實現。其作用是虛擬出一個子網,讓處於不同主機的容器能透明地使用這個子網。所以跨主機的容器通信就變成了在同一個子網下的容器通信,看上去就像是同一主機下的bridge網路通信。
根據vxlan的作用知道,它是要在三層網絡中虛擬出二層網絡,即跨網段建立虛擬子網。簡單的理解就是把發送到虛擬子網地址10.0.0.3的報文封裝為發送到真實IP192.168.1.3的報文。這必然會有更大的數據開銷,但卻簡化了集羣的網絡連接,讓分佈在不同主機的容器好像都在同一個主機上一樣。關於vxlan的具體實現原理可以參考《vxlan協議原理簡介》。我們在Docker Swarm中,看一看overlay網絡的作用。在一個擁有兩個Node的Swarm Cluster中創建一個overlay網絡:
10.0.0.3
192.168.1.3
[email protected]:~# docker network create --driver overlay --subnet 10.10.10.0/24 my-overlay-network
然後部署一個nginx服務:
[email protected]:~# docker service create --name webapp --replicas=2 --network my-overlay-network -p 8080:80 nginx
這裡我們部署了一個副本數為2的nginx服務,使用了剛剛創建的my-overlay-network網絡
[email protected]:~# docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
t2z1cbbq1tnm webapp.1 nginx:latest vultr.guest2 Running Running 3 minutes ago
v116fzm54tz7 webapp.2 nginx:latest vultr.guest1 Running Running 3 minutes ago
[email protected]:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
df75f490d566 nginx:latest "nginx -g 'daemon of…" 12 minutes ago Up 11 minutes 80/tcp webapp.2.v116fzm54tz714k7d1jrszxyt
先看看manager節點的nginx容器網絡和該節點的docker網絡:可以發現這個容器有三個網卡:eth0、eth1、eth2,分別屬於docker的ingress網絡、my-overlay-network網絡、docker_gwbridge網絡。其中my-overlay-network就是我們剛剛創建的overlay網絡,這個網絡分配到了一個子網地址10.10.10.10。而ingress網絡會用於容器間的負載均衡,docker_gwbridge網絡用於容器連接外網。再登入到另一臺worker節點看看另一個nginx容器副本的網絡:這個容器eth2也連接到了my-overlay-network網絡,並且分配到了一個子網地址10.10.10.9。這樣兩個容器就可以通過子網地址通信了。(nginx鏡像本身沒有ifconfig、ping命令,需要自行安裝)同在一個子網還不够,Swarm還內寘了DNS服務。將service name作為service的DNS,就可以訪問到這個service了。隨意另建一個服務,也加入剛才創建的overlay網絡:
10.10.10.10
10.10.10.9
[email protected]:~# docker service create --name test --replicas=1 --network my-overlay-network -p 9090:80 nginx
[email protected]:~# docker exec -it b6 ifconfig |grep -A 1 eth2
eth2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 10.10.10.12 netmask 255.255.255.0 broadcast 10.10.10.255
用service name webapp訪問服務:發現能够ping通,但是解析的IP地址和之前看到的兩個容器IP並不一樣,這裡是Swarm做了負載均衡,稍後再具體討論下。這裡還有一個坑需要注意,如果一個節點處於NAT之後的網絡,其他節點處於公網,那麼這個節點是不能和其他節點建立Swarm的overlay網絡的。需要用weave等方案。我猜是不是和Swarm的overlay網絡是基於vxlan隧道實現而weave是基於包封裝有關。
webapp
負載均衡
負載均衡分為兩種:Swarm集羣內的service之間的相互訪問需要做負載均衡,稱為內部負載均衡(Internal LB);從Swarm集羣外部訪問服務的公開埠,也需要做負載均衡,稱外部部負載均衡(Exteral LB or Ingress LB)。
Internal LB
內部負載均衡就是我們在上一段提到的負載均衡,集羣內部通過DNS訪問service時,Swarm默認通過VIP(virtual IP)、iptables、IPVS轉發到某個容器。
Exteral LB(Ingress LB)
看名字就知道,這個負載均衡管道和前面提到的Ingress網絡有關。Swarm網絡要提供對外訪問的服務就需要打開公開埠,並映射到宿主機。Ingress LB就是外部通過公開埠訪問集羣時做的負載均衡。上圖是一個三個節點的Swarm集羣,app服務公開了8000埠,並且有兩個副本。雖然服務只有兩個副本,分別在A、B兩臺主機上,但是訪問C主機的8000埠,ingress網絡會通過IPVS將請求轉到A、B之一的容器中處理,依然可以對外提供服務。(這種負載均衡管道需要Node的docker engine版本儘量一致,我用17.05.0-ce和17.12.1-ce組成的Cluster時,提示load balancing出錯。用兩個17.12.1-ce版本Node就沒有這個問題。)看一看宿主機的iptables:9090和8080分別是上面兩個service暴露的埠,在宿主機上都轉給了172.18.0.2的相應埠。而這個172.18.0.2又是誰的IP呢?172.18.0.2正是ingress-sbox的IP地址。ingress-sbox再通過iptables的mangle規則和IPVS將請求轉發到合適的容器。具體流程如下圖:要完全弄明白Swarm的負載均衡還需要對iptables和IPVS很熟悉,所以還得多修煉一下內功啊。
9090
8080
172.18.0.2
172.18.0.2
172.18.0.2
docker-compose in Swarm
Docker三劍客之二的docker-compose和Swarm的結合,會讓集羣管理更加的簡單。甚至一鍵就可以在集羣中部署應用。前面提到的docker stack命令,就是主要用在這裡的。docker-compose用到Swarm裏,需要用到它的第三版,因為第三版才加入了Swarm相關的命令:
docker stack
Version 3: Designed to be cross-compatible between Compose and the Docker Engine’s swarm mode
docker-compose在上一篇blog中已經提到過了。這裡就記一下不同的地方吧。
- deploy在第三版中,加入了針對Swarm的deploy命令,它主要的作用是:選定部署節點(placement)、副本數量(REPLICAS)、資源限制(RESOURCES)、部署模式(mode)…
在第三版中,加入了針對Swarm的deploy命令,它主要的作用是:選定部署節點(placement)、副本數量(REPLICAS)、資源限制(RESOURCES)、部署模式(mode)…
- networks networks會出現在量個地方,一個是頂格命令,用於定義整個服務用到的網絡資訊,包括網絡名和網絡類型。另一個是在services命令之下,用於定義,某一個service用到的網絡和它在網絡中的一些資訊。
networks會出現在量個地方,一個是頂格命令,用於定義整個服務用到的網絡資訊,包括網絡名和網絡類型。另一個是在services命令之下,用於定義,某一個service用到的網絡和它在網絡中的一些資訊。
- build Swarm模式下,之前的build命令就不可用了。也就說Swarm模式下,不能通過Dockerfile製作並啟動鏡像。鏡像必須之前就存在於本地或者存在於hub中通過網絡拉取。
Swarm模式下,之前的build命令就不可用了。也就說Swarm模式下,不能通過Dockerfile製作並啟動鏡像。鏡像必須之前就存在於本地或者存在於hub中通過網絡拉取。
demo
最後還是用一個demo來當例子吧,就用上一篇的demo稍微改了一下,地址在這裡。還是一個Web應用,包括Nginx、Flask後端、MongoDB資料庫。事先得準備一個包含兩個節點的Swarm Cluster,注意這兩個節點得能够搭起overlay網絡。在docker-compose.yml中可以看到:
networks:
swarm_demo:
driver: overlay
這裡是頂格的networks命令,先定義了一個名為swarm_demo的overlay網絡。
networks
services:
web:
networks:
swarm_demo:
aliases:
- demo_web
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
這裡我們把web服務放到了swarm_demo網絡中,定義了別名demo_web。在這個overlay網絡中的其他服務就可以用demo_web這個網絡名訪問到web服務。比如/nginx/default.conf中直接以demo_web作為反代的地址:
/nginx/default.conf
location /api {
proxy_pass http://demo_web:5678;
...
}
而deploy命令定義了副本數量和service運行的位置。我們來測試一下,在manager節點上執行:
git clone https://github.com/liverpoolpjy/docker_swarm_demo.git
cd docker_swarm_demo
docker build -t demo_web:latest web/. # 先制作好镜像
docker build -t demo_nginx:latest nginx/.
docker stack deploy --compose-file=docker-compose.yml app # 部署
因為這個demo中的Nginx鏡像和python鏡像都是自己用Dockerfile製作的,所以我們先在manager節點上製作好鏡像,並限制web和nginx服務只運行在manager節點。
[email protected]:/tmp/docker_swarm_demo# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
z8fae79ld53k app_db replicated 1/1 mongo:3.4
rzlz56bg1aa0 app_nginx replicated 1/1 demo_nginx:latest *:80->80/tcp
wvnlymts6hh0 app_web replicated 1/1 demo_web:latest
[email protected]:/tmp/docker_swarm_demo# docker service ps app_db app_nginx app_web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
y2u9gk5yvdm4 app_db.1 mongo:3.4 vultr.guest2 Running Running 22 minutes ago
h05gavtnladf app_nginx.1 demo_nginx:latest vultr.guest1 Running Running 22 minutes ago
fdls6o6lurnh app_web.1 demo_web:latest vultr.guest1 Running Running 22 minutes ago
和預期一樣,db服務運行在worker節點,web和nginx服務運行在manager節點。現在訪問任意一個節點的80埠,都可以訪問到demo頁面了。
summary
總的來說,Docker Swarm的使用是比較簡單的,檔案也挺詳細,功能也算是覆蓋了容器集羣管理的方方面面。但是又因為Swarm為我們做了太多了,把很多的底層工作為我們遮罩了,想要學一下它的各種原理反而顯得要困難一些。所以我感覺它算是學習容器集羣不錯的開端,相比之下Kubenetes這種安裝配置超級麻煩的giant可能更能學習到集羣管理的細節吧。
reference
Getting started with swarm mode Docker Networking Internals: Container Connectivity in Docker Swarm and Overlay Networks Compose file versions and upgrading docker swarm mode的服務發現和LB詳解