向 swarm 部署服務

Swarm 服務使用宣告式模型,這意味著您定義服務的期望狀態,並依賴 Docker 維護此狀態。狀態資訊包括(但不限於):

  • 服務容器應執行的映象名稱和標籤
  • 參與服務的容器數量
  • 是否向 Swarm 外部的客戶端公開任何埠
  • 服務是否應在 Docker 啟動時自動啟動
  • 服務重啟時發生的具體行為(例如是否使用滾動重啟)
  • 可以執行服務的節點的特性(例如資源約束和放置偏好)

有關 Swarm 模式的概述,請參閱Swarm 模式關鍵概念。有關服務工作原理的概述,請參閱服務如何工作

建立服務

要建立一個沒有任何額外配置的單副本服務,您只需提供映象名稱。此命令會啟動一個 Nginx 服務,其名稱隨機生成且沒有釋出埠。這是一個簡單的例子,因為您無法與 Nginx 服務互動。

$ docker service create nginx

該服務被排程到一個可用的節點上。要確認服務已成功建立並啟動,請使用 docker service ls 命令。

$ docker service ls

ID                  NAME                MODE                REPLICAS            IMAGE                                                                                             PORTS
a3iixnklxuem        quizzical_lamarr    replicated          1/1                 docker.io/library/nginx@sha256:41ad9967ea448d7c2b203c699b429abe1ed5af331cd92533900c6d77490e0268

建立的服務並不總是立即執行。如果映象不可用、沒有節點滿足您為服務配置的要求,或者由於其他原因,服務可能會處於待定狀態。有關更多資訊,請參閱待定服務

要為您的服務提供一個名稱,請使用 --name 標誌:

$ docker service create --name my_web nginx

就像獨立容器一樣,您可以在映象名稱後新增要執行的命令來指定服務容器應執行的命令。此示例啟動一個名為 helloworld 的服務,它使用一個 alpine 映象並執行 ping docker.com 命令:

$ docker service create --name helloworld alpine ping docker.com

您還可以為服務指定一個要使用的映象標籤。此示例修改了上一個示例,使用 alpine:3.6 標籤:

$ docker service create --name helloworld alpine:3.6 ping docker.com

有關映象標籤解析的更多詳細資訊,請參閱指定服務應使用的映象版本

用於 Swarm 的 gMSA

注意

此示例僅適用於 Windows 容器。

Swarm 現在允許使用 Docker 配置作為 gMSA 憑證規範——這是 Active Directory 認證應用程式的一個要求。這減輕了將憑證規範分發到使用它們的節點上的負擔。

以下示例假定一個 gMSA 及其憑證規範(名為 credspec.json)已經存在,並且將要部署到的節點已為該 gMSA 正確配置。

要使用配置作為憑證規範,首先建立包含憑證規範的 Docker 配置:

$ docker config create credspec credspec.json

現在,您應該有一個名為 credspec 的 Docker 配置,並且您可以使用此憑證規範建立服務。為此,請將 --credential-spec 標誌與配置名稱一起使用,如下所示:

$ docker service create --credential-spec="config://credspec" <your image>

您的服務在啟動時使用 gMSA 憑證規範,但與典型的 Docker 配置(透過傳遞 --config 標誌使用)不同,憑證規範不會掛載到容器中。

使用私有倉庫中的映象建立服務

如果您的映象在需要登入的私有倉庫中可用,請在登入後將 --with-registry-auth 標誌與 docker service create 一起使用。如果您的映象儲存在 registry.example.com(這是一個私有倉庫)上,請使用類似以下的命令:

$ docker login registry.example.com

$ docker service  create \
  --with-registry-auth \
  --name my_service \
  registry.example.com/acme/my_image:latest

這會將登入令牌從您的本地客戶端透過加密的 WAL 日誌傳遞到部署服務的 swarm 節點。有了這些資訊,節點就能夠登入到倉庫並拉取映象。

為託管服務賬戶提供憑證規範

在企業版 3.0 中,透過使用 Docker 配置功能集中分發和管理組託管服務帳戶(gMSA)憑證,安全性得到了提高。Swarm 現在允許使用 Docker 配置作為 gMSA 憑證規範,這減輕了將憑證規範分發到使用它們的節點上的負擔。

注意

此選項僅適用於使用 Windows 容器的服務。

憑證規範檔案在執行時應用,無需基於主機的憑證規範檔案或登錄檔項——沒有 gMSA 憑證被寫入工作節點上的磁碟。您可以在容器啟動之前,讓執行 swarm kit 工作節點的 Docker Engine 可用憑證規範。當使用基於 gMSA 的配置部署服務時,憑證規範將直接傳遞給該服務中容器的執行時。

--credential-spec 必須是以下格式之一:

  • file://<filename>:引用的檔案必須存在於 Docker 資料目錄下的 CredentialSpecs 子目錄中,在 Windows 上預設為 C:\ProgramData\Docker\。例如,指定 file://spec.json 會載入 C:\ProgramData\Docker\CredentialSpecs\spec.json
  • registry://<value-name>:憑證規範從守護程式主機上的 Windows 登錄檔中讀取。
  • config://<config-name>:配置名稱在 CLI 中會自動轉換為配置 ID。將使用指定的 config 中包含的憑證規範。

以下簡單示例從您的 Active Directory (AD) 例項中檢索 gMSA 名稱和 JSON 內容:

$ name="mygmsa"
$ contents="{...}"
$ echo $contents > contents.json

確保您要部署到的節點已為 gMSA 正確配置。

要使用配置作為憑證規範,請在名為 credpspec.json 的憑證規範檔案中建立一個 Docker 配置。您可以為 config 的名稱指定任何名稱。

$ docker config create --label com.docker.gmsa.name=mygmsa credspec credspec.json

現在您可以使用此憑證規範建立服務。使用配置名稱指定 --credential-spec 標誌:

$ docker service create --credential-spec="config://credspec" <your image>

您的服務在啟動時使用 gMSA 憑證規範,但與典型的 Docker 配置(透過傳遞 --config 標誌使用)不同,憑證規範不會掛載到容器中。

更新服務

您可以使用 docker service update 命令更改現有服務的幾乎所有內容。當您更新服務時,Docker 會停止其容器並使用新配置重新啟動它們。

由於 Nginx 是一個 Web 服務,如果您將埠 80 釋出給 swarm 外部的客戶端,它會工作得更好。您可以在建立服務時使用 -p--publish 標誌指定這一點。更新現有服務時,該標誌是 --publish-add。還有一個 --publish-rm 標誌用於移除之前釋出的埠。

假設上一節中的 my_web 服務仍然存在,請使用以下命令更新它以釋出埠 80。

$ docker service update --publish-add 80 my_web

要驗證它是否有效,請使用 docker service ls

$ docker service ls

ID                  NAME                MODE                REPLICAS            IMAGE                                                                                             PORTS
4nhxl7oxw5vz        my_web              replicated          1/1                 docker.io/library/nginx@sha256:41ad9967ea448d7c2b203c699b429abe1ed5af331cd92533900c6d77490e0268   *:0->80/tcp

有關釋出埠如何工作的更多資訊,請參閱釋出埠

您可以更新現有服務的幾乎所有配置細節,包括它執行的映象名稱和標籤。請參閱建立後更新服務的映象

移除服務

要刪除一個服務,請使用 docker service remove 命令。您可以按 ID 或名稱刪除服務,如 docker service ls 命令的輸出所示。以下命令刪除 my_web 服務。

$ docker service remove my_web

服務配置詳情

以下部分提供了有關服務配置的詳細資訊。本主題不涵蓋每個標誌或場景。在幾乎所有您可以在服務建立時定義配置的情況下,您也可以以類似的方式更新現有服務的配置。

請參閱 docker service createdocker service update 的命令列參考,或執行其中一個帶有 --help 標誌的命令。

配置執行時環境

您可以為容器中的執行時環境配置以下選項:

  • 使用 --env 標誌設定環境變數
  • 使用 --workdir 標誌設定容器內的工作目錄
  • 使用 --user 標誌設定使用者名稱或 UID

以下服務的容器設定了環境變數 $MYVARmyvalue,從 /tmp/ 目錄執行,並以 my_user 使用者身份執行。

$ docker service create --name helloworld \
  --env MYVAR=myvalue \
  --workdir /tmp \
  --user my_user \
  alpine ping docker.com

更新現有服務執行的命令

要更新現有服務執行的命令,您可以使用 --args 標誌。以下示例更新一個名為 helloworld 的現有服務,使其執行 ping docker.com 命令,而不是之前執行的任何命令:

$ docker service update --args "ping docker.com" helloworld

指定服務應使用的映象版本

當您建立一個服務而未指定有關要使用的映象版本的任何詳細資訊時,該服務將使用標記為 latest 標籤的版本。您可以根據您期望的結果,通過幾種不同的方式強制服務使用特定版本的映象。

映象版本可以透過多種方式表示:

  • 如果您指定一個標籤,管理器(或者如果您使用內容信任,則是 Docker 客戶端)會將該標籤解析為一個摘要(digest)。當建立容器任務的請求在工作節點上接收時,工作節點只看到摘要,而不是標籤。

    $ docker service create --name="myservice" ubuntu:16.04
    

    一些標籤代表離散的釋出版本,例如 ubuntu:16.04。這類標籤隨著時間的推移幾乎總是解析為穩定的摘要。建議在可能的情況下使用這種型別的標籤。

    其他型別的標籤,如 latestnightly,可能會經常解析為新的摘要,這取決於映象作者更新標籤的頻率。不建議使用更新頻繁的標籤來執行服務,以防止不同的服務副本任務使用不同的映象版本。

  • 如果您根本不指定版本,按照慣例,映象的 latest 標籤將被解析為一個摘要。工作節點在建立服務任務時使用該摘要處的映象。

    因此,以下兩個命令是等效的:

    $ docker service create --name="myservice" ubuntu
    
    $ docker service create --name="myservice" ubuntu:latest
    
  • 如果您直接指定一個摘要,那麼在建立服務任務時總是使用該映象的確切版本。

    $ docker service create \
        --name="myservice" \
        ubuntu:16.04@sha256:35bc48a1ca97c3971611dc4662d08d131869daa692acb281c7e9e052924e38b1
    

當您建立一個服務時,映象的標籤會在**服務建立時**被解析為該標籤指向的特定摘要。該服務的 Worker 節點將永遠使用該特定摘要,除非服務被明確更新。如果您確實使用了像 latest 這樣經常變化的標籤,這個功能就特別重要,因為它確保了所有服務任務都使用相同版本的映象。

注意

如果啟用了內容信任,客戶端在聯絡 swarm 管理器之前實際上會將映象的標籤解析為摘要,以驗證映象是否已簽名。因此,如果您使用內容信任,swarm 管理器接收到的是預先解析的請求。在這種情況下,如果客戶端無法將映象解析為摘要,請求將失敗。

如果管理器無法將標籤解析為摘要,每個工作節點將負責將標籤解析為摘要,不同的節點可能會使用不同版本的映象。如果發生這種情況,將記錄類似以下的警告,並將佔位符替換為真實資訊。

unable to pin image <IMAGE-NAME> to digest: <REASON>

要檢視映象當前的摘要,請執行命令 docker inspect <IMAGE>:<TAG> 並查詢 RepoDigests 行。以下是編寫此內容時 ubuntu:latest 的當前摘要。為清晰起見,輸出已被截斷。

$ docker inspect ubuntu:latest
"RepoDigests": [
    "ubuntu@sha256:35bc48a1ca97c3971611dc4662d08d131869daa692acb281c7e9e052924e38b1"
],

在您建立一個服務之後,它的映象永遠不會被更新,除非您明確地使用 --image 標誌執行 docker service update,如下所述。其他更新操作,如擴充套件服務、新增或刪除網路或卷、重新命名服務,或任何其他型別的更新操作,都不會更新服務的映象。

建立後更新服務的映象

每個標籤代表一個摘要,類似於 Git 雜湊。一些標籤,如 latest,會經常更新以指向新的摘要。其他的,如 ubuntu:16.04,代表一個已釋出的軟體版本,預計不會或者很少會更新指向新的摘要。當您建立一個服務時,它被限制為使用特定摘要的映象建立任務,直到您使用 service update--image 標誌更新服務。

當您使用 --image 標誌執行 service update 時,swarm 管理器會查詢 Docker Hub 或您的私有 Docker 倉庫,獲取標籤當前指向的摘要,並更新服務任務以使用該摘要。

注意

如果您使用內容信任,Docker 客戶端會解析映象,而 swarm 管理器會收到映象和摘要,而不是標籤。

通常,管理器可以將標籤解析為新的摘要,服務會更新,重新部署每個任務以使用新的映象。如果管理器無法解析標籤或出現其他問題,接下來的兩節將概述預期的情況。

如果管理器解析標籤

如果 swarm 管理器能夠將映象標籤解析為一個摘要,它會指示工作節點重新部署任務並使用該摘要處的映象。

  • 如果一個工作節點快取了該摘要處的映象,它將使用該映象。

  • 否則,它會嘗試從 Docker Hub 或私有倉庫拉取該映象。

    • 如果成功,任務將使用新映象進行部署。

    • 如果工作節點拉取映象失敗,該服務在該工作節點上的部署將失敗。Docker 會再次嘗試部署該任務,可能會在不同的工作節點上進行。

如果管理器無法解析標籤

如果 swarm 管理器無法將映象解析為摘要,並非一切都完了:

  • 管理器指示工作節點使用該標籤的映象重新部署任務。

  • 如果工作節點有本地快取的解析為該標籤的映象,它將使用該映象。

  • 如果工作節點沒有本地快取的解析為該標籤的映象,該工作節點會嘗試連線到 Docker Hub 或私有倉庫,以拉取該標籤的映象。

    • 如果成功,工作節點將使用該映象。

    • 如果失敗,任務部署失敗,管理器會再次嘗試部署該任務,可能會在不同的工作節點上進行。

釋出埠

當您建立一個 swarm 服務時,您可以透過兩種方式將該服務的埠釋出到 swarm 外部的主機:

  • 您可以依賴路由網格。當您釋出一個服務埠時,swarm 會在每個節點的目標埠上使服務可訪問,無論該節點上是否有該服務的任務在執行。這比較簡單,對於許多型別的服務來說是正確的選擇。

  • 您可以直接在執行該服務的 swarm 節點上釋出服務任務的埠。這會繞過路由網格,並提供最大的靈活性,包括讓您能夠開發自己的路由框架。然而,您需要負責跟蹤每個任務的執行位置,並將請求路由到這些任務,以及在節點之間進行負載均衡。

繼續閱讀以獲取有關這兩種方法的更多資訊和用例。

使用路由網格釋出服務埠

要將服務的埠釋出到 swarm 外部,請使用 --publish <PUBLISHED-PORT>:<SERVICE-PORT> 標誌。swarm 會在每個 swarm 節點的釋出埠上使服務可訪問。如果外部主機連線到任何 swarm 節點上的該埠,路由網格會將其路由到一個任務。外部主機不需要知道服務任務的 IP 地址或內部使用的埠就可以與服務互動。當用戶或程序連線到一個服務時,任何執行服務任務的工作節點都可能響應。有關 swarm 服務網路的更多詳細資訊,請參閱管理 swarm 服務網路

示例:在 10 節點的 swarm 上執行一個三任務的 Nginx 服務

假設您有一個 10 節點的 swarm,並且您部署了一個在 10 節點 swarm 上執行三個任務的 Nginx 服務:

$ docker service create --name my_web \
                        --replicas 3 \
                        --publish published=8080,target=80 \
                        nginx

三個任務最多在三個節點上執行。您不需要知道哪些節點正在執行這些任務;連線到 10 個節點中任何一個的埠 8080 都會將您連線到三個 nginx 任務之一。您可以使用 curl 來測試這一點。以下示例假設 localhost 是 swarm 節點之一。如果不是這種情況,或者 localhost 在您的主機上無法解析為 IP 地址,請替換為主機的 IP 地址或可解析的主機名。

HTML 輸出被截斷:

$ curl localhost:8080

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...truncated...
</html>

後續連線可能會被路由到同一個 swarm 節點或不同的節點。

直接在 Swarm 節點上釋出服務埠

如果您需要根據應用程式狀態做出路由決策,或者需要完全控制將請求路由到服務任務的流程,使用路由網格可能不是您應用程式的正確選擇。要直接在執行它的節點上釋出服務的埠,請使用 --publish 標誌的 mode=host 選項。

注意

如果您使用 mode=host 直接在 swarm 節點上釋出服務埠,並且還設定了 published=<PORT>,這會產生一個隱含的限制,即您在給定的 swarm 節點上只能為該服務執行一個任務。您可以透過指定不帶埠定義的 published 來解決這個問題,這會導致 Docker 為每個任務分配一個隨機埠。

此外,如果您使用 mode=host 並且不在 docker service create 上使用 --mode=global 標誌,那麼很難知道哪些節點正在執行該服務,以便將工作路由給它們。

示例:在每個 swarm 節點上執行一個 nginx Web 伺服器服務

nginx 是一個開源的反向代理、負載均衡器、HTTP 快取和 Web 伺服器。如果您使用路由網格將 nginx 作為服務執行,連線到任何 swarm 節點上的 nginx 埠都會向您顯示(實際上是)執行該服務的隨機 swarm 節點的網頁。

以下示例將 nginx 作為服務在您的 swarm 中的每個節點上執行,並在每個 swarm 節點上本地公開 nginx 埠。

$ docker service create \
  --mode global \
  --publish mode=host,target=80,published=8080 \
  --name=nginx \
  nginx:latest

您可以在每個 swarm 節點的 8080 埠訪問 nginx 伺服器。如果您向 swarm 新增一個節點,將在該節點上啟動一個 nginx 任務。您不能在任何 swarm 節點上啟動另一個繫結到 8080 埠的服務或容器。

注意

這純粹是一個說明性示例。為多層服務建立應用層路由框架是複雜的,超出了本主題的範圍。

將服務連線到覆蓋網路

您可以使用覆蓋網路連線 swarm 內的一個或多個服務。

首先,在管理器節點上使用 docker network create 命令和 --driver overlay 標誌建立一個覆蓋網路。

$ docker network create --driver overlay my-network

在 swarm 模式下建立覆蓋網路後,所有管理器節點都可以訪問該網路。

您可以建立一個新服務,並傳遞 --network 標誌將該服務附加到覆蓋網路:

$ docker service create \
  --replicas 3 \
  --network my-network \
  --name my-web \
  nginx

swarm 將 my-network 擴充套件到執行該服務的每個節點。

您還可以使用 --network-add 標誌將現有服務連線到覆蓋網路。

$ docker service update --network-add my-network my-web

要將正在執行的服務從網路中斷開,請使用 --network-rm 標誌。

$ docker service update --network-rm my-network my-web

有關覆蓋網路和服務發現的更多資訊,請參閱將服務附加到覆蓋網路Docker swarm 模式覆蓋網路安全模型

授予服務訪問金鑰的許可權

要建立一個有權訪問 Docker 管理的金鑰的服務,請使用 --secret 標誌。更多資訊,請參閱為 Docker 服務管理敏感字串(金鑰)

自定義服務的隔離模式

重要

此設定僅適用於 Windows 主機,對於 Linux 主機將被忽略。

Docker 允許您指定 swarm 服務的隔離模式。隔離模式可以是以下之一:

  • default:使用為 Docker 主機配置的預設隔離模式,該模式由 -exec-opt 標誌或 daemon.json 中的 exec-opts 陣列配置。如果守護程序未指定隔離技術,則對於 Windows Server,預設為 process,對於 Windows 10,預設為 hyperv(也是唯一的選擇)。

  • process:將服務任務作為主機上的獨立程序執行。

    注意

    process 隔離模式僅在 Windows Server 上受支援。Windows 10 僅支援 hyperv 隔離模式。

  • hyperv:將服務任務作為隔離的 hyperv 任務執行。這會增加開銷,但提供更多的隔離。

您可以在建立或更新新服務時使用 --isolation 標誌來指定隔離模式。

控制服務放置

Swarm 服務提供了幾種不同的方法來控制服務在不同節點上的規模和放置。

  • 您可以指定服務是需要執行特定數量的副本,還是應該在每個工作節點上全域性執行。請參閱複製服務或全域性服務

  • 您可以配置服務的CPU 或記憶體需求,服務將只在能夠滿足這些需求的節點上執行。

  • 放置約束允許您配置服務只在設定了特定(任意)元資料的節點上執行,如果不存在合適的節點,則部署會失敗。例如,您可以指定您的服務只應在任意標籤 pci_compliant 設定為 true 的節點上執行。

  • 放置偏好允許您為每個節點應用一個具有一系列值的任意標籤,並使用一種演算法在這些節點之間分散您的服務任務。目前,唯一支援的演算法是 spread,它會嘗試將它們均勻放置。例如,如果您為每個節點標記一個值為 1-10 的標籤 rack,然後指定一個基於 rack 的放置偏好,那麼服務任務將在所有帶有 rack 標籤的節點上儘可能均勻地放置,同時考慮其他放置約束、放置偏好和其他特定於節點的限制。

    與約束不同,放置偏好是盡力而為的,如果沒有任何節點能夠滿足偏好,服務也不會部署失敗。如果您為服務指定了放置偏好,那麼在 swarm 管理器決定哪些節點應該執行服務任務時,匹配該偏好的節點將被賦予更高的排名。其他因素,例如服務的高可用性,也會影響哪些節點被排程執行服務任務。例如,如果您有 N 個帶有 rack 標籤的節點(以及一些其他節點),並且您的服務被配置為執行 N+1 個副本,那麼如果有可用的節點,+1 將被排程到一個尚未執行該服務的節點上,無論該節點是否具有 rack 標籤。

複製服務或全域性服務

Swarm 模式有兩種型別的服務:複製服務和全域性服務。對於複製服務,您需要指定 swarm 管理器要排程到可用節點上的副本任務數量。對於全域性服務,排程器會在每個滿足服務放置約束資源需求的可用節點上放置一個任務。

您可以使用 --mode 標誌來控制服務的型別。如果您不指定模式,服務預設為 replicated。對於複製服務,您可以使用 --replicas 標誌指定要啟動的副本任務數量。例如,要啟動一個有 3 個副本任務的複製 nginx 服務:

$ docker service create \
  --name my_web \
  --replicas 3 \
  nginx

要在每個可用節點上啟動一個全域性服務,請將 --mode global 傳遞給 docker service create。每當一個新節點變為可用時,排程器就會在新節點上放置一個全域性服務的任務。例如,要啟動一個在 swarm 中每個節點上執行 alpine 的服務:

$ docker service create \
  --name myservice \
  --mode global \
  alpine top

服務約束允許您設定節點在排程器將服務部署到該節點之前必須滿足的標準。您可以根據節點屬性和元資料或引擎元資料對服務應用約束。有關約束的更多資訊,請參閱 docker service create CLI 參考

為服務預留記憶體或 CPU

要為服務預留一定數量的記憶體或 CPU,請使用 --reserve-memory--reserve-cpu 標誌。如果沒有可用的節點能夠滿足要求(例如,如果您請求 4 個 CPU,而 swarm 中沒有節點有 4 個 CPU),服務將保持在待定狀態,直到有合適的節點可以執行其任務。

記憶體不足異常 (OOME)

如果您的服務試圖使用超過 swarm 節點可用記憶體的記憶體,您可能會遇到記憶體不足異常(OOME),並且容器或 Docker 守護程序可能會被核心 OOM 殺手殺死。為防止這種情況發生,請確保您的應用程式在具有足夠記憶體的主機上執行,並參閱瞭解記憶體耗盡的風險

Swarm 服務允許您使用資源約束、放置偏好和標籤,以確保您的服務部署到適當的 swarm 節點上。

放置約束

使用放置約束來控制服務可以分配到的節點。在以下示例中,服務只會在標籤 region 設定為 east 的節點上執行。如果沒有帶適當標籤的節點可用,任務將保持在 Pending 狀態,直到有可用節點。--constraint 標誌使用相等運算子(==!=)。對於複製服務,所有服務可能執行在同一個節點上,或者每個節點只執行一個副本,或者某些節點不執行任何副本。對於全域性服務,該服務將在滿足放置約束和任何資源需求的每個節點上執行。

$ docker service create \
  --name my-nginx \
  --replicas 5 \
  --constraint node.labels.region==east \
  nginx

您還可以在 compose.yaml 檔案中使用服務級別的 `constraint` 鍵。

如果您指定多個放置約束,服務將只部署在同時滿足所有這些約束的節點上。以下示例將服務限制在所有 region 設定為 easttype 未設定為 devel 的節點上執行:

$ docker service create \
  --name my-nginx \
  --mode global \
  --constraint node.labels.region==east \
  --constraint node.labels.type!=devel \
  nginx

您還可以將放置約束與放置偏好和 CPU/記憶體約束結合使用。請注意不要使用無法滿足的設定。

有關約束的更多資訊,請參閱 docker service create CLI 參考

放置偏好

雖然放置約束限制了服務可以執行的節點,但*放置偏好*則嘗試以演算法方式(目前僅支援均勻分佈)將任務放置在適當的節點上。例如,如果您為每個節點分配一個 `rack` 標籤,您可以設定一個放置偏好,以根據 `rack` 標籤的值在節點間均勻分佈服務。這樣,如果您丟失一個機架,服務仍然在其他機架的節點上執行。

放置偏好不是嚴格執行的。如果沒有任何節點具有您在偏好中指定的標籤,服務將像未設定偏好一樣部署。

注意

對於全域性服務,放置偏好將被忽略。

以下示例設定了一個偏好,根據 datacenter 標籤的值來分散部署。如果一些節點有 datacenter=us-east,而其他節點有 datacenter=us-west,那麼服務將盡可能均勻地部署在這兩組節點上。

$ docker service create \
  --replicas 9 \
  --name redis_2 \
  --placement-pref 'spread=node.labels.datacenter' \
  redis:7.4.0
注意

缺少用於分佈的標籤的節點仍然會接收任務分配。作為一個群體,這些節點接收到的任務比例與由特定標籤值標識的任何其他群體相等。在某種意義上,缺少標籤與附加了空值標籤是相同的。如果服務只應在具有用於分佈偏好的標籤的節點上執行,則應將偏好與約束結合使用。

您可以指定多個放置偏好,它們將按照遇到的順序進行處理。以下示例設定了一個具有多個放置偏好的服務。任務首先分佈在不同的資料中心,然後分佈在機架上(由相應的標籤指示):

$ docker service create \
  --replicas 9 \
  --name redis_2 \
  --placement-pref 'spread=node.labels.datacenter' \
  --placement-pref 'spread=node.labels.rack' \
  redis:7.4.0

您還可以將放置偏好與放置約束或 CPU/記憶體約束結合使用。請注意不要使用無法滿足的設定。

此圖說明了放置偏好如何工作:

How placement preferences work

使用 docker service update 更新服務時,--placement-pref-add 會在所有現有的放置偏好之後追加一個新的放置偏好。--placement-pref-rm 會移除一個與引數匹配的現有放置偏好。

配置服務的更新行為

當您建立一個服務時,您可以指定一個滾動更新行為,用於在您執行 docker service update 時 swarm 應如何應用對該服務的更改。您也可以在更新時將這些標誌作為 docker service update 的引數來指定。

--update-delay 標誌配置了更新服務任務或任務集之間的時間延遲。您可以將時間 T 描述為秒數 Ts、分鐘數 Tm 或小時數 Th 的組合。因此 10m30s 表示 10 分 30 秒的延遲。

預設情況下,排程器一次更新一個任務。您可以傳遞 --update-parallelism 標誌來配置排程器同時更新的最大服務任務數量。

當對單個任務的更新返回狀態為 RUNNING 時,排程器透過繼續到另一個任務來繼續更新,直到所有任務都更新完畢。如果在更新期間任何時候有任務返回 FAILED,排程器會暫停更新。您可以使用 docker service createdocker service update--update-failure-action 標誌來控制此行為。

在下面的示例服務中,排程器一次最多對 2 個副本應用更新。當更新後的任務返回 RUNNINGFAILED 時,排程器會等待 10 秒,然後停止下一個要更新的任務:

$ docker service create \
  --replicas 10 \
  --name my_web \
  --update-delay 10s \
  --update-parallelism 2 \
  --update-failure-action continue \
  alpine

--update-max-failure-ratio 標誌控制在更新過程中可以失敗的任務比例,超過該比例則整個更新被視為失敗。例如,使用 --update-max-failure-ratio 0.1 --update-failure-action pause,在 10% 的正在更新的任務失敗後,更新將暫停。

如果任務未能啟動,或者在用 --update-monitor 標誌指定的監控期內停止執行,則單個任務更新被視為失敗。--update-monitor 的預設值為 30 秒,這意味著在啟動後的前 30 秒內失敗的任務會計入服務更新失敗閾值,而之後的失敗則不計入。

回滾到服務的先前版本

如果更新後的服務版本未能按預期工作,可以使用 docker service update--rollback 標誌手動回滾到服務的先前版本。這將使服務恢復到最近一次 docker service update 命令之前的配置。

其他選項可以與 --rollback 結合使用;例如,--update-delay 0s,可以在任務之間無延遲地執行回滾:

$ docker service update \
  --rollback \
  --update-delay 0s
  my_web

您可以配置服務在服務更新部署失敗時自動回滾。請參閱如果更新失敗則自動回滾

手動回滾在伺服器端處理,這使得手動發起的回滾能夠遵循新的回滾引數。請注意,--rollback 不能與 docker service update 的其他標誌一起使用。

如果更新失敗則自動回滾

您可以配置一個服務,使得如果服務更新導致重新部署失敗,該服務可以自動回滾到先前的配置。這有助於保護服務的可用性。您可以在服務建立或更新時設定以下一個或多個標誌。如果您不設定值,將使用預設值。

標誌預設值描述
--rollback-delay0秒回滾一個任務後等待多長時間再回滾下一個任務。值為 0 表示在第一個回滾的任務部署後立即回滾第二個任務。
--rollback-failure-action暫停當任務回滾失敗時,是 `pause`(暫停)還是 `continue`(繼續)嘗試回滾其他任務。
--rollback-max-failure-ratio0在回滾期間容忍的失敗率,指定為 0 到 1 之間的浮點數。例如,對於 5 個任務,失敗率為 .2 將容忍一個任務回滾失敗。值為 0 表示不容忍任何失敗,而值為 1 表示容忍任意數量的失敗。
--rollback-monitor5秒每個任務回滾後監控失敗的持續時間。如果任務在此時間段結束前停止,則認為回滾失敗。
--rollback-parallelism1並行回滾的最大任務數。預設情況下,一次回滾一個任務。值為 0 會導致所有任務並行回滾。

以下示例配置一個 redis 服務,以便在 docker service update 部署失敗時自動回滾。可以並行回滾兩個任務。任務在回滾後被監控 20 秒,以確保它們不會退出,並且容忍的最大失敗率為 20%。--rollback-delay--rollback-failure-action 使用預設值。

$ docker service create --name=my_redis \
                        --replicas=5 \
                        --rollback-parallelism=2 \
                        --rollback-monitor=20s \
                        --rollback-max-failure-ratio=.2 \
                        redis:latest

為服務提供卷或繫結掛載的訪問許可權

為了獲得最佳效能和可移植性,您應避免將重要資料直接寫入容器的可寫層。您應該改用資料卷或繫結掛載。此原則也適用於服務。

您可以為 swarm 中的服務建立兩種型別的掛載:volume 掛載或 bind 掛載。無論您使用哪種型別的掛載,都可以在建立服務時使用 --mount 標誌,或在更新現有服務時使用 --mount-add--mount-rm 標誌進行配置。如果您不指定型別,預設為資料卷。

資料卷

資料卷是獨立於容器存在的儲存。在 swarm 服務下,資料卷的生命週期與在容器下相似。卷的生命週期超過任務和服務,因此它們的移除必須單獨管理。卷可以在部署服務之前建立,或者如果它們在任務被排程到特定主機時不存在,則會根據服務上的卷規範自動建立。

要將現有資料卷與服務一起使用,請使用 --mount 標誌:

$ docker service create \
  --mount src=<VOLUME-NAME>,dst=<CONTAINER-PATH> \
  --name myservice \
  <IMAGE>

如果名為 <VOLUME-NAME> 的卷在任務被排程到特定主機時不存在,則會建立一個。預設的卷驅動是 local。要使用不同的卷驅動並採用這種按需建立的模式,請使用 --mount 標誌指定驅動及其選項:

$ docker service create \
  --mount type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=<DRIVER>,volume-opt=<KEY0>=<VALUE0>,volume-opt=<KEY1>=<VALUE1>
  --name myservice \
  <IMAGE>

有關如何建立資料卷以及卷驅動程式使用的更多資訊,請參閱使用卷

繫結掛載

繫結掛載是排程器部署任務容器的主機上的檔案系統路徑。Docker 將該路徑掛載到容器中。在 swarm 初始化任務容器之前,檔案系統路徑必須存在。

以下示例顯示了繫結掛載語法:

  • 掛載一個讀寫繫結:

    $ docker service create \
      --mount type=bind,src=<HOST-PATH>,dst=<CONTAINER-PATH> \
      --name myservice \
      <IMAGE>
    
  • 掛載一個只讀繫結:

    $ docker service create \
      --mount type=bind,src=<HOST-PATH>,dst=<CONTAINER-PATH>,readonly \
      --name myservice \
      <IMAGE>
    
重要

繫結掛載可能很有用,但也可能導致問題。在大多數情況下,建議您設計您的應用程式,使其不需要從主機掛載路徑。主要風險包括以下幾點:

  • 如果您將主機路徑繫結掛載到服務的容器中,該路徑必須在每個 swarm 節點上都存在。Docker swarm 模式排程器可以在任何滿足資源可用性要求並滿足您指定的所有約束和放置偏好的機器上排程容器。

  • 如果正在執行的服務容器變得不健康或無法訪問,Docker Swarm 模式排程器可能隨時重新排程它們。

  • 主機繫結掛載是不可移植的。當您使用繫結掛載時,無法保證您的應用程式在開發環境中的執行方式與在生產環境中相同。

使用模板建立服務

您可以使用 Go 的 text/template 包提供的語法,為 service create 的某些標誌使用模板。

支援以下標誌:

  • --hostname
  • --mount
  • --env

Go 模板的有效佔位符是:

佔位符描述
.Service.ID服務 ID
.Service.Name服務名稱
.Service.Labels服務標籤
.Node.ID節點 ID
.Node.Hostname節點主機名
.Task.Name任務名稱
.Task.Slot任務插槽

模板示例

此示例根據服務名稱和容器執行節點的 ID 設定建立容器的模板:

$ docker service create --name hosttempl \
                        --hostname="{{.Node.ID}}-{{.Service.Name}}"\
                         busybox top

要檢視使用模板的結果,請使用 docker service psdocker inspect 命令。

$ docker service ps va8ew30grofhjoychbr6iot8c

ID            NAME         IMAGE                                                                                   NODE          DESIRED STATE  CURRENT STATE               ERROR  PORTS
wo41w8hg8qan  hosttempl.1  busybox:latest@sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912  2e7a8a9c4da2  Running        Running about a minute ago
$ docker inspect --format="{{.Config.Hostname}}" hosttempl.1.wo41w8hg8qanxwjwsg4kxpprj

瞭解更多