返回文章列表

Docker Swarm 服務叢集與擴充套件佈署

本文探討 Docker Swarm 的服務叢集與擴充套件佈署,包含服務間網路連線組態、使用 Docker Compose 指定網路、驗證網路組態、服務擴充套件與縮減,以及結合 Ansible 和 Jenkins 實作自動化佈署。文章涵蓋了 Docker Swarm 的核心概念和實務操作,並以實際案例展示如何利用

容器技術 DevOps

Docker Swarm 提供了原生網路功能,簡化了容器間的通訊。透過 overlay 網路,不同主機上的容器如同在同一個區域網路內,可以直接透過容器名稱互相存取。文章中以 books-ms 服務為例,示範瞭如何使用 Docker Compose 定義服務網路,並透過 docker network create 建立 overlay 網路。同時,也說明瞭如何透過 Consul 查詢服務地址,以及如何使用 docker exec 進入容器驗證網路設定。此外,文章也詳細介紹瞭如何使用 Docker Swarm 擴充套件和縮減服務,並透過 docker ps 命令檢視容器佈署狀態。最後,文章還介紹瞭如何結合 Ansible 和 Jenkins,實作 Docker Swarm 的自動化佈署,並說明瞭藍綠佈署策略的應用。

使用 Docker Swarm 進行服務叢集與擴充套件

服務間的網路連線組態

在前面的章節中,我們探討瞭如何使用 Docker Compose 來佈署服務。現在,我們將深入瞭解如何利用 Docker Swarm 進行服務的叢集與擴充套件。首先,我們來看看服務之間的網路連線是如何組態的。

環境變數與 Docker 網路

當我們執行 docker exec -it books-ms env 命令時,可以看到一系列環境變數被設定。其中,DB_HOST 被設定為 books-ms-db。這表明我們的服務使用了 Docker 網路來進行容器間的通訊。

docker exec -it books-ms env

輸出結果如下:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=eb3443a66355
DB_HOST=books-ms-db
DB_DBNAME=books
DB_COLLECTION=books
HOME=/root

使用 Docker Compose 指定網路

docker-compose-swarm.yml 檔案中,我們指定了 net 引數來定義網路。這樣,Docker Compose 就會為我們的服務建立一個新的網路。

app:
  image: 10.100.198.200:5000/books-ms
  ports:
    - 8080
  net: books-ms
  environment:
    - SERVICE_NAME=books-ms
    - DB_HOST=books-ms-db

db:
  container_name: books-ms-db
  image: mongo
  net: books-ms
  environment:
    - SERVICE_NAME=books-ms-db

建立網路並執行容器

在執行容器之前,我們先建立一個名為 books-ms 的網路。

docker network create books-ms
docker-compose -f docker-compose-swarm.yml up -d db app

驗證網路組態

執行 docker network ls 命令,可以看到 books-ms 網路已經被成功建立。

docker network ls

輸出結果如下:

NETWORK ID          NAME                DRIVER
6e5f816d4800        swarm-node-1/host   host
aa1ccdaefd70        swarm-node-2/docker_gwbridge   bridge
cd8b1c3d9be5        swarm-node-2/none   null
ebcc040e5c0c        swarm-node-1/bridge   bridge
6768bad8b390        swarm-node-1/docker_gwbridge   bridge
8ebdbd3de5a6        swarm-node-1/none   null
58a585d09bbc        books-ms            overlay
de4925ea50d1        swarm-node-2/bridge   bridge
2b003ff6e5da        swarm-node-2/host   host

驗證容器內的主機檔案組態

進入容器並檢視 /etc/hosts 檔案,可以看到主機名 books-ms-db 已經被正確解析。

docker exec -it booksms_app_1 bash
cat /etc/hosts
exit

輸出結果如下:

10.0.0.2    3166318f0f9c
127.0.0.1   localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.0.0.3    books-ms-db
10.0.0.3    books-ms-db.my-network

測試服務功能

透過 Consul 取得服務的 IP 和埠,並傳送 PUT 和 GET 請求來測試服務是否正常運作。

ADDRESS=`curl \
  10.100.192.200:8500/v1/catalog/service/books-ms \
  | jq -r '.[0].ServiceAddress + ":" + (.[0].ServicePort | tostring)'`

curl -H 'Content-Type: application/json' -X PUT -d \
  '{"_id": 2,
    "title": "My Second Book",
    "author": "John Doe",
    "description": "A bit better book"}' \
  $ADDRESS/api/v1/books | jq '.'

curl $ADDRESS/api/v1/books | jq '.'

輸出結果如下:

[
  {
    "author": "John Doe",
    "title": "My Second Book",
    "_id": 2
  }
]

使用 Docker Swarm 進行服務擴充套件

Docker Swarm 允許我們輕鬆地在叢集中擴充套件服務。現在,我們將 books-ms 服務擴充套件到三個例項。

Docker Swarm 的優勢

  • 利用 Docker 網路實作容器間的通訊。
  • 支援跨主機的容器佈署。
  • 可透過 Docker Compose 檔案定義服務和網路。
  • 能夠動態地擴充套件或縮減服務例項數量。

#### 內容解密:

上述指令展示瞭如何使用Docker Swarm進行服務佈署和擴充套件。首先,我們透過docker network create建立了一個overlay型別的網路books-ms,使得不同主機上的容器可以互相通訊。然後,使用docker-compose -f docker-compose-swarm.yml up -d db app命令啟動了資料函式庫和應用程式服務。接著,透過檢查網路組態和容器內的主機檔案,確認了容器間的網路連線正常。最後,透過向Consul查詢服務地址並傳送HTTP請求,驗證了跨主機佈署的服務能夠正常運作。整個流程展現了Docker Swarm在多主機環境下佈署和管理容器的能力。

叢集與擴充套件服務

在前面的章節中,我們已經瞭解瞭如何使用 Docker Swarm 來佈署和擴充套件服務。本文將探討如何根據保留的 CPU 和記憶體來排程容器。

擴充套件服務

首先,讓我們來擴充套件 books-ms 服務到三個例項。

docker-compose -f docker-compose-swarm.yml scale app=3

接著,使用 docker ps 命令來檢視目前執行的容器。

docker ps --filter name=books --format "table {{.Names}}"

輸出結果

NAMES
swarm-node-2/booksms_app_3
swarm-node-1/booksms_app_2
swarm-node-2/books-ms-db
swarm-node-1/booksms_app_1

從輸出結果中,我們可以看到 Swarm 均勻地分配容器到不同的節點上。目前,每個節點執行兩個容器。由於我們要求 Docker Swarm 將 books-ms 容器擴充套件到三個,因此兩個容器執行在不同的節點上,而第三個容器與資料函式庫一起佈署。

內容解密:

  1. docker-compose scale app=3:將 app 服務擴充套件到三個例項。
  2. docker ps --filter name=books --format "table {{.Names}}":列出名稱包含 books 的容器,並以表格形式顯示容器名稱。

縮減服務

服務也可以輕易地縮減。例如,當流量下降時,我們可能希望釋放資源給其他服務。

docker-compose -f docker-compose-swarm.yml scale app=1

內容解密:

  1. docker-compose scale app=1:將 app 服務縮減到一個例項。
  2. Swarm 將移除多餘的容器例項,只保留一個執行中的例項。

根據保留的 CPU 和記憶體排程容器

預設情況下,Swarm 會將容器佈署到執行容器數量最少的伺服器上。然而,在實際情況中,並非所有容器都需要相同的資源。我們可以透過指定所需的 CPU 和記憶體來進一步最佳化 Swarm 的佈署。

檢視目前節點狀態

docker info

輸出結果(相關部分)

...
Nodes: 2
swarm-node-1: 10.100.192.201:2375
└ Containers: 2
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.535 GiB
...
swarm-node-2: 10.100.192.202:2375
└ Containers: 2
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.535 GiB
...

內容解密:

  1. docker info:顯示 Docker 的相關資訊,包括節點狀態。
  2. 目前兩個節點都沒有保留任何 CPU 或記憶體。

使用 CPU 和記憶體限制佈署容器

讓我們嘗試執行一個 MongoDB 容器,並保留一個 CPU 給該程式。

docker run -d --cpu-shares 1 --name db1 mongo

輸出結果(相關部分)

...
Nodes: 2
swarm-node-1: 10.100.192.201:2375
└ Status: Healthy
└ Containers: 3
└ Reserved CPUs: 1 / 1
└ Reserved Memory: 0 B / 1.535 GiB
...
swarm-node-2: 10.100.192.202:2375
└ Status: Healthy
└ Containers: 2
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.535 GiB
...

內容解密:

  1. docker run -d --cpu-shares 1 --name db1 mongo:執行一個 MongoDB 容器,並保留一個 CPU 給該容器。
  2. 由於每個節點只有一個 CPU,因此 Swarm 將該容器佈署到 swarm-node-1 上。

使用記憶體限制佈署容器

我們也可以使用記憶體作為限制條件。例如,佈署一個保留一個 CPU 和一 GB 記憶體的容器。

docker run -d --cpu-shares 1 -m 1g --name db1 mongo

輸出結果(相關部分)

...
Nodes: 2
swarm-node-1: 10.100.192.201:2375
└ Status: Healthy
└ Containers: 3
└ Reserved CPUs: 1 / 1
└ Reserved Memory: 1 GiB / 1.535 GiB
...
swarm-node-2: 10.100.192.202:2375
└ Status: Healthy
└ Containers: 2
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.535 GiB
...

內容解密:

  1. docker run -d --cpu-shares 1 -m 1g --name db1 mongo:執行一個 MongoDB 容器,並保留一個 CPU 和一 GB 記憶體給該容器。
  2. Swarm 將該容器佈署到 swarm-node-1 上,並保留相應的資源。

本章節展示瞭如何使用 Docker Swarm 對服務進行擴充套件和縮減,以及如何根據 CPU 和記憶體限制來排程容器的佈署。這些功能使得在叢集中管理容器變得更加靈活和高效。

自動化佈署與 Docker Swarm 及 Ansible 的整合應用

在前面的章節中,我們已經探討了 Docker Swarm 的基本操作與叢集管理,接下來將深入討論如何結合 Ansible 自動化工具來實作佈署自動化。

準備環境:Jenkins 與 Ansible 的整合

首先,我們需要利用 Ansible 來佈建我們的 cd 節點並安裝 Jenkins。

ansible-playbook /vagrant/ansible/jenkins-node-swarm.yml \
-i /vagrant/ansible/hosts/prod

ansible-playbook /vagrant/ansible/jenkins.yml \
-c local

內容解密:

  1. ansible-playbook 命令用於執行 Ansible 指令碼。
  2. /vagrant/ansible/jenkins-node-swarm.yml 是用於設定 Jenkins 節點的 playbook。
  3. -i /vagrant/ansible/hosts/prod 指定了 inventory 檔案的位置,定義了目標主機。
  4. 第二個命令則是在本地執行 Jenkins 的設定。

Jenkins Workflow 與 Docker Swarm 的整合

Jenkins Workflow 提供了一個靈活的方式來定義佈署流程。我們將探討 books-ms-swarm 這個 Job 的設定。

node("cd") {
    def serviceName = "books-ms"
    def prodIp = "10.100.192.200"
    def proxyIp = "10.100.192.200"
    def proxyNode = "swarm-master"
    def registryIpPort = "10.100.198.200:5000"
    def swarmPlaybook = "swarm.yml"
    def proxyPlaybook = "swarm-proxy.yml"
    def instances = 1

    def flow = load "/data/scripts/workflow-util.groovy"

    git url: "https://github.com/vfarcic/${serviceName}.git"
    flow.provision(swarmPlaybook)
    flow.provision(proxyPlaybook)
    flow.buildTests(serviceName, registryIpPort)
    flow.runTests(serviceName, "tests", "")
    flow.buildService(serviceName, registryIpPort)

    def currentColor = flow.getCurrentColor(serviceName, prodIp)
    def nextColor = flow.getNextColor(currentColor)

    flow.deploySwarm(serviceName, prodIp, nextColor, instances)
    flow.runBGPreIntegrationTests(serviceName, prodIp, nextColor)
    flow.updateBGProxy(serviceName, proxyNode, nextColor)
    flow.runBGPostIntegrationTests(serviceName, prodIp, proxyIp, proxyNode, currentColor, nextColor)
}

內容解密:

  1. node("cd") 指定了執行該 Workflow 的節點。
  2. 定義了一系列變數,例如服務名稱、生產 IP、代理 IP 等。
  3. 載入了一個共用的 Groovy 指令碼 workflow-util.groovy,該指令碼封裝了許多佈署相關的函式。
  4. 使用 git 命令從 GitHub 提取程式碼。
  5. 呼叫 provision 函式執行 Ansible playbook 來佈建 Swarm 叢集和設定代理伺服器。
  6. 編譯、測試、建置服務,並進行藍綠佈署。

Docker Swarm 的佈署策略

在 Docker Swarm 中,我們可以透過不同的策略來控制服務的佈署。預設情況下,Swarm 會根據節點的資源狀況來決定在哪個節點上佈署容器。

docker ps --filter name=db --format "table {{.Names}}"

內容解密:

  1. docker ps 命令用於列出正在執行的容器。
  2. --filter name=db 表示只顯示名字中包含 db 的容器。
  3. --format "table {{.Names}}" 指定了輸出的格式,只顯示容器的名稱。