目錄html
Docker v1.12 是一個很是重要的版本,Docker 從新實現了集羣的編排方式。在此以前,提供集羣功能的 Docker Swarm 是一個單獨的軟件,並且依賴外部數據庫(好比 Consul、etcd 或 Zookeeper)。前端
從 v1.12 開始,Docker Swarm 的功能已經徹底與 Docker Engine 集成,要管理集羣,只須要啓動 Swarm Mode。安裝好 Docker,Swarm 就已經在那裏了,服務發現也在那裏了(不須要安裝 Consul 等外部數據庫)。node
相比 Kubernetes,用 Docker Swarm 建立集羣很是簡單,不須要額外安裝任何軟件,也不須要作任何額外的配置。很適合做爲學習容器編排引擎的起點。mysql
swarm 運行 Docker Engine 的多個主機組成的集羣。nginx
從 v1.12 開始,集羣管理和編排功能已經集成進 Docker Engine。當 Docker Engine 初始化了一個 swarm 或者加入到一個存在的 swarm 時,它就啓動了 swarm mode。web
沒啓動 swarm mode 時,Docker 執行的是容器命令;運行 swarm mode 後,Docker 增長了編排 service 的能力。sql
Docker 容許在同一個 Docker 主機上既運行 swarm service,又運行單獨的容器。docker
swarm 中的每一個 Docker Engine 都是一個 node,有兩種類型的 node:manager 和 worker。shell
爲了向 swarm 中部署應用,咱們須要在 manager node 上執行部署命令,manager node 會將部署任務拆解並分配給一個或多個 worker node 完成部署。數據庫
manager node 負責執行編排和集羣管理工做,保持並維護 swarm 處於指望的狀態。swarm 中若是有多個 manager node,它們會自動協商並選舉出一個 leader 執行編排任務。
woker node 接受並執行由 manager node 派發的任務。默認配置下 manager node 同時也是一個 worker node,不過能夠將其配置成 manager-only node,讓其專職負責編排和集羣管理工做。
work node 會按期向 manager node 報告本身的狀態和它正在執行的任務的狀態,這樣 manager 就能夠維護整個集羣的狀態。
service 定義了 worker node 上要執行的任務。swarm 的主要編排任務就是保證 service 處於指望的狀態下。
舉一個 service 的例子:在 swarm 中啓動一個 http 服務,使用的鏡像是 httpd:latest,副本數爲 3。
manager node 負責建立這個 service,通過分析知道須要啓動 3 個 httpd 容器,根據當前各 worker node 的狀態將運行容器的任務分配下去,好比 worker1 上運行兩個容器,worker2 上運行一個容器。
運行了一段時間,worker2 忽然宕機了,manager 監控到這個故障,因而當即在 worker3 上啓動了一個新的 httpd 容器。
這樣就保證了 service 處於指望的三個副本狀態。
實驗環境
主機名 | IP | 系統 | docker版本 |
---|---|---|---|
swarm-manager | 192.168.2.110 | CentOS 7.5 | docker-ce-18.09.0-3.el7.x86_64 |
swarm-worker1 | 192.168.2.120 | CentOS 7.5 | docker-ce-18.09.0-3.el7.x86_64 |
swarm-worker2 | 192.168.2.130 | CentOS 7.5 | docker-ce-18.09.0-3.el7.x86_64 |
在 swarm-manager 上執行以下命令建立 swarm。
[root@manager ~]# docker swarm init --advertise-addr 192.168.2.110 Swarm initialized: current node (rxoqe9tvd0rfd4zxc4uoniu05) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-04d6zlih0yqjgnlz8rlwhpz1qfc2ua9yp18y15wyefrctgrj0x-chtm4rrdysjp8e310um4rjx09 192.168.2.110:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
--advertise-addr
指定與其餘 node 通訊的地址。
docker swarm init
輸出告訴咱們:
① swarm 建立成功,swarm-manager 成爲 manager node。
② 添加 worker node 須要執行的命令。
③ 添加 manager node 須要執行的命令。
執行 docker node ls
查看當前 swarm 的 node,目前只有一個 manager。
[root@manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION rxoqe9tvd0rfd4zxc4uoniu05 * manager Ready Active Leader 18.09.0
複製前面的 docker swarm join
命令,在 worker1 和worker2 上執行,將它們添加到 swarm 中。命令輸出以下:
[root@swarm-worker2 ~]# docker swarm join --token SWMTKN-1-04d6zlih0yqjgnlz8rlwhpz1qfc2ua9yp18y15wyefrctgrj0x-chtm4rrdysjp8e310um4rjx09 192.168.2.110:2377 This node joined a swarm as a worker.
[root@swarm-manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION rxoqe9tvd0rfd4zxc4uoniu05 * swarm-manager Ready Active Leader 18.09.0 jfpu6n3qt4gqnoqs8lv36o5fn swarm-worker1 Ready Active 18.09.0 byxpoc4rgi45jz1d8vi5hgrog swarm-worker2 Ready Active 18.09.0
若是當時沒有記錄下 docker swarm init
提示的添加 worker 的完整命令,能夠經過 docker swarm join-token worker
查看。
[root@manager ~]# docker swarm join-token worker To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-04d6zlih0yqjgnlz8rlwhpz1qfc2ua9yp18y15wyefrctgrj0x-chtm4rrdysjp8e310um4rjx09 192.168.2.110:2377
注意:此命令只能在 manager node 上執行。
至此,三節點的 swarm 集羣就已經搭建好了。
部署一個運行 httpd 鏡像的 service,執行以下命令:
docker service create --name web_server httpd
部署 service 的命令形式與運行容器的 docker run
很類似,--name
爲 service 命名,nginx:1.14-alpine
爲鏡像的名字。
[root@swarm-manager ~]# docker service create --name my_web nginx:1.14-alpine kqhkkqt0i6r6u40qknuyb76ja overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged
經過 docker service ls
能夠查看當前 swarm 中的 service。
[root@swarm-manager ~]# docker service ls ID NAME MODE REPLICAS IMAGE PORTS kqhkkqt0i6r6 my_web replicated 1/1 nginx:1.14-alpine
REPLICAS
顯示當前副本信息,1/1
的意思是 web_server 這個 service 指望的容器副本數量爲 1,目前已經啓動的副本數量爲1。也就是當前 service 尚未部署完成。命令 docker service ps
能夠查看 service 每一個副本的狀態。
[root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS kokoy6h24gwp my_web.1 nginx:1.14-alpine swarm-worker1 Running Running about a minute ago
能夠看到 service 惟一的副本被分派到 swarm-worker1,當前的狀態是 running
若是以爲不放心,還能夠到 swarm-worker1 去確認 nginx 容器已經運行。
[root@swarm-worker1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a0f7ea32d403 nginx:1.14-alpine "nginx -g 'daemon of…" 2 minutes ago Up 2 minutes 80/tcp my_web.1.kokoy6h24gwpbujbp0id9ay15
目前爲止 Service 與普通的容器尚未太大的不一樣
對於 web 服務,咱們一般會運行多個實例。這樣能夠負載均衡,同時也能提供高可用。
swarm 要實現這個目標很是簡單,增長 service 的副本數就能夠了。在 swarm-manager 上執行以下命令:
docker service scale web_server=5
[root@swarm-manager ~]# docker service scale my_web=5 my_web 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 [root@swarm-manager ~]# docker service scale my_web=5 my_web 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 [root@swarm-manager ~]# docker service ls ID NAME MODE REPLICAS IMAGE PORTS kqhkkqt0i6r6 my_web replicated 5/5 nginx:1.14-alpine [root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS kokoy6h24gwp my_web.1 nginx:1.14-alpine swarm-worker1 Running Running 3 minutes ago e8yjfo9td44m my_web.2 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago 7fth256vi4dw my_web.3 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago 7dk4zf9li67p my_web.4 nginx:1.14-alpine swarm-worker1 Running Running 50 seconds ago kz9b8mv2q1sk my_web.5 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago
5 個副本已經分佈在 swarm 的全部三個節點上。
默認配置下 manager node 也是 worker node,因此 swarm-manager 上也運行了副本。若是不但願在 manager 上運行 service,能夠執行以下命令:
docker node update --availability drain swarm-manager
[root@swarm-manager ~]# docker node update --availability drain swarm-manager swarm-manager [root@swarm-manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION rxoqe9tvd0rfd4zxc4uoniu05 * swarm-manager Ready Drain Leader 18.09.0 jfpu6n3qt4gqnoqs8lv36o5fn swarm-worker1 Ready Active 18.09.0 byxpoc4rgi45jz1d8vi5hgrog swarm-worker2 Ready Active 18.09.0 [root@swarm-manager ~]# docker service ps web_server ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS qdq9gcq6u01d web_server.1 httpd:latest swarm-worker2 Running Running less than a second ago h3b36zug0o3b web_server.2 httpd:latest swarm-worker2 Running Running less than a second ago pmxnu78a94lm web_server.3 httpd:latest swarm-worker1 Running Running 2 minutes ago j08u3j2ctwal web_server.4 httpd:latest swarm-worker1 Running Running 20 seconds ago 2teq0ag7n4u4 \_ web_server.4 httpd:latest swarm-manager Shutdown Shutdown 21 seconds ago pmrzsdue7ryk web_server.5 httpd:latest swarm-worker1 Running Running 20 seconds ago wqtbw718bcx3 \_ web_server.5 httpd:latest swarm-manager Shutdown Shutdown 21 seconds ago
swarm-manager 上的副本 web_server.4 \5
已經被 Shutdown
了,爲了達到 5 個副本數的目標,在 swarm-worker1 上添加了副本 web_server.4\5
。
前面咱們的場景是 scale up,咱們還能夠 scale down,減小副本數,運行下面的命令:
docker service scale web_server=3
[root@swarm-manager ~]# docker service scale my_web=3 my_web scaled to 3 overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] verify: Service converged [root@swarm-manager ~]# docker service ls ID NAME MODE REPLICAS IMAGE PORTS kqhkkqt0i6r6 my_web replicated 3/3 nginx:1.14-alpine [root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS kokoy6h24gwp my_web.1 nginx:1.14-alpine swarm-worker1 Running Running 4 minutes ago e8yjfo9td44m my_web.2 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago 7fth256vi4dw my_web.3 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago
能夠看到,web_server.4
和 web_server.5
這兩個副本已經被刪除了。
故障是在所不免的,容器可能崩潰,Docker Host 可能宕機,不過幸運的是,Swarm 已經內置了 failover 策略。
建立 service 的時候,咱們沒有告訴 swarm 發生故障時該如何處理,只是說明了咱們指望的狀態(好比運行3個副本),swarm 會盡最大的努力達成這個指望狀態,不管發生什麼情況.
如今咱們測試 swarm 的 failover 特性,關閉 swarm-worker1。
Swarm 會檢測到 swarm-worker1 的故障,並標記爲 Down。
[root@swarm-manager ~]# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION rxoqe9tvd0rfd4zxc4uoniu05 * swarm-manager Ready Drain Leader 18.09.0 jfpu6n3qt4gqnoqs8lv36o5fn swarm-worker1 Down Active 18.09.0 byxpoc4rgi45jz1d8vi5hgrog swarm-worker2 Ready Active 18.09.0
Swarm 會將 swarm-worker1 上的副本調度到其餘可用節點。咱們能夠經過 docker service ps
觀察這個 failover 過程。
[root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS w285dbb0spcf my_web.1 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago kokoy6h24gwp \_ my_web.1 nginx:1.14-alpine swarm-worker1 Shutdown Running 5 minutes ago e8yjfo9td44m my_web.2 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago 7fth256vi4dw my_web.3 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago
能夠看到,web_server.1
和 web_server.2
已經從 swarm-worker1 遷移到了 swarm-worker2,以前運行在故障節點 swarm-worker1 上的副本狀態被標記爲 Shutdown
。即便worker1恢復也不行
爲了便於分析,咱們從新部署 web_server。
[root@swarm-manager ~]# docker service rm my_web my_web [root@swarm-manager ~]# docker service create --name web_server --replicas=2 nginx:1.14-alpine qnr86tsd8ht8r7d1bfrbhxx5i overall progress: 2 out of 2 tasks 1/2: running [==================================================>] 2/2: running [==================================================>] verify: Service converged [root@swarm-manager ~]# docker service ls ID NAME MODE REPLICAS IMAGE PORTS qnr86tsd8ht8 web_server replicated 2/2 nginx:1.14-alpine [root@swarm-manager ~]# docker service ps web_server ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ak7uuvnjf8mx web_server.1 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago z9kck3rspzec web_server.2 nginx:1.14-alpine swarm-worker1 Running Running about a minute ago
① docker service rm
刪除 web_server,service 的全部副本(容器)都會被刪除。
② 從新建立 service,此次直接用 --replicas=2
建立兩個副本。
③ 每一個 worker node 上運行了一個副本。
要訪問 http 服務,最起碼網絡得通吧,服務的 IP 咱們得知道吧,但這些信息目前咱們都不清楚。不過至少咱們知道每一個副本都是一個運行的容器,要不先看看容器的網絡配置吧。
[root@swarm-worker1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 68502d64ca5f nginx:1.14-alpine "nginx -g 'daemon of…" 46 seconds ago Up 46 seconds 80/tcp web_server.2.z9kck3rspzecnyik9llg3pa1f [root@swarm-worker1 ~]# docker exec web_server.2.z9kck3rspzecnyik9llg3pa1f ip r default via 172.16.1.1 dev eth0 172.16.1.0/24 dev eth0 scope link src 172.16.1.2
在 swarm-worker1 上運行了一個容器,是 web_server 的一個副本,容器監聽了 80
端口,但並無映射到 Docker Host,因此只能經過容器的 IP 訪問。查看一下容器的 IP。
容器 IP 爲 172.16.1.2
,實際上鍊接的是 Docker 默認 bridge
網絡。
咱們能夠直接在 swarm-worker1 上訪問容器的 http 服務。
[root@swarm-worker1 ~]# curl 172.16.1.2 -I HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Wed, 26 Dec 2018 02:16:48 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Fri, 21 Dec 2018 01:22:26 GMT Connection: keep-alive ETag: "5c1c4052-264" Accept-Ranges: bytes
但這樣的訪問也僅僅是容器層面的訪問,服務並無暴露給外部網絡,只能在 Docker 主機上訪問。換句話說,當前配置下,咱們沒法訪問 service web_server。
要將 service 暴露到外部,方法其實很簡單,執行下面的命令:
[root@swarm-manager ~]# docker service update --publish-add 8080:80 web_server web_server overall progress: 2 out of 2 tasks 1/2: running [==================================================>] 2/2: running [==================================================>] verify: Service converged
若是是新建 service,能夠直接用使用 --publish
參數,好比:
docker service create --name web_server --publish 8080:80 --replicas=2 httpd
容器在 80 端口上監聽 http 請求,--publish-add 8080:80
將容器的 80 映射到主機的 8080 端口,這樣外部網絡就能訪問到 service 了。
[root@swarm-manager ~]# curl -I 192.168.2.110:8080 HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Wed, 26 Dec 2018 02:18:17 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Fri, 21 Dec 2018 01:22:26 GMT Connection: keep-alive ETag: "5c1c4052-264" Accept-Ranges: bytes [root@swarm-manager ~]# curl -I 192.168.2.120:8080 HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Wed, 26 Dec 2018 02:18:20 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Fri, 21 Dec 2018 01:22:26 GMT Connection: keep-alive ETag: "5c1c4052-264" Accept-Ranges: bytes [root@swarm-manager ~]# curl -I 192.168.2.130:8080 HTTP/1.1 200 OK Server: nginx/1.14.2 Date: Wed, 26 Dec 2018 02:18:22 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Fri, 21 Dec 2018 01:22:26 GMT Connection: keep-alive ETag: "5c1c4052-264" Accept-Ranges: bytes
當咱們訪問任何節點的 8080 端口時,swarm 內部的 load balancer 會將請求轉發給 web_server 其中的一個副本,不管訪問哪一個節點,即便該節點上沒有運行 service 的副本,最終都能訪問到 service。
另外,咱們還能夠配置一個外部 load balancer,將請求路由到 swarm service。好比配置 HAProxy,將請求分發到各個節點的 8080 端口。
當咱們應用 --publish-add 8080:80
時,swarm 會從新配置 service。
[root@swarm-manager ~]# docker service ps web_server ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS wyl8a3mhheyr web_server.1 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago ak7uuvnjf8mx \_ web_server.1 nginx:1.14-alpine swarm-worker2 Shutdown Shutdown 11 hours ago v3sw5eq19z4x web_server.2 nginx:1.14-alpine swarm-worker1 Running Running about a minute ago z9kck3rspzec \_ web_server.2 nginx:1.14-alpine swarm-worker1 Shutdown Shutdown about a minute ago
以前的全部副本都被 Shutdown,而後啓動了新的副本。咱們查看一下新副本的容器網絡配置。
[root@swarm-worker1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9a28cef94e92 nginx:1.14-alpine "nginx -g 'daemon of…" About a minute ago Up About a minute 80/tcp web_server.2.v3sw5eq19z4x8ytauz3x2wl1w [root@swarm-worker1 ~]# docker exec web_server.2.v3sw5eq19z4x8ytauz3x2wl1w ip r default via 172.18.0.1 dev eth1 10.255.0.0/16 dev eth0 scope link src 10.255.0.10 172.18.0.0/16 dev eth1 scope link src 172.18.0.3
容器的網絡與 --publish-add
以前已經大不同了,如今有兩塊網卡,每塊網卡鏈接不一樣的 Docker 網絡
實際上:
ingress
,其做用是讓運行在不一樣主機上的容器能夠相互通訊。docker_gwbridge
,其做用是讓容器可以訪問到外網。[root@swarm-worker1 ~]# docker network ls NETWORK ID NAME DRIVER SCOPE d174ec92bfb9 bridge bridge local f57703c9517c docker_gwbridge bridge local 17bf4830406d harbor_harbor bridge local 266cc54ae977 host host local t4xnhmp6y5nr ingress overlay swarm a5d3ec376305 mybr0 bridge local 436b29f1c660 none null local
ingress
網絡是 swarm 建立時 Docker 爲自動咱們建立的,swarm 中的每一個 node 都能使用 ingress
。
微服務架構的應用由若干 service 組成。好比有運行 httpd 的 web 前端,有提供緩存的 memcached,有存放數據的 mysql,每一層都是 swarm 的一個 service,每一個 service 運行了若干容器。在這樣的架構中,service 之間是必然要通訊的。
一種實現方法是將全部 service 都 publish 出去,而後經過 routing mesh 訪問。但明顯的缺點是把 memcached 和 mysql 也暴露到外網,增長了安全隱患。
若是不 publish,那麼 swarm 就要提供一種機制,可以:
這其實就是服務發現(service discovery)。Docker Swarm 原生就提供了這項功能,經過服務發現,service 的使用者不須要知道 service 運行在哪裏,IP 是多少,有多少個副本,就能與 service 通訊。
要使用服務發現,須要相互通訊的 service 必須屬於同一個 overlay 網絡,因此咱們先得建立一個新的 overlay 網絡。
[root@swarm-manager ~]# docker network create --driver overlay myapp_net rdozkrfo8mg9y9t3m8swiyv8q [root@swarm-manager ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 4508165c1437 bridge bridge local e56359b1d013 docker_gwbridge bridge local 266cc54ae977 host host local t4xnhmp6y5nr ingress overlay swarm rdozkrfo8mg9 myapp_net overlay swarm 436b29f1c660 none null local
注意:目前 ingress
沒有提供服務發現,必須建立本身的 overlay 網絡。
部署一個 web 服務,並將其掛載到新建立的 overlay 網絡。
[root@swarm-manager ~]# docker service create --name my_web --replicas=3 --network myapp_net nginx:1.14-alpine hlv54albpldu99ox7a5bnpsch overall progress: 3 out of 3 tasks 1/3: running [==================================================>] 2/3: running [==================================================>] 3/3: running [==================================================>] verify: Service converged [root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS v6luevjpk1of my_web.1 nginx:1.14-alpine swarm-worker1 Running Running 22 seconds ago o6orjanarrk8 my_web.2 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago zo6hgkztxzzx my_web.3 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago
部署一個 util 服務用於測試,掛載到同一個 overlay 網絡。
[root@swarm-manager ~]# docker service create --name util --network myapp_net busybox sleep 10000000 pa8qw96mx4ru0bcb6krz21shi overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged
sleep 10000000
的做用是保持 busybox 容器處於運行的狀態,咱們纔可以進入到容器中訪問 service my_web
。
經過 docker service ps util
確認 util 所在的節點爲 swarm-worker1。
[root@swarm-manager ~]# docker service ps util ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS uuf4yyfra9sd util.1 busybox:latest swarm-worker1 Running Running about a minute ago
登陸到 swarm-worker1,在容器 util.1 中 ping 服務 my_web
。
[root@swarm-worker1 ~]# docker exec util.1.uuf4yyfra9sdqqbyd9mchcewt ping -c 3 my_web PING my_web (10.0.0.2): 56 data bytes 64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.141 ms 64 bytes from 10.0.0.2: seq=1 ttl=64 time=0.080 ms 64 bytes from 10.0.0.2: seq=2 ttl=64 time=0.080 ms --- my_web ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.080/0.100/0.141 ms
能夠看到 my_web
的 IP 爲 10.0.0.2
,這是哪一個副本的 IP 呢?
其實哪一個副本的 IP 都不是。10.0.0.2
是 my_web
service 的 VIP(Virtual IP),swarm 會將對 VIP 的訪問負載均衡到每個副本。
對於服務的使用者(這裏是 util.1),根本不須要知道 my_web
副本的 IP,也不須要知道 my_web
的 VIP,只需直接用 service 的名字 my_web
就能訪問服務。
滾動更新下降了應用更新的風險,若是某個副本更新失敗,整個更新將暫停,其餘副本則能夠繼續提供服務。同時,在更新的過程當中,老是有副本在運行的,所以也保證了業務的連續性。
下面咱們將部署三副本的服務,鏡像使用 nginx:1.14-alpine,而後將其更新到 nginx:1.15-alpine。
[root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS v6luevjpk1of my_web.1 nginx:1.14-alpine swarm-worker1 Running Running 12 minutes ago o6orjanarrk8 my_web.2 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago zo6hgkztxzzx my_web.3 nginx:1.14-alpine swarm-worker2 Running Running 11 hours ago
docker service update --image httpd:2.2.32 my_web
--image
指定新的鏡像。
Swarm 將按照以下步驟執行滾動更新:
docker service ps
查看更新結果。
[root@swarm-manager ~]# docker service update --image nginx:1.15-alpine my_web my_web overall progress: 3 out of 3 tasks 1/3: running 2/3: running 3/3: running verify: Service converged [root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ws8ym7uxht1g my_web.1 nginx:1.15-alpine swarm-worker1 Running Running 15 seconds ago v6luevjpk1of \_ my_web.1 nginx:1.14-alpine swarm-worker1 Shutdown Shutdown 20 seconds ago unbw58qiakb9 my_web.2 nginx:1.15-alpine swarm-worker2 Running Running 11 hours ago o6orjanarrk8 \_ my_web.2 nginx:1.14-alpine swarm-worker2 Shutdown Shutdown 11 hours ago eqkbqmzyllxi my_web.3 nginx:1.15-alpine swarm-worker2 Running Running 11 hours ago zo6hgkztxzzx \_ my_web.3 nginx:1.14-alpine swarm-worker2 Shutdown Shutdown 11 hours ago
默認配置下,Swarm 一次只更新一個副本,而且兩個副本之間沒有等待時間。咱們能夠經過 --update-parallelism
設置並行更新的副本數目,經過 --update-delay
指定滾動更新的間隔時間。
好比執行以下命令:
docker service update --replicas 6 --update-parallelism 2 --update-delay 1m30s my_web
service 增長到六個副本,每次更新兩個副本,間隔時間一分半鐘。
[root@swarm-manager ~]# docker service update --replicas 6 --update-parallelism 2 --update-delay 1m30s my_web my_web overall progress: 6 out of 6 tasks 1/6: running 2/6: running 3/6: running 4/6: running 5/6: running 6/6: running verify: Service converged [root@swarm-manager ~]# docker service inspect --pretty my_web ID: hlv54albpldu99ox7a5bnpsch Name: my_web Service Mode: Replicated Replicas: 6 Placement: UpdateConfig: Parallelism: 2 Delay: 1m30s On failure: pause Monitoring Period: 5s Max failure ratio: 0 Update order: stop-first RollbackConfig: Parallelism: 1 On failure: pause Monitoring Period: 5s Max failure ratio: 0 Rollback order: stop-first ContainerSpec: Image: nginx:1.15-alpine@sha256:2e497c294e3ba84aaeab7a0fbb1027819cd1f5f5892ed3c4a82b8b05010090da Init: false Resources: Networks: myapp_net Endpoint Mode: vip
docker service ps
確保6個副本處於正常狀態。
[root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ws8ym7uxht1g my_web.1 nginx:1.15-alpine swarm-worker1 Running Running 3 minutes ago v6luevjpk1of \_ my_web.1 nginx:1.14-alpine swarm-worker1 Shutdown Shutdown 3 minutes ago unbw58qiakb9 my_web.2 nginx:1.15-alpine swarm-worker2 Running Running 11 hours ago o6orjanarrk8 \_ my_web.2 nginx:1.14-alpine swarm-worker2 Shutdown Shutdown 11 hours ago eqkbqmzyllxi my_web.3 nginx:1.15-alpine swarm-worker2 Running Running 11 hours ago zo6hgkztxzzx \_ my_web.3 nginx:1.14-alpine swarm-worker2 Shutdown Shutdown 11 hours ago i0nuldq0b6fy my_web.4 nginx:1.15-alpine swarm-worker1 Running Running 52 seconds ago m8ofettpaj9n my_web.5 nginx:1.15-alpine swarm-worker2 Running Running 11 hours ago zphfbb64m5t8 my_web.6 nginx:1.15-alpine swarm-worker1 Running Running 52 seconds ago
將鏡像更新到nginx:1.15.7-alpine
[root@swarm-manager ~]# docker service update --image nginx:1.15.7-alpine my_web my_web overall progress: 6 out of 6 tasks 1/6: running 2/6: running 3/6: running 4/6: running 5/6: running 6/6: running verify: Service converged [root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS kc2y0tedle3u my_web.1 nginx:1.15.7-alpine swarm-worker1 Running Running 21 seconds ago ws8ym7uxht1g \_ my_web.1 nginx:1.15-alpine swarm-worker1 Shutdown Shutdown 21 seconds ago v6luevjpk1of \_ my_web.1 nginx:1.14-alpine swarm-worker1 Shutdown Shutdown 8 minutes ago mebv7vaxnn3v my_web.2 nginx:1.15.7-alpine swarm-worker2 Running Running 11 hours ago unbw58qiakb9 \_ my_web.2 nginx:1.15-alpine swarm-worker2 Shutdown Shutdown 11 hours ago o6orjanarrk8 \_ my_web.2 nginx:1.14-alpine swarm-worker2 Shutdown Shutdown 11 hours ago rhyrbqpna2jm my_web.3 nginx:1.15.7-alpine swarm-worker2 Running Running 11 hours ago eqkbqmzyllxi \_ my_web.3 nginx:1.15-alpine swarm-worker2 Shutdown Shutdown 11 hours ago zo6hgkztxzzx \_ my_web.3 nginx:1.14-alpine swarm-worker2 Shutdown Shutdown 11 hours ago vnwofhlgrn3s my_web.4 nginx:1.15.7-alpine swarm-worker1 Running Running about a minute ago i0nuldq0b6fy \_ my_web.4 nginx:1.15-alpine swarm-worker1 Shutdown Shutdown about a minute ago pvfa2dhzqhod my_web.5 nginx:1.15.7-alpine swarm-worker2 Running Running 11 hours ago m8ofettpaj9n \_ my_web.5 nginx:1.15-alpine swarm-worker2 Shutdown Shutdown 11 hours ago yciilsu8di50 my_web.6 nginx:1.15.7-alpine swarm-worker1 Running Running 3 minutes ago zphfbb64m5t8 \_ my_web.6 nginx:1.15-alpine swarm-worker1 Shutdown Shutdown 3 minutes ago
Swarm 還有個方便的功能是回滾,若是更新後效果不理想,能夠經過 --rollback
快速恢復到更新以前的狀態。
請注意,--rollback
只能回滾到上一次執行 docker service update
以前的狀態,並不能無限制地回滾。
[root@swarm-manager ~]# docker service update --rollback my_web my_web rollback: manually requested rollback overall progress: rolling back update: 6 out of 6 tasks 1/6: running [> ] 2/6: running [> ] 3/6: running [> ] 4/6: running [> ] 5/6: running [> ] 6/6: running [> ] verify: Service converged [root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS h3ajwiltt5si my_web.1 nginx:1.15-alpine swarm-worker1 Running Running about a minute ago kc2y0tedle3u \_ my_web.1 nginx:1.15.7-alpine swarm-worker1 Shutdown Shutdown about a minute ago ws8ym7uxht1g \_ my_web.1 nginx:1.15-alpine swarm-worker1 Shutdown Shutdown 3 minutes ago v6luevjpk1of \_ my_web.1 nginx:1.14-alpine swarm-worker1 Shutdown Shutdown 11 minutes ago mz9biuxzrjpl my_web.2 nginx:1.15-alpine swarm-worker2 Running Running 11 hours ago mebv7vaxnn3v \_ my_web.2 nginx:1.15.7-alpine swarm-worker2 Shutdown Shutdown 11 hours ago unbw58qiakb9 \_ my_web.2 nginx:1.15-alpine swarm-worker2 Shutdown Shutdown 11 hours ago o6orjanarrk8 \_ my_web.2 nginx:1.14-alpine swarm-worker2 Shutdown Shutdown 11 hours ago 7kjpoptdhxgl my_web.3 nginx:1.15-alpine swarm-worker2 Running Running 11 hours ago rhyrbqpna2jm \_ my_web.3 nginx:1.15.7-alpine swarm-worker2 Shutdown Shutdown 11 hours ago eqkbqmzyllxi \_ my_web.3 nginx:1.15-alpine swarm-worker2 Shutdown Shutdown 11 hours ago zo6hgkztxzzx \_ my_web.3 nginx:1.14-alpine swarm-worker2 Shutdown Shutdown 11 hours ago dehr4bbs3e58 my_web.4 nginx:1.15-alpine swarm-worker1 Running Running 50 seconds ago vnwofhlgrn3s \_ my_web.4 nginx:1.15.7-alpine swarm-worker1 Shutdown Shutdown 51 seconds ago i0nuldq0b6fy \_ my_web.4 nginx:1.15-alpine swarm-worker1 Shutdown Shutdown 5 minutes ago wshw5cdo3v43 my_web.5 nginx:1.15-alpine swarm-worker2 Running Running 11 hours ago pvfa2dhzqhod \_ my_web.5 nginx:1.15.7-alpine swarm-worker2 Shutdown Shutdown 11 hours ago m8ofettpaj9n \_ my_web.5 nginx:1.15-alpine swarm-worker2 Shutdown Shutdown 11 hours ago uqejx1yrc6yx my_web.6 nginx:1.15-alpine swarm-worker1 Running Running 58 seconds ago yciilsu8di50 \_ my_web.6 nginx:1.15.7-alpine swarm-worker1 Shutdown Shutdown 59 seconds ago zphfbb64m5t8 \_ my_web.6 nginx:1.15-alpine swarm-worker1 Shutdown Shutdown 6 minutes ago
Swarm 能夠在 service 建立或運行過程當中靈活地經過 --replicas
調整容器副本的數量,內部調度器則會根據當前集羣的資源使用情況在不一樣 node 上啓停容器,這就是 service 默認的 replicated
mode。在此模式下,node 上運行的副本數有多有少,通常狀況下,資源更豐富的 node 運行的副本數更多,反之亦然。
除了 replicated
mode,service 還提供了一個 global
mode,其做用是強制在每一個 node 上都運行一個且最多一個副本。
此模式特別適合須要運行 daemon 的集羣環境。好比要收集全部容器的日誌,就能夠 global
mode 建立 service,在全部 node 上都運行 gliderlabs/logspout
容器,即便以後有新的 node 加入,swarm 也會自動在新 node 上啓動一個 gliderlabs/logspout
副本。
[root@swarm-manager ~]# docker service create \ > --mode global \ > --name logspout \ > --mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock \ > gliderlabs/logspout su2vyv5n6vaazpj8ds3cvl14y overall progress: 2 out of 2 tasks byxpoc4rgi45: running jfpu6n3qt4gq: running verify: Service converged [root@swarm-manager ~]# docker service ps logspout ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS z1633gpkqvh7 logspout.jfpu6n3qt4gqnoqs8lv36o5fn gliderlabs/logspout:latest swarm-worker1 Running Running 21 seconds ago 8uibx9n8dt56 logspout.byxpoc4rgi45jz1d8vi5hgrog gliderlabs/logspout:latest swarm-worker2 Running Running 11 hours ago
能夠經過 docker service inspect
查看 service 的 mode。
[root@swarm-manager ~]# docker service inspect logspout ...... "Mode": { "Global": {} }, ......
這裏是 Global
,若是建立 service 時不指定,默認是 Replicated
。
不管採用 global mode 仍是 replicated mode,副本運行在哪些節點都是由 Swarm 決定的,做爲用戶咱們有沒有可能精細控制 service 的運行位置呢?
能,使用 label
邏輯分兩步:
label 能夠靈活描述 node 的屬性,其形式是 key=value,用戶能夠任意指定,例如將 swarm-worker1
做爲測試環境,爲其添加 label env=test
:
[root@swarm-manager ~]# docker node update --label-add env=test swarm-worker1 swarm-worker1 [root@swarm-manager ~]# docker node inspect swarm-worker1 [ { "ID": "jfpu6n3qt4gqnoqs8lv36o5fn", "Version": { "Index": 388 }, "CreatedAt": "2018-12-25T02:43:42.19392138Z", "UpdatedAt": "2018-12-26T03:52:58.276285242Z", "Spec": { "Labels": { "env": "test"
對應的,將 swarm-worker2
做爲生產環境,添加 label env=prod
:
[root@swarm-manager ~]# docker node update --label-add env=prod swarm-worker2 swarm-worker2 [root@swarm-manager ~]# docker node inspect swarm-worker2 [ { "ID": "byxpoc4rgi45jz1d8vi5hgrog", "Version": { "Index": 389 }, "CreatedAt": "2018-12-25T02:43:44.590690728Z", "UpdatedAt": "2018-12-26T03:54:09.646331335Z", "Spec": { "Labels": { "env": "prod" },
如今部署 service 到測試環境:
[root@swarm-manager ~]# docker service create \ > --constraint node.labels.env==test \ > --replicas 3 \ > --name my_web \ > --publish 8080:80 \ > nginx:1.15.7-alpine [root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 9huefun6bfw8 my_web.1 nginx:1.15.7-alpine swarm-worker1 Running Running 24 seconds ago tdyah0y5wflf my_web.2 nginx:1.15.7-alpine swarm-worker1 Running Running 24 seconds ago 6dssuoosib4w my_web.3 nginx:1.15.7-alpine swarm-worker1 Running Running 24 seconds ago
--constraint node.labels.env==test
限制將 service 部署到 label=test 的 node,即 swarm-worker1
。從部署結果看,三個副本所有都運行在 swarm-worker1
上。
能夠經過 docker service inspect
查看 --constraint
的設置:
[root@swarm-manager ~]# docker service inspect my_web --pretty ID: vgcmd2r8pznw6koqwf4l896hv Name: my_web Service Mode: Replicated Replicas: 3 Placement: Constraints: [node.labels.env==test]
更新 service,將其遷移到生產環境:
[root@swarm-manager ~]# docker service update --constraint-add node.labels.env==prod my_web my_web overall progress: 3 out of 3 tasks 1/3: running 2/3: running 3/3: running verify: Service converged [root@swarm-manager ~]# docker service ps my_web ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 0z09qjd1iaj8 my_web.1 nginx:1.15.7-alpine swarm-worker2 Running Running 13 hours ago 9huefun6bfw8 \_ my_web.1 nginx:1.15.7-alpine swarm-worker1 Shutdown Shutdown 2 hours ago wi9ab6ubjd6l my_web.2 nginx:1.15.7-alpine swarm-worker2 Running Running 13 hours ago tdyah0y5wflf \_ my_web.2 nginx:1.15.7-alpine swarm-worker1 Shutdown Shutdown 2 hours ago yk7a48parkrn my_web.3 nginx:1.15.7-alpine swarm-worker2 Running Running 13 hours ago 6dssuoosib4w \_ my_web.3 nginx:1.15.7-alpine swarm-worker1 Shutdown
刪除並添加新的 constraint,設置 node.labels.env==prod
,最終全部副本都遷移到了 swarm-worker2
。
label 還能夠跟 global 模式配合起來使用,好比只收集生產環境中容器的日誌。
[root@swarm-manager ~]# docker service create \ > --mode global \ > --constraint node.labels.env==prod \ > --name logspout \ > --mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock \ > gliderlabs/logspout [root@swarm-manager ~]# docker service ps logspout ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 6kvcjfddostu logspout.byxpoc4rgi45jz1d8vi5hgrog gliderlabs/logspout:latest swarm-worker2 Running Running 12 hours ago
只有 swarm-worker2
節點上纔會運行 logspout。
Docker 只能從容器啓動進程的返回代碼判斷其狀態,而對於容器內部應用的運行狀況基本沒有了解。
執行 docker run
命令時,一般會根據 Dockerfile 中的 CMD 或 ENTRYPOINT 啓動一個進程,這個進程的狀態就是 docker ps
STATUS
列顯示容器的狀態。
[root@swarm-worker2 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7ee058b8f935 gliderlabs/logspout:latest "/bin/logspout" 2 minutes ago Up 2 minutes 80/tcp logspout.byxpoc4rgi45jz1d8vi5hgrog.6kvcjfddostuz9bv6bltx9vl1 b92cb165214c nginx:1.15.7-alpine "nginx -g 'daemon of…" 2 hours ago Up 2 hours 80/tcp my_web.2.wi9ab6ubjd6lyzc4g05f863w6 866b27b17a11 nginx:1.15.7-alpine "nginx -g 'daemon of…" 2 hours ago Up 2 hours 80/tcp my_web.1.0z09qjd1iaj8aq6ih039od4bi ae8a52638e94 nginx:1.15.7-alpine "nginx -g 'daemon of…" 2 hours ago Up 2 hours 80/tcp my_web.3.yk7a48parkrnct7r74bp5m24v 97fd40918b21 nginx:1.15-alpine "nginx -g 'daemon of…" 3 hours ago Exited (0) 2 hours ago my_web.3.7kjpoptdhxgldkpgo8gib29df 9b62f2347853 nginx:1.15-alpine "nginx -g 'daemon of…" 3 hours ago Exited (0) 2 hours ago my_web.5.wshw5cdo3v43zz4do2zi30hfi
命令顯示:
UP
。Exited (0)
。Exited (137)
、Exited (1)
等。即便容器狀態是 UP
,也不能保證應用沒有問題。web server 雖然沒有崩潰,但若是老是返回 HTTP 500 - Internal Server Error
,對應用來講這就是很嚴重的故障。
Docker 支持的 Health Check 能夠是任何一個單獨的命令,Docker 會在容器中執行該命令,若是返回 0,容器被認爲是 healthy
,若是返回 1,則爲 unhealthy
。
對於提供 HTTP 服務接口的應用,經常使用的 Health Check 是經過 curl
檢查 HTTP 狀態碼,好比:
curl --fail http://localhost:8080/ || exit 1
若是 curl
命令檢測到任何一個錯誤的 HTTP 狀態碼,則返回 1,Health Check 失敗。
[root@swarm-manager ~]# docker service create --name my_db \ --health-cmd "curl --fail http://localhost:8091/pools || exit 1" \ couchbase x12gbja26pb9unlx2l2of5q7x overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged [root@swarm-manager ~]# docker service ps my_db ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 80c0p3cs7y7k my_db.1 couchbase:latest swarm-worker1 Running Running about a minute ago
--health-cmd
Health Check 的命令,還有幾個相關的參數:
--timeout
命令超時的時間,默認 30s。--interval
命令執行的間隔時間,默認 30s。--retries
命令失敗重試的次數,默認爲 3,若是 3 次都失敗了則會將容器標記爲 unhealthy
。swarm 會銷燬並重建 unhealthy
的副本。經過 docker ps
能夠查看到容器的狀態爲 healthy
:
[root@swarm-worker1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 072cad1caa46 couchbase:latest "/entrypoint.sh couc…" 2 minutes ago Up 2 minutes (healthy) 8091-8096/tcp, 11207/tcp, 11210-11211/tcp, 18091-18096/tcp my_db.1.80c0p3cs7y7kc9836ngxaetat
下面模擬一個 unhealthy
的場景,curl
指向一個不存在的 url。(未測試成功)
docker service create --name my_db \ --health-cmd "curl --fail http://localhost:8091/non-exist || exit 1" \ couchbase
容器被標記爲 unhealthy
,其緣由是 curl 連續三次返回 404 錯誤。
Docker 默認只能經過容器進程的返回碼判斷容器的狀態,Health Check 則可以從業務角度判斷應用是否發生故障,是否須要重啓。
咱們常常要向容器傳遞敏感信息,最多見的莫過於密碼了。好比:
docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql
在啓動 MySQL 容器時咱們經過環境變量 MYSQL_ROOT_PASSWORD
設置了 MySQL 的管理員密碼。不過密碼是以明文的形式寫在 docker run
命令中,有潛在的安全隱患。
爲了解決這個問題,docker swarm 提供了 secret 機制,容許將敏感信息加密後保存到 secret 中,用戶能夠指定哪些容器可使用此 secret。
若是使用 secret 啓動 MySQL 容器,方法是:
一、在 swarm manager 中建立 secret my_secret_data
,將密碼保存其中。
[root@swarm-manager ~]# echo "my-secret-pw" | docker secret create my_secret_data - i0n061n5kpat7q8kmp4q8n2ud
二、啓動 MySQL service,並指定使用 secret my_secret_data
。
[root@swarm-manager ~]# docker service create \ > --name mysql \ > --secret source=my_secret_data,target=mysql_root_password \ > -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \ > mysql:latest t92t9rmooxab9netuxs20itzf overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged
① source 指定容器使用 secret 後,secret 會被解密並存放到容器的文件系統中,默認位置爲 /run/secrets/
--secretsource=my_secret_data,target=mysql_root_password
的做用就是指定使用 secret
my_secret_data
,而後把器解密後的內容保存到容器
/run/secrets/mysql_root_password
文件中,文件名稱
mysql_root_password
由
target
指定。
② 環境變量 MYSQL_ROOT_PASSWORD_FILE
指定從 /run/secrets/mysql_root_password
中讀取並設置 MySQL 的管理員密碼。
答:在咱們的例子中建立 secret 和使用 secret 是分開完成的,其好處是將密碼和容器解耦合。secret 能夠由專人(好比管理員)建立,而運行容器的用戶只需使用 secret 而不須要知道 secret 的內容。也就是說,例子中的這兩個步驟能夠由不一樣的人在不一樣的時間完成。
答:這須要 image 的支持。若是 image 但願它部署出來的容器可以從 secret 中讀取數據,那麼此 image 就應該提供一種方式,讓用戶可以指定 secret 的位置。最經常使用的方法就是經過環境變量,Docker 的不少官方 image 都是採用這種方式。好比 MySQL 鏡像同時提供了 MYSQL_ROOT_PASSWORD
和 MYSQL_ROOT_PASSWORD_FILE
兩個環境變量。用戶能夠用 MYSQL_ROOT_PASSWORD
顯示地設置管理員密碼,也能夠經過 MYSQL_ROOT_PASSWORD_FILE
指定 secret 路徑。
secret 可用於管理:
secret 只能在 swarm service 中使用。普通容器想使用 secret,能夠將其包裝成副本數爲 1 的 service。
數據中心有三套 swarm 環境,分別用於開發、測試和生產。對於同一個應用,在不一樣的環境中使用不一樣的用戶名密碼。咱們能夠在三個環境中分別建立 secret,不過使用相同的名字,好比 username
和 password
。應用部署時只須要指定 secret 名字,這樣咱們就能夠用同一套腳本在不一樣的環境中部署應用了。
除了敏感數據,secret 固然也能夠用於非敏感數據,好比配置文件。不過目前新版本的 Docker 提供了 config 子命令來管理不須要加密的數據。config 與 secret 命令的使用方法徹底一致。
當在 swarm 中建立 secret 時,Docker 經過 TLS 鏈接將加密後的 secret 發送給因此的 manager 節點。
secret 建立後,即便是 swarm manager 也沒法查看 secret 的明文數據,只能經過 docker secret inspect
查看 secret 的通常信息。
[root@swarm-manager ~]# docker secret inspect my_secret_data [ { "ID": "i0n061n5kpat7q8kmp4q8n2ud", "Version": { "Index": 2820 }, "CreatedAt": "2019-01-02T02:11:42.350879188Z", "UpdatedAt": "2019-01-02T02:11:42.350879188Z", "Spec": { "Name": "my_secret_data", "Labels": {} } } ]
只有當 secret 被指定的 service 使用是,Docker 纔會將解密後的 secret 以文件的形式 mount 到容器中,默認的路徑爲/run/secrets/<secret_name>
。例如在前面 MySQL 的例子中,咱們能夠在容器中查看 secret。
[root@swarm-manager ~]# docker service ps mysql ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS fd9ggspslrvv mysql.1 mysql:latest swarm-worker1 Running Running 5 minutes ago [root@swarm-worker1 ~]# docker exec -it mysql.1.fd9ggspslrvv3et2s1lhj2drb cat /run/secrets/mysql_root_password my-secret-pw
當容器中止運行,Docker 會 unmount secret,並從節點上清除。
建立一個 MySQL service,將密碼保存到 secret 中。咱們還會建立一個 WordPress service,它將使用 secret 鏈接 MySQL。這個例子將展現如何用 secret 避免在 image 中存放敏感信息,或者在命令行中直接傳遞敏感數據。
實驗步驟以下:
建立 secret 存放 MySQL 的管理員密碼。
[root@swarm-manager ~]# openssl rand -base64 20 | docker secret create mysql_root_password - weiz3fof9qe56sjtztvixvjco
注意 ag7injh6juonwl09lq8st36o8
是新建立的 service 的 ID,而非 service 的內容。
上面這種方式是從標準輸入讀取 secret 的內容,也能夠指定從文件中讀取,例如:
openssl rand -base64 20 > password.txt docker secret create my_password ./password.txt
通常狀況下,應用不會直接用 root 密碼訪問 MySQL。咱們會建立一個單獨的用戶 workpress
,密碼存放到 secret mysql_password
中。
[root@swarm-manager ~]# openssl rand -base64 20 | docker secret create mysql_password - zv55ejrqimhflaajx5f6oez8e [root@swarm-manager ~]# docker secret ls ID NAME DRIVER CREATED UPDATED zv55ejrqimhflaajx5f6oez8e mysql_password 45 seconds ago 45 seconds ago weiz3fof9qe56sjtztvixvjco mysql_root_password 2 minutes ago 2 minutes ago
MySQL 經過 overlay 網絡 mysql_private
與 WordPress 通訊,不須要將 MySQL service 暴露給外部網絡和其餘容器。
[root@swarm-manager ~]# docker network create -d overlay mysql_private 45j2p7ley2b6s8buyxohi9a27
命令以下:
[root@swarm-manager ~]# docker service create \ > --name mysql \ > --network mysql_private \ > --secret source=mysql_root_password,target=mysql_root_password \ > --secret source=mysql_password,target=mysql_password \ > -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \ > -e MYSQL_PASSWORD_FILE="/run/secrets/mysql_password" \ > -e MYSQL_USER="wordpress" \ > -e MYSQL_DATABASE="wordpress" \ > mysql:latest 8xg5dmt7rn6ecglv1frzcd9h0 overall progress: 1 out of 1 tasks 1/1: running verify: Service converged [root@swarm-manager ~]# docker service ls ID NAME MODE REPLICAS IMAGE PORTS 8xg5dmt7rn6e mysql replicated 1/1 mysql:latest [root@swarm-manager ~]# docker service ps mysql ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS evv84yno073p mysql.1 mysql:latest swarm-worker1 Running Running about a minute ago
MYSQL_DATABASE
指明建立數據庫 wordpress
。
MYSQL_USER
和 MYSQL_PASSWORD_FILE
指明建立數據庫用戶 workpress
,密碼從 secret mysql_password
中讀取。
有關 mysql 鏡像環境變量更詳細的使用方法可參考 https://hub.docker.com/_/mysql/
MySQL service 已就緒,如今建立 WordPress service。命令以下:
[root@swarm-manager ~]# docker service create \ > --name wordpress \ > --network mysql_private \ > --publish 30000:80 \ > --secret source=mysql_password,target=wp_db_password \ > -e WORDPRESS_DB_HOST="mysql:3306" \ > -e WORDPRESS_DB_NAME="wordpress" \ > -e WORDPRESS_DB_USER="wordpress" \ > -e WORDPRESS_DB_PASSWORD_FILE="/run/secrets/wp_db_password" \ > wordpress:latest dtunutpigfh8a07xsk33fibe6 overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged
WORDPRESS_DB_HOST
指明 MySQL service 地址 mysql:3306
,這裏用到了 DNS。
WORDPRESS_DB_NAME
指明 WordPress 的數據庫爲 wordpress
,與前面 MYSQL_DATABASE
一致。
WORDPRESS_DB_USER
指明鏈接 WordPress 數據庫的用戶爲 wordpress
,與前面 MYSQL_USER
一致。
WORDPRESS_DB_PASSWORD_FILE
指明數據庫的用戶 wordpress
的密碼,從 secret mysql_password
中獲取。
有關 wordpress 鏡像環境變量更詳細的使用方法可參考 https://hub.docker.com/_/wordpress/
訪問 http://[swarm_master_ip]:30000/
能正常顯示初始化界面,代表 WordPress 已經鏈接到 MySQL,部署成功。
回憶一下前面部署 WordPress 應用的過程:
也就是說,這個應用包含了兩個 service:MySQL 和 WordPress,它們之間有明確的依賴關係,必須先啓動 MySQL。
爲了保證這個依賴關係,咱們控制了 docker secret
和 docker service
命令的執行順序,只不過這個過程是手工完成的。
稍微複雜一點的是第三步,經過 if
判斷 MySQL service 是否運行,若是是,則運行 WordPress service,不然經過 while
繼續等待,直到 MySQL 運行。
這個腳本大致上可以工做,實現了自動化,但有兩個缺點:
while
和 if
維護 service 之間的依賴關係也是頗有挑戰的,容易出錯。並且如何判斷 service 正常運行也不是件容易的事,腳本中只簡單檢查了 service 是否存在,並無考慮 service 的實際運行狀態。咱們但願有一種更高效和可靠的方法來部署基於 service 的應用,這就是 stack。
stack 包含一系列 service,這些 service 組成了應用。stack 經過一個 YAML 文件定義每一個 service,並描述 service 使用的資源和各類依賴。
若是將前面 WordPress 用 stack 來定義,YAML 文件能夠是這樣:
[root@swarm-manager ~]# vim wordpress.yml version: '3.1' services: db: image: mysql:latest volumes: - db_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD_FILE: /run/secrets/ad_password secrets: - db_root_password - db_password wordpress: depends_on: - db image: wordpress:latest port: - "8000:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password secrets: - db_password secrets: db_password: file: db_password.txt db_root_password: file: db_root_password.txt volumes: db_data:
YAML 是一種閱讀性很強的文本格式,上面這個 stack 中定義了三種資源:service、secret 和 volume。
① services
定義了兩個 service:db
和 wordpress
。
② secrets
定義了兩個 secret:db_password
和 db_root_password
,在 service db
和 wordpress
的定義中引用了這兩個 secret。
③ volumes
定義了一個 volume:db_data
,service db
使用了此 volume。
④ wordpress
經過 depends_on
指定本身依賴 db
這個 service。Docker 會保證當 db
正常運行後再啓動 wordpress
。
能夠在 YAML 中定義的元素遠遠不止這裏看到的這幾個,完整列表和使用方法可參考文檔 https://docs.docker.com/compose/compose-file/
定義好了 stack YAML 文件,就能夠經過 docker stack deploy
命令部署應用。
[root@swarm-manager ~]# vim db_password.txt [root@swarm-manager ~]# vim db_root_password.txt [root@swarm-manager ~]# docker stack deploy -c wordpress.yml wpstack Creating secret wpstack_db_root_password Creating secret wpstack_db_password Creating service wpstack_db Creating service wpstack_wordpress [root@swarm-manager ~]# docker service ls ID NAME MODE REPLICAS IMAGE PORTS b2tblr32vu8g wpstack_db replicated 1/1 mysql:latest wiwtgohw332z wpstack_wordpress replicated 1/1 wordpress:latest *:8000->80/tcp
部署完成後能夠經過相關命令查看各類資源的狀態。
[root@swarm-manager ~]# docker stack services wpstack ID NAME MODE REPLICAS IMAGE PORTS b2tblr32vu8g wpstack_db replicated 1/1 mysql:latest wiwtgohw332z wpstack_wordpress replicated 1/1 wordpress:latest *:8000->80/tcp [root@swarm-manager ~]# docker stack ps wpstack ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS e98ttrud0oga wpstack_wordpress.1 wordpress:latest swarm-worker2 Running Running 7 days ago 3ko8t5y3ja9e \_ wpstack_wordpress.1 wordpress:latest swarm-worker2 Shutdown Failed 7 days ago "task: non-zero exit (1)" qmsyq2ahutxp wpstack_db.1 mysql:latest swarm-worker1 Running Running about a minute ago l0fs3ijwqm5b \_ wpstack_db.1 mysql:latest swarm-worker1 Shutdown Failed about a minute ago "task: non-zero exit (1)" [root@swarm-manager ~]# docker secret ls ID NAME DRIVER CREATED UPDATED zv55ejrqimhflaajx5f6oez8e mysql_password About an hour ago About an hour ago weiz3fof9qe56sjtztvixvjco mysql_root_password About an hour ago About an hour ago ssqn3cndzy9vh5mw8285td2gq wpstack_db_password 9 minutes ago 9 minutes ago fdudslxllj30van0yyyde4e7o wpstack_db_root_password 9 minutes ago 9 minutes ago
若是想更新 stack 的某些屬性,直接修改 YAML 文件,而後從新部署。好比將 WordPress 的端口由 8000
改成 8888
。
ports: - "8888:80"
再次執行 docker stack deploy
命令。
[root@swarm-manager ~]# docker stack deploy -c wordpress.yml wpstack Updating service wpstack_db (id: b2tblr32vu8gzqxu33iv0xct1) Updating service wpstack_wordpress (id: wiwtgohw332z20o2snocxukh4)
[root@swarm-manager ~]# docker stack ps wpstack ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS jp91ygjocy26 wpstack_wordpress.1 wordpress:latest swarm-worker2 Running Running 7 days ago q4zoh1z2ebv5 \_ wpstack_wordpress.1 wordpress:latest swarm-worker1 Shutdown Shutdown 22 seconds ago ixmhlli95l2e \_ wpstack_wordpress.1 wordpress:latest swarm-worker2 Shutdown Failed 7 days ago "task: non-zero exit (1)" yn0n3fhnawvr \_ wpstack_wordpress.1 wordpress:latest swarm-worker2 Shutdown Failed 7 days ago "task: non-zero exit (1)" 2w9dhvz3ifzx \_ wpstack_wordpress.1 wordpress:latest swarm-worker2 Shutdown Failed 7 days ago "task: non-zero exit (1)" qmsyq2ahutxp wpstack_db.1 mysql:latest swarm-worker1 Running Running 3 minutes ago l0fs3ijwqm5b \_ wpstack_db.1 mysql:latest swarm-worker1 Shutdown Failed 3 minutes ago "task: non-zero exit (1)"
爲了更新端口,swarm 啓動了一個新的 wpstack_wordpress
容器,以前的容器已經被 shutdown。
要刪除 stack 也很簡單:
[root@swarm-manager ~]# docker stack rm wpstack Removing service wpstack_db Removing service wpstack_wordpress Removing secret wpstack_db_root_password Removing secret wpstack_db_password Removing network wpstack_default
docker stack rm
會將 stack 相關的因此資源清除乾淨。
stack 將應用所包含的 service,依賴的 secret、voluem 等資源,以及它們之間的關係定義在一個 YAML 文件中。相比較手工執行命令或是腳本,stack 有明顯的優點。
What
,是 stack 最終要達到的狀態。How
。顯而易見,What
更直觀,也更容易理解。至於如何將 What
翻譯成 How
,這就是 Docker swarm 的任務了,用戶只須要告訴 Docker 想達到什麼效果。docker stack deploy
。stack 的這種自包含特性使得在不一樣的 Docker 環境中部署應用變得極其簡單。在開發、測試和生成環境中部署能夠徹底採用同一份 YAML,並且每次部署的結果都是一致的。