即便有了Docker Compose,項目的部署仍然存在問題,由於Docker Compose只能把項目全部的容器部署在同一臺機器上,這在生產環境下是不現實的。html
Docker Compose通常只適用於開發環境,而對於生產環境下的項目部署,咱們須要用到Docker Swarm。node
Docker Swarm是Docker官方提供的一套容器編排系統,它將一組Docker主機虛擬成一個單獨的虛擬Docker主機。mysql
架構以下:linux
swarm是一系列節點的集合,而節點能夠是一臺裸機或者一臺虛擬機。一個節點能扮演一個或者兩個角色,manager或者worker。sql
manager Docker Swarm集羣須要至少一個manager節點,節點之間使用Raft consensus protocol進行協同工做。 一般,第一個啓用docker swarm的節點將成爲leader,後來加入的都是follower。當前的leader若是掛掉, 剩餘的節點將從新選舉出一個新的leader。每個manager都有一個完整的當前集羣狀態的副本,能夠保證manager的高可用。 worker worker節點是運行實際應用服務的容器所在的地方。理論上,一個manager節點也能同時成爲worker節點,但在生產環境中, 咱們不建議這樣作。worker節點之間,經過control plane進行通訊,這種通訊使用gossip協議,而且是異步的。
多個tasks組成一個service,多個services組成一個stack。docker
task 在Docker Swarm中,task是一個部署的最小單元,task與容器是一對一的關係。 service swarm service是一個抽象的概念,它只是一個對運行在swarm集羣上的應用服務,所指望狀態的描述。 它就像一個描述了下面物品的清單列表同樣: 服務名稱 使用哪一個鏡像來建立容器 要運行多少個副本 服務的容器要鏈接到哪一個網絡上 須要映射哪些端口 stack stack是描述一系列相關services的集合,能夠經過在一個YAML文件中來定義一個stack,相似於docker-compose。
對於單主機網絡,全部的容器都運行在一個docker主機上,他們之間的通訊通常使用本地的bridge network便可。centos
而對於swarm集羣,針對的是一組docker主機,須要使用docker的overlay network。瀏覽器
docker swarm
命令:ca 顯示根CA證書 init 初始化一個集羣 join 加入集羣 join-token worker 查看工做節點的token join-token manager 查看管理節點的token leave 離開集羣 unlock 解鎖集羣 unlock-key 管理解鎖密鑰 update 更新集羣
docker node
命令:demote 節點降級,由管理節點降級爲工做節點 inspect 查看一個或多個節點的詳情 ls 查看全部的節點 promote 節點升級,由工做節點升級爲管理節點 ps 查看一個或多個節點中的task,默認爲當前節點 rm 刪除一個或多個節點 update 更新一個節點
docker service
命令:create 建立一個新的service inspect 查看一個或多個service的詳情 logs 獲取service或task的日誌 ls 列出全部的service ps 列出一個或多個service的task rm 刪除一個或多個service rollback 將更改還原爲service的配置 scale 建立一個或多個service的副本 update 更新一個service
docker stack
命令:deploy 部署新的stack或更新現有stack ls 列出現有stack ps 列出stack中的tasks rm 刪除一個或多個stack services 列出stack中的services
注意:以上命令大多隻能在manager節點上執行。網絡
根據集羣的高可用性要求實現奇數個節點。當有兩個以上manager節點時,集羣能夠manager節點的故障中恢復,而無需停機。架構
N個manager節點的集羣將最多容忍(N-1) / 2
個manager節點的丟失。
下面建立一個三節點的swarm集羣。
role | ip | hostname |
---|---|---|
manager | 192.168.30.128 | test1 |
worker1 | 192.168.30.129 | test2 |
worker2 | 192.168.30.130 | test3 |
# systemctl stop firewalld && systemctl disable firewalld# sed -i 's/=enforcing/=disabled/g' /etc/selinux/config && setenforce 0
# curl http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker.repo# yum makecache fast# yum install -y docker-ce# systemctl start docker && systemctl enable docker
注意:swarm集羣必須先在manager節點進行集羣初始化,而後在worker節點上加入集羣。
192.168.30.128
# docker swarm init --advertise-addr=192.168.30.128Swarm initialized: current node (q1n9ztahdj489pltf3gl5pomj) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-38ci507e4fyp92oauqvov5axo3qhti5wlm58odjz5lo2rdatyo-e2y52gxq7y40mah2nzq1b5fg9 192.168.30.128:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
將添加worker節點的命令複製到其它非manager節點的機器執行
192.168.30.129
# docker swarm join --token SWMTKN-1-38ci507e4fyp92oauqvov5axo3qhti5wlm58odjz5lo2rdatyo-e2y52gxq7y40mah2nzq1b5fg9 192.168.30.128:2377This node joined a swarm as a worker.
192.168.30.130
# docker swarm join --token SWMTKN-1-38ci507e4fyp92oauqvov5axo3qhti5wlm58odjz5lo2rdatyo-e2y52gxq7y40mah2nzq1b5fg9 192.168.30.128:2377This node joined a swarm as a worker.
192.168.30.128
# docker node lsID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION q1n9ztahdj489pltf3gl5pomj * test1 Ready Active Leader 19.03.3 0qyp2ut4m3pggag1yq7f3jn31 test2 Ready Active 19.03.4 cbi8detm7t9v8w5ntyzid0cvj test3 Ready Active 19.03.4
能夠看到,一個三節點的swarm集羣建立完畢,test1(192.168.30.128)爲manager節點。
在Docker Swarm集羣中,咱們能夠經過docker service
命令建立一些service,每一個service都包含多個tasks,每一個task對應一個容器。
192.168.30.128
# docker service create --name busybox busybox:latest sh -c "while true; do sleep 3600; done"y8o6jogs0iyp4qewb5okgzb37 overall progress: 1 out of 1 tasks 1/1: running verify: Service converged# docker service lsID NAME MODE REPLICAS IMAGE PORTS y8o6jogs0iyp busybox replicated 1/1 busybox:latest# docker service ps busybox ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS mavy3blpmzvz busybox.1 busybox:latest test2 Running Running about a minute ago
能夠看到,該service的task運行在test2(192.168.30.129)上
192.168.30.129
# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3dd48d9541ca busybox:latest "sh -c 'while true; …" 2 minutes ago Up 2 minutes busybox.1.mavy3blpmzvzka1ks1ebuz3s4
當前busybox這個service的task只有1個,擴展爲5個。
192.168.30.128
# docker service scale busybox=5busybox scaled to 5 overall progress: 5 out of 5 tasks 1/5: running 2/5: running 3/5: running 4/5: running 5/5: running verify: Service converged# docker service lsID NAME MODE REPLICAS IMAGE PORTS y8o6jogs0iyp busybox replicated 5/5 busybox:latest# docker service ps busybox ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS mavy3blpmzvz busybox.1 busybox:latest test2 Running Running 4 minutes ago gxg5gt2j5a1v busybox.2 busybox:latest test1 Running Running 20 seconds ago okge105yuzb8 busybox.3 busybox:latest test2 Running Running 25 seconds ago b86rr94bbotj busybox.4 busybox:latest test3 Running Running 22 seconds ago 8zogu5kacnpw busybox.5 busybox:latest test1 Running Running 20 seconds ago
能夠看到,該service的task分別運行在集羣的3個節點上。
當某個task對應的容器掛掉時,會自動在任一節點啓動該task對應的容器。
192.168.30.128
# docker rm -f 7d013a7eb6857d013a7eb685# docker service ps busybox ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS mavy3blpmzvz busybox.1 busybox:latest test2 Running Running 11 minutes ago jewllc9gywpa busybox.2 busybox:latest test3 Ready Ready 3 seconds ago gxg5gt2j5a1v \_ busybox.2 busybox:latest test1 Shutdown Failed 3 seconds ago "task: non-zero exit (137)" okge105yuzb8 busybox.3 busybox:latest test2 Running Running 7 minutes ago b86rr94bbotj busybox.4 busybox:latest test3 Running Running 7 minutes ago 8zogu5kacnpw busybox.5 busybox:latest test1 Running Running 7 minutes ago # docker service lsID NAME MODE REPLICAS IMAGE PORTS y8o6jogs0iyp busybox replicated 5/5 busybox:latest
能夠看到,test1(192.168.30.128)上強制刪除的容器在test3(192.168.30.130)上從新啓動。
192.168.30.130
# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 05efd68e06c5 busybox:latest "sh -c 'while true; …" 2 minutes ago Up About a minute busybox.2.jewllc9gywpaude65rmc87wka 629fe2d2b396 busybox:latest "sh -c 'while true; …" 9 minutes ago Up 9 minutes busybox.4.b86rr94bbotj1fhyk7owwt2tl
故障恢復能夠保證咱們的service是穩定有效的。
192.168.30.128
# docker service lsID NAME MODE REPLICAS IMAGE PORTS y8o6jogs0iyp busybox replicated 5/5 busybox:latest # docker service rm busybox busybox# docker service lsID NAME MODE REPLICAS IMAGE PORTS# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
192.168.30.129
# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
192.168.30.130
# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
當刪除service後,該service對應的task容器也會中止運行並刪除。
若是在swarm集羣中部署項目,首先須要建立的是overlay network,由於項目中關聯的services須要經過overlay network通訊。
在swarm集羣中建立overlay network,再也不須要外部的分佈式存儲(如etcd),swarm集羣會自動完成overlay network的同步工做。
下面使用Docker Service部署wordpress項目,該項目包含兩個service:wordpress和mysql。
192.168.30.128
# docker network lsNETWORK ID NAME DRIVER SCOPE 5ee1b278fd34 bridge bridge local faf258f504b0 docker_gwbridge bridge local 535808221d2e host host local 5yetwtzg2b1x ingress overlay swarm 2addad8d8857 none null local# docker network create -d overlay testexyl7ksbeavt00c5ot0k66s2w# docker network lsNETWORK ID NAME DRIVER SCOPE 5ee1b278fd34 bridge bridge local faf258f504b0 docker_gwbridge bridge local 535808221d2e host host local 5yetwtzg2b1x ingress overlay swarm 2addad8d8857 none null local exyl7ksbeavt test overlay swarm
192.168.30.128
# docker service create --name mysql --network test -e MYSQL_ROOT_PASSWORD=123456789 -e MYSQL_DATABASE=wordpress --mount type=volume,source=mysql_data,destination=/var/lib/mysql mysql:5.73bjl5kse0letilvkx0kltnfm9 overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged
# docker service lsID NAME MODE REPLICAS IMAGE PORTS 3bjl5kse0let mysql replicated 1/1 mysql:5.7 # docker service ps mysql ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS d8ofaptycyzs mysql.1 mysql:5.7 test3 Running Running about a minute ago
192.168.30.128
# docker service create --name wordpress --network test -p 80:80 -e WORDPRESS_DB_PASSWORD=123456789 -e WORDPRESS_DB_HOST=mysql wordpressx96xdiazi4iupgvwl5oza4sx3 overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged
# docker service lsID NAME MODE REPLICAS IMAGE PORTS 3bjl5kse0let mysql replicated 1/1 mysql:5.7 x96xdiazi4iu wordpress replicated 1/1 wordpress:latest *:80->80/tcp# docker service ps wordpress ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 8b9g1upsll15 wordpress.1 wordpress:latest test1 Running Running 36 seconds ago
能夠看到,mysql這個service的task容器運行在test3(192.168.30.130)上,而wordpress這個服務的task容器運行在test1(192.168.30.128)上。
192.168.30.128
# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e189db13cbe3 wordpress:latest "docker-entrypoint.s…" About a minute ago Up About a minute 80/tcp wordpress.1.8b9g1upsll15m8crlhkebgc64
192.168.30.130
# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6be947ccfe36 mysql:5.7 "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 3306/tcp, 33060/tcp mysql.1.d8ofaptycyzs01ckt6k2zhxd7
打開瀏覽器訪問192.168.30.128
,
填寫信息後直接登陸,能夠看看wordpress站點
經過overlay network,在swarm集羣中使用docker service
部署wordpress項目成功。
繼續使用瀏覽器,分別訪問192.168.30.129
和192.168.30.130
,
這是爲何呢?這就是Routing Mesh的做用。若是service有綁定端口,則該service可經過任意swarm節點的相應端口訪問。
建立whoami service
# docker service create --name whoami --network test -p 8000:8000 jwilder/whoamickgqv2okq5wdscgv0pihk2hwr overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged# docker service scale whoami=3whoami scaled to 3 overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] verify: Service converged
# docker service lsID NAME MODE REPLICAS IMAGE PORTS 3bjl5kse0let mysql replicated 1/1 mysql:5.7 ckgqv2okq5wd whoami replicated 3/3 jwilder/whoami:latest *:8000->8000/tcp x96xdiazi4iu wordpress replicated 1/1 wordpress:latest *:80->80/tcp# docker service ps whoami ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ugndxn4ojkw4 whoami.1 jwilder/whoami:latest test2 Running Running 2 minutes ago iv3cu975hpr4 whoami.2 jwilder/whoami:latest test1 Running Running about a minute ago qc5kp773iof7 whoami.3 jwilder/whoami:latest test3 Running Running about a minute ago
建立busybox service
# docker service create --name busybox --network test busybox sh -c "while true; do sleep 3600; done"bxy6hzvrfoxy28yyagzvkfqmf overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged# docker service ps busybox ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS rewjvfn34qq9 busybox.1 busybox:latest test2 Running Running 23 seconds ago
192.168.30.129
# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 933d4e916cbd busybox:latest "sh -c 'while true; …" About a minute ago Up About a minute busybox.1.rewjvfn34qq9tbrn2dty4e6vf 7b28da1c9491 jwilder/whoami:latest "/app/http" 5 minutes ago Up 5 minutes 8000/tcp whoami.1.ugndxn4ojkw42u6y22rfdjlii# docker exec -it busybox.1.rewjvfn34qq9tbrn2dty4e6vf sh/ # ping whoamiPING whoami (10.0.0.17): 56 data bytes 64 bytes from 10.0.0.17: seq=0 ttl=64 time=0.192 ms 64 bytes from 10.0.0.17: seq=1 ttl=64 time=0.353 ms 64 bytes from 10.0.0.17: seq=2 ttl=64 time=0.144 ms 64 bytes from 10.0.0.17: seq=3 ttl=64 time=0.144 ms ^C --- whoami ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 0.144/0.208/0.353 ms
前面啓動了3個whoami的task容器,爲何在busybox中ping whoami
時,始終只返回一個ip呢?
/ # nslookup whoamiServer: 127.0.0.11 Address: 127.0.0.11:53 Non-authoritative answer: *** Can't find whoami: No answer / # nslookup tasks.whoami 127.0.0.11 Server: 127.0.0.11 Address: 127.0.0.11:53 Non-authoritative answer: Name: tasks.whoami Address: 10.0.0.18 Name: tasks.whoami Address: 10.0.0.21 Name: tasks.whoami Address: 10.0.0.20 *** Can't find tasks.whoami: No answer
這回看到3個ip:10.0.0.18
、10.0.0.21
、10.0.0.20
,分別在進入各個whoami的容器內查看ip可知,這3個ip就是whoami容器的真實ip,而咱們ping whoami
獲得的ip10.0.0.17
是一個虛擬ip(vip)。
對於一個service來講,它的vip通常是不變的,在水平擴展時發生變化的是vip後面的task容器ip。
任選一個節點,
# curl 127.0.0.1:8000I'm ae9da507e9f7 # curl 127.0.0.1:8000 I'm 5e4782fd9dee# curl 127.0.0.1:8000I'm 7b28da1c9491 # curl 127.0.0.1:8000 I'm ae9da507e9f7# curl 127.0.0.1:8000I'm 5e4782fd9dee # curl 127.0.0.1:8000 I'm 7b28da1c9491
經過連續curl返回的內容能夠看到,每次返回的結果是不一樣的hostname,而且是輪詢返回,這就造成了負載均衡。
其實routing mesh內部根據LVS(Linux Virtual Server)來實現的,經過vip達到負載均衡的目的。
Internal 容器和容器之間的訪問經過overlay網絡(經過VIP) Ingress 若是service有綁定端口,則此service可經過任意swarm節點的相應端口訪問
外部訪問的負載均衡 服務端口被暴露到各個swarm節點 內部經過LVS進行負載均衡