使用Docker Swarm來運行服務

LakeshaVrol 8年前發布 | 32K 次閱讀 Docker Docker Swarm

本文介紹了Docker 1.12中的Docker Swarm Mode,包括如何安裝Docker Engine、如何建立Swarm集群、如何部署服務和創建Global Service。

Docker的最新版本v1.12,包含了很多更新和Docker Swarm提供的功能。在今天的文章中,我們將探討如何使用Docker Swarm來部署服務。

在Ubuntu 16.04中激活Swarm模式

在我們使用Docker Engine Swarm部署服務之前,我們需要建立一個Swarm集群。因為我們需要1.12新添加的功能,所以我們也要安裝Docker Engine的最新版本。

以下步驟將指導你在Ubuntu 16.04上安裝Docker Engine。對于其他平臺和版本,你可以參考Docker的 官方安裝文檔

設置Docker Apt倉庫

我們會使用Ubuntu的標準安裝方式,依賴于Apt包管理器。因為我們需要安裝最新版本的Docker Engine,所以我們需要配置Apt,從Docker官方Apt倉庫來安裝 docker-engine ,而不是從系統預配置的倉庫。

添加Docker公鑰

配置Apt來使用新倉庫的第一步是想Apt緩存中添加該庫的公鑰。使用 apt-key 命令:

apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

以上的 apt-key 命令向密鑰服務器 p80.pool.sks-keyservers.net 請求一個特定的密鑰( 58118E89F3A912897C070ADBF76221572C52609D )。公鑰將會被用來驗證從新倉庫下載的所有包。

指定Docker倉庫的位置

引入Docker的公鑰,我們可以配置Apt使用Docker的倉庫服務器。我們可以在 /etc/apt/sources.list.d/ 目錄中添加一個條目。

echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" >> /etc/apt/sources.list.d/docker.list

當我們刷新Apt緩存時,Apt將會搜索 sources.list.d/ 目錄下的所有文件,來尋找新的包倉庫。上述命令會創建一個新文件 docker.list ,其中包含了一個添加了 apt.dockerproject.org 倉庫的條目。

更新Apt包緩存

運行 apt-get 命令的 update 選項,來刷新Apt包緩存。

apt-get update

這會觸發Apt重新讀取配置文件,刷新倉庫列表,包含進我們添加的那個倉庫。該命令也會查詢這些倉庫來緩存可用的包列表。

安裝 linux-image-extra

在安裝Docker Engine之前,我們需要安裝一個先決軟件包(prerequisite package)。 linux-image-extra 包是一個內核相關的包,Ubuntu系統需要它來支持 aufs 存儲設備驅動。Docker會使用該驅動來加載卷。

為了安裝該包,我們將使用 apt-get 命令的 install 選項。

apt-get install linux-image-extra-$(uname -r)

在 apt-get 命令中, $(uname -r) 將返回正在運行的內核的版本。任何對于該系統的內核更新應當包括安裝 linux-image-extra ,它的版本需要與新內核版本相一致。如果該包沒有正確更新的話,Docker加載卷的功能可能受到影響。

安裝Docker Engine

在Apt配置好和 linux-image-extra 安裝好之后,我們可以繼續安裝Docker Engine了。我們可以使用 apt-get 命令的 install 選項來安裝 docker-engine 包。

apt-get install docker-engine

此時,我們應該已經安裝好了 Docker Engine v1.12.0 或者更新版本。我們可以執行 docker 命令的 version 選項來驗證我們已經安裝了最新版本。

 

 

docker version

Client:

Version: 1.12.0

API version: 1.24

Go version: go1.6.3

Git commit: 8eab29e

Built: Thu Jul 28 22:11:10 2016

OS/Arch: linux/amd64

Server:

Version: 1.12.0

API version: 1.24

Go version: go1.6.3

Git commit: 8eab29e

Built: Thu Jul 28 22:11:10 2016

OS/Arch: linux/amd64

 

我們可以看到,Server版本和Client版本都是 1.12.0 。接下來,我們會創建Swarm集群。

創建一個Docker Swarm集群

在這一小節中,我們將在多臺機器上執行多個任務。為了更清楚地表述,我會在例子中包含主機名。

我們會使用兩個節點來啟動Swarm集群。此時,兩個節點都按照上述步驟安裝了Docker Engine。

當創建Swarm集群時,我們需要指定一個manager節點。在這個例子中,我們會使用主機名為 swarm-01 的主機作為manager節點。為了使 swarm-01 成為manager節點,我們需要首先在 swarm-01 執行命令來創建Swarm集群。這個命令就是 docker 命令的 swarm init 選項。

 

root@swarm-01:~# docker swarm init --advertise-addr 10.0.0.1

Swarm initialized: current node (awwiap1z5vtxponawdqndl0e7) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join \

--token SWMTKN-1-51pzs5ax8dmp3h0ic72m9wq9vtagevp1ncrgik115qwo058ie6-3fokbd3onl2i8r7dowtlwh7kb \

10.0.0.1:2377

To add a manager to this swarm, run the following command:

docker swarm join \

--token SWMTKN-1-51pzs5ax8dmp3h0ic72m9wq9vtagevp1ncrgik115qwo058ie6-bwex7fd4u5aov4naa5trcxs34 \

10.0.0.1:2377

在上述命令中,除了 swarm init 之外,我們還指定了 --advertise-addr 為 10.0.0.1 。Swarmmanager節點會使用該IP地址來廣告Swarm集群服務。雖然該地址可以是私有地址,重要的是,為了使節點加入該集群,那些節點需要能通過該IP的 2377 端口來訪問manager節點。

在運行 docker swarm init 命令之后,我們可以看到 swarm-01 被賦予了一個節點名字( awwiap1z5vtxponawdqndl0e7 ),并被選為Swarm集群的管理器。輸出中也提供了兩個命令:一個命令可以添加worker節點到swarm中,另一個命令可以添加另一個manager節點到該Swarm中。

Docker Swarm Mode可以支持多個manager節點。然而,其中的一個會被選舉為主節點服務器,它會負責Swarm的編排。

添加worker節點到Swarm集群中

Swarm集群建立之后,我們需要添加一個新的worker節點。

root@swarm-02:~# docker swarm join \

--token SWMTKN-1-51pzs5ax8dmp3h0ic72m9wq9vtagevp1ncrgik115qwo058ie6-3fokbd3onl2i8r7dowtlwh7kb \

10.0.0.1:2377

This node joined a swarm as a worker.

在本例中,我們將 swarm-02 添加到了swarm中,作為worker節點。Swarm集群中的worker節點的角色是用來運行任務(tasks)的;在該例中,任務(tasks)就是容器(containers)。另一方面,manager節點的角色是管理任務(容器)的編排,并維護Swarm集群本身。

除此之外,manager節點本身也是worker節點,也可以運行任務。

查看當前的Swarm節點

我們現在有了一個最基本的兩節點的Swarm集群。我們可以執行 docker 命令的 node ls 選項來驗證集群的狀態。

root@swarm-01:~# docker node ls

ID                           HOSTNAME              STATUS  AVAILABILITY  MANAGER STATUS

13evr7hmiujjanbnu3n92dphk    swarm-02.example.com  Ready   Active        

awwiap1z5vtxponawdqndl0e7 *  swarm-01.example.com  Ready   Active        Leader

從輸出中可以看到, swarm-01 和 swarm-02 都處于 Ready 和 Active 狀態。因此,我們可以繼續在Swarm集群上部署服務了。

創建一個服務

在Docker Swarm Mode中,服務是指一個長期運行(long-running)的Docker容器,它可以被部署到任意一臺worker節點上,可以被遠端系統或者Swarm中其他容器連接和消費(consume)的。

在本例中,我們會部署一個Redis服務。

部署一個有副本的服務

一個有副本的服務是一個Docker Swarm服務,運行了特定數目的副本(replicas)。這些副本是由多個Docker容器的實例組成的。在本例中,每個副本都是一個獨立的Redis實例。

為了創建新服務,我們會使用 docker 命令的 service create 選項。以下命令將創建一個名為 redis 的服務,包含 2 個副本,并在集群中發布 6379 端口。

root@swarm-01:~# docker service create --name redis --replicas 2 --publish 6379:6379 redis

er238pvukeqdev10nfmh9q1kr

除了 service create 選項之外,我們還指定了 --name 為 redis , --replicas 表示該服務需要運行在 2 個不同的節點上。我們可以運行 docker 命令的 service ls 選項來驗證該服務是運行在兩個節點上的。

root@swarm-01:~# docker service ls

ID            NAME   REPLICAS  IMAGE  COMMAND

er238pvukeqd  redis  2/2       redis

從輸出中可以看到, 2 個副本都在運行。如果我們想看到這些任務的更多細節,我們可以運行 docker 命令的 service ps 選項。

root@swarm-01:~# docker service ps redis

ID                         NAME     IMAGE  NODE                  DESIRED STATE  CURRENT STATE           ERROR

5lr10nbpy91csmc91cew5cul1  redis.1  redis  swarm-02.example.com  Running        Running 40 minutes ago  

1t77jsgo1qajxxdekbenl4pgk  redis.2  redis  swarm-01.example.com  Running        Running 40 minutes ago

service ps 選項會顯示特定服務的任務(容器)。在本例中,我們可以看到 redis 服務有一個任務(容器)運行在兩個Swarm節點上。

連接Redis服務

我們已經驗證了服務正在運行,我們可以嘗試從遠端系統,使用 redis-cli 客戶端來連接該服務。

vagrant@vagrant:~$ redis-cli -h swarm-01.example.com -p 6379

swarm-01.example.com:6379>

從上面的連接可以看到,我們已經成功地連接上了 redis 服務。這意味著我們的服務已經運行起來了。

Docker Swarm是如何發布服務的

當我們創建了 redis 服務時,我們使用了 --publish 選項。該選項用來告知Docker將端口 6379 發布為 redis 服務的可用端口。

當Docker發布了服務端口時,它在Swarm集群上的所有節點上監聽該端口。當流量到達該端口時,該流量將被路由到運行該服務的容器上。如果所有節點都運行著一個服務的容器,那么概念是相對標準的;然而,當我們的節點數比副本多時,概念就變得有趣了。

添加第三個worker節點

為了添加另一個worker節點,我們只要簡單地重復第一部分中的安裝步驟。因為我們已經做過這些步驟了,所以我們直接跳到3節點的Swarm集群。再一次地,我們可以運行 docker 命令來檢查集群狀態。

root@swarm-01:~# docker node ls

ID                           HOSTNAME              STATUS  AVAILABILITY  MANAGER STATUS

13evr7hmiujjanbnu3n92dphk    swarm-02.example.com  Ready   Active        

awwiap1z5vtxponawdqndl0e7 *  swarm-01.example.com  Ready   Active        Leader

e4ymm89082ooms0gs3iyn8vtl    swarm-03.example.com  Ready   Active

我們可以看到集群包含三個主機:

  • swarm-01
  • swarm-02
  • swarm-03

當我們創建了兩個副本的服務時,它在 swarm-01 和 swarm-02 上分別創建了任務(容器)。即便我們添加了另一個worker節點,我們可以看到情況仍然是這樣的。

root@swarm-01:~# docker service ps redis

ID                         NAME     IMAGE  NODE                  DESIRED STATE  CURRENT STATE           ERROR

5lr10nbpy91csmc91cew5cul1  redis.1  redis  swarm-02.example.com  Running        Running 55 minutes ago  

1t77jsgo1qajxxdekbenl4pgk  redis.2  redis  swarm-01.example.com  Running        Running 55 minutes ago

Docker Swarm通過replicated服務,可以保證對于每個指定的副本,都運行了一個任務(容器)。當我們創建 redis 服務時,我們指定了 2 個副本。這就意味著,即便我們有了第三個節點,Docker也沒有理由在新節點上創建一個新任務。

此時,我們遇到了一個有趣的情形:我們在 3 個Swarm節點中的 2 個上運行了服務。在non-swarm的世界中,這就意味著當連接第三個Swarm節點時, redis 服務將變得不可用。然而,Swarm Mode中,情況卻不是這樣的。

在一個無任務運行的worker節點上連接服務

之前,我們提到Docker是如何發布服務端口的,Swarm在所有節點上都發布了該端口。有趣的是,當我們連接一個并未運行任何容器的worker節點時,會發生什么呢。

讓我們看一下,當我們連接 swarm-03 的 redis 端口時,會發生什么呢。

vagrant@vagrant:~$ redis-cli -h swarm-03.example.com -p 6379

swarm-03.example.com:6379>

有趣的是,連接竟然成功了。盡管 swarm-03 上并未運行任何 redis 容器,但是連接成功了。這是因為,在內部,Docker將 redis 服務流量重路由到運行了 redis 容器的worker節點。

Docker稱之為入口負載均衡(ingress load balancing)。它的工作方式是,所有worker節點都監聽在發布的服務端口上。當該服務被外部系統調用時,收到流量的節點會通過Docker提供的內部DNS服務,將流量負載均衡該流量。

因此,即便我們將Swarm集群擴展至100個worker節點時, redis 服務的終端用戶可以連接到任意一個worker節點。他們會被重定向到運行了任務(容器)的兩個Docker宿主機之一。

這些重路由和負載均衡對于終端用戶是完全透明的。

讓服務global化

此時,我們已經建立了 redis 服務,運行了 2 個副本,這意味著, 3 個節點中的 2 個正在運行容器。

如果我們希望 redis 服務在每一個worker節點上運行一個實例,我們可以簡單地修改服務的副本數目,從 2 增加到 3 。這意味著,如果我們增加或者減少worker節點數目,我們需要調整副本數目。

我們可以自動化地做這件事,只要把我們的服務變成一個Global Service。Docker Swarm Mode中的Global Service使用了創建一個服務,該服務會自動地在每個worker節點上運行任務。這種方法對于像Redis這樣的一般服務都是有效的。

讓我們重新創建 redis 服務為Global Service。

root@swarm-01:~# docker service create --name redis --mode global --publish 6379:6379 redis

5o8m338zmsped0cmqe0guh2to

同樣是 docker service create 命令,唯一的區別是指定了 --mode 參數為 global 。

服務建立好之后,運行 docker 命令的 service ps 選項,我們可以看到,Docker是如何分發該服務的。

root@swarm-01:~# docker service ps redis

ID                         NAME       IMAGE  NODE                  DESIRED STATE  CURRENT STATE           ERROR

27s6q5yvmyjvty8jvp5k067ul  redis      redis  swarm-03.example.com  Running        Running 26 seconds ago  

2xohhkqvlw7969qj6j0ca70xx   \_ redis  redis  swarm-02.example.com  Running        Running 38 seconds ago  

22wrdkun5f5t9lku6sbprqi1k   \_ redis  redis  swarm-01.example.com  Running        Running 38 seconds ago

我們可以看到,一旦該服務被創建為Global Service,那么每個worker節點上都會運行一個任務。

小結

在本文中,我們不僅安裝了Docker Engine,也創建了一個Swarm集群,部署了一個有副本的服務,然后創建了Global Service。

 

 

來自:http://dockone.io/article/1736

 

 本文由用戶 LakeshaVrol 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!