將服務部署到叢集

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

這會將您本地端用戶端的登入權杖傳遞到部署服務的 Swarm 節點,使用加密的 WAL 記錄。有了這些資訊,節點就能夠登入倉庫並提取映像檔。

提供受管理服務帳戶的憑證規格

在 Enterprise Edition 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。

以下服務的容器將環境變數 $MYVAR 設定為 myvalue,從 /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 用戶端)會將該標籤解析為摘要。當在工作節點上收到建立容器任務的請求時,工作節點只會看到摘要,而不是標籤。

    $ 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
    

當您建立服務時,映像檔的標籤會解析為**在服務建立時**標籤指向的特定摘要。該服務的工作節點會永遠使用該特定摘要,除非明確更新服務。如果您確實使用經常變化的標籤(例如 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 或私有 Registry 以提取該標籤的映像。

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

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

發佈埠

建立 Swarm 服務時,您可以透過兩種方式將該服務的埠發佈到 Swarm 外部的 hosts。

  • 您可以依賴路由網格。當您發佈服務埠時,Swarm 會讓服務在每個節點上的目標埠都可存取,無論該節點上是否有該服務的任務正在執行。這種方式比較簡單,並且適用於許多類型的服務。

  • 您可以直接在執行該服務的 Swarm 節點上發佈服務任務的埠。這會繞過路由網格,並提供最大的彈性,包括讓您開發自己的路由架構的能力。但是,您需要負責追蹤每個任務的執行位置、將請求路由到任務,以及跨節點進行負載平衡。

請繼續閱讀以瞭解更多關於這些方法的資訊和使用案例。

使用路由網格發佈服務的埠

要將服務的埠發佈到 Swarm 外部,請使用 --publish <PUBLISHED-PORT>:<SERVICE-PORT> 旗標。Swarm 會讓服務在每個 Swarm 節點上的已發佈埠都可存取。如果外部主機連線到任何 Swarm 節點上的該埠,路由網格會將其路由到一個任務。外部主機不需要知道服務任務的 IP 位址或內部使用的埠即可與服務互動。當使用者或程序連線到服務時,任何執行服務任務的工作節點都可能會回應。有關 Swarm 服務網路的更多詳細資訊,請參閱 管理 Swarm 服務網路

範例:在 10 個節點的 Swarm 上執行一個具有三個任務的 Nginx 服務

假設您有一個 10 個節點的 Swarm,並且您在該 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 網頁伺服器服務

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

以下範例在 Swarm 中的每個節點上將 nginx 作為服務運行,並在每個 Swarm 節點上本地公開 nginx 埠。

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

您可以在每個 Swarm 節點的埠 8080 上訪問 nginx 伺服器。如果您向 Swarm 添加一個節點,則會在其上啟動一個 nginx 任務。您無法在任何繫結到埠 8080 的 Swarm 節點上啟動其他服務或容器。

**注意**

這只是一個純粹的說明性範例。為多層服務建立應用程式層路由架構很複雜,並且超出了本主題的範圍。

將服務連線到覆蓋網路

您可以使用覆蓋網路來連線 Swarm 中的一個或多個服務。

首先,使用帶有 --driver overlay 旗標的 docker network create 命令在管理節點上建立覆蓋網路。

$ 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 管理的 secrets 的服務,請使用 --secret 旗標。如需更多資訊,請參閱 管理 Docker 服務的敏感字串 (secrets)

自訂服務的隔離模式

重要

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

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

  • default:使用為 Docker 主機設定的預設隔離模式,如 daemon.json 中的 -exec-opt 旗標或 exec-opts 陣列所設定。如果 daemon 沒有指定隔離技術,則 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。每次有新的節點可用時,排程器會將全域服務的任務放置在新節點上。例如,要啟動在叢集中每個節點上都運行 alpine 的服務:

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

服務限制條件可讓您設定節點必須符合的條件,排程器才能將服務部署到該節點。您可以根據節點屬性和中繼資料或引擎中繼資料將限制條件應用於服務。如需限制條件的詳細資訊,請參閱 docker service createCLI 參考

為服務保留記憶體或 CPU

要為服務保留一定量的記憶體或 CPU 數量,請使用 --reserve-memory--reserve-cpu 旗標。如果沒有可用的節點可以滿足需求(例如,如果您請求 4 個 CPU,但叢集中沒有任何節點擁有 4 個 CPU),則服務將保持在擱置狀態,直到有合適的節點可用於運行其任務為止。

記憶體不足例外狀況 (OOME)

如果您的服務嘗試使用超過叢集節點可用記憶體的記憶體,您可能會遇到記憶體不足例外狀況 (OOME),並且容器或 Docker 守護程式可能會被核心 OOM 殺手終止。為了防止這種情況發生,請確保您的應用程式在具有足夠記憶體的主機上運行,並參閱 了解記憶體不足的風險

Swarm 服務允許您使用資源限制條件、放置偏好設定和標籤,以確保您的服務部署到適當的 Swarm 節點。

放置限制條件

使用放置限制條件來控制可以將服務指派給哪些節點。在以下範例中,服務僅在 標籤 region 設定為 east 的節點上運行。如果沒有適當標籤的節點可用,任務將在 Pending(擱置)狀態下等待,直到它們可用為止。--constraint 旗標使用等於運算子(==!=)。對於副本服務,所有服務都可能在同一個節點上運行,或者每個節點只運行一個副本,或者某些節點沒有運行任何副本。對於全域服務,服務會在每個符合放置限制條件和任何 資源需求 的節點上運行。

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

您也可以在 compose.yml 檔案中使用服務層級的 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 createCLI 參考

放置偏好設定

雖然 放置限制條件 限制了服務可以運行的節點,但*放置偏好設定* 會嘗試以演算法方式將任務放置在適當的節點上(目前只有平均分佈)。例如,如果您為每個節點指派一個 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 秒的延遲。

預設情況下,排程器一次更新 1 個任務。您可以傳遞 --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-delay0s回復任務後,在回復下一個任務之前要等待的時間。值 0 表示在第一個回復的任務部署後立即回復第二個任務。
--rollback-failure-actionpause當任務無法回復時,是否 pause(暫停)或 continue(繼續)嘗試回復其他任務。
--rollback-max-failure-ratio0回復期間可容忍的失敗率,指定為介於 0 到 1 之間的浮點數。例如,給定 5 個任務,失敗率 .2 將容忍一個任務無法回復。值 0 表示不容忍任何失敗,而值 1 表示容忍任何數量的失敗。
--rollback-monitor5s每次任務回復後監控失敗的持續時間。如果任務在此時間段結束之前停止,則回復被視為失敗。
--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

深入瞭解