将服务部署到集群

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 节点。有了这些信息,节点就可以登录注册表并提取映像。

提供托管服务帐户的凭据规范

在 Enterprise Edition 3.0 中,通过使用 Docker 配置功能集中分发和管理组托管服务帐户 (gMSA) 凭据,提高了安全性。 Swarm 现在允许使用 Docker 配置作为 gMSA 凭据规范,这减少了将凭据规范分发到使用它们的节点的负担。

笔记

此选项仅适用于使用 Windows 容器的服务。

凭据规范文件在运行时应用,无需基于主机的凭据规范文件或注册表项 - 不会将 gMSA 凭据写入工作节点上的磁盘。您可以在容器启动之前使凭证规范可供运行 swarm kit 工作节点的 Docker 引擎使用。使用基于 gMSA 的配置部署服务时,凭据规范将直接传递到该服务中容器的运行时。

必须--credential-spec采用以下格式之一:

  • file://<filename>:引用的文件必须存在于CredentialSpecsdocker 数据目录的子目录中,C:\ProgramData\Docker\在 Windows 上默认为该子目录。例如,指定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 进行了正确配置。

要将配置用作凭证规范,请在名为 的凭证规范文件中创建 Docker 配置credpspec.json。您可以为 的名称指定任何名称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 create请参阅和 的命令行参考 docker 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 管理器之前将图像的标签解析为摘要,以验证图像是否已签名。因此,如果您使用内容信任,群管理器会收到预先解析的请求。在这种情况下,如果客户端无法将图像解析为摘要,则请求将失败。

如果管理器无法将标签解析为摘要,则每个工作节点负责将标签解析为摘要,并且不同的节点可能使用不同版本的图像。如果发生这种情况,则会记录如下警告,并用占位符替换真实信息。

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

要查看图像的当前摘要,请发出命令 docker inspect <IMAGE>:<TAG>并查找该RepoDigests行。以下是ubuntu:latest撰写本内容时的最新摘要。为了清楚起见,输出被截断。

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

创建服务后,其映像永远不会更新,除非您明确 docker service update使用该--image标志运行,如下所述。其他更新操作(例如扩展服务、添加或删除网络或卷、重命名服务或任何其他类型的更新操作)不会更新服务的映像。

创建后更新服务的镜像

每个标签代表一个摘要,类似于 Git 哈希。某些标签(例如 latest)经常更新以指向新的摘要。其他的,例如 ubuntu:16.04,代表已发布的软件版本,并且预计不会经常更新以指向新的摘要(如果有的话)。当您创建服务时,它只能使用图像的特定摘要创建任务,直到您使用service update--image标志更新服务为止。

当您service update使用该--image标志运行时,群管理器会查询 Docker Hub 或您的私有 Docker 注册表以获取标签当前指向的摘要,并更新服务任务以使用该摘要。

笔记

如果您使用content trust,Docker 客户端会解析镜像,而 swarm 管理器会接收镜像和摘要,而不是标签。

通常,管理器可以将标签解析为新的摘要并更新服务,重新部署每个任务以使用新映像。如果管理员无法解决标签或出现其他问题,接下来的两节将概述将会发生的情况。

如果管理员解析了标签

如果 swarm 管理器可以将镜像标签解析为摘要,它会指示工作节点重新部署任务并使用该摘要中的镜像。

  • 如果工作进程已将图像缓存在该摘要中,则会使用它。

  • 如果没有,它会尝试从 Docker Hub 或私有注册表中提取映像。

    • 如果成功,将使用新映像部署该任务。

    • 如果工作程序无法拉取映像,则服务无法在该工作程序节点上部署。 Docker 再次尝试部署该任务,可能是在不同的工作节点上。

如果管理员无法解析标签

如果 swarm 管理器无法将图像解析为摘要,则一切都不会丢失:

  • 管理器指示工作节点使用该标签处的映像重新部署任务。

  • 如果工作线程有解析为该标签的本地缓存图像,则它会使用该图像。

  • 如果工作程序没有解析为该标记的本地缓存映像,则工作程序会尝试连接到 Docker Hub 或私有注册表以提取该标记处的映像。

    • 如果成功,工作人员将使用该图像。

    • 如果失败,则任务部署失败,管理器可能会在不同的工作节点上再次尝试部署任务。

发布端口

创建 swarm 服务时,可以通过两种方式将该服务的端口发布到 swarm 外部的主机:

  • 您可以信赖路由网格。当您发布服务端口时,Swarm 会在每个节点上的目标端口上访问该服务,无论该节点上是否有该服务正在运行的任务。这不太复杂,并且是许多类型服务的正确选择。

  • 您可以直接在运行该服务的swarm 节点上发布服务任务的端口。这绕过了路由网格并提供了最大的灵活性,包括让您能够开发自己的路由框架。但是,您负责跟踪每个任务的运行位置并将请求路由到任务,以及跨节点进行负载平衡。

继续阅读以获取这些方法的更多信息和用例。

使用路由网格发布服务的端口

要将服务的端口发布到集群外部,请使用该 --publish <PUBLISHED-PORT>:<SERVICE-PORT>标志。 Swarm 使服务可以在每个 Swarm 节点上的已发布端口上进行访问。如果外部主机连接到任何 swarm 节点上的该端口,路由网格会将其路由到任务。外部主机不需要知道服务任务的IP地址或内部使用的端口即可与服务交互。当用户或进程连接到服务时,运行服务任务的任何工作节点都可以响应。有关 swarm 服务网络的更多详细信息,请参阅 管理 swarm 服务网络

示例:在 10 节点 swarm 上运行三任务 Nginx 服务

假设您有一个 10 节点群,并且您部署了一个 Nginx 服务,在 10 节点群上运行三个任务:

$ 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 节点上发布服务的端口

如果您需要根据应用程序状态做出路由决策,或者需要完全控制将请求路由到服务任务的过程,那么使用路由网格可能不是您的应用程序的正确选择。要直接在运行服务的节点上发布服务的端口,请使用mode=host--publish标志的选项。

笔记

mode=host如果您使用并设置直接在 swarm 节点上发布服务的端口, published=<PORT>这会创建一个隐式限制,即您只能在给定的 swarm 节点上运行该服务的一项任务。您可以通过不指定端口定义来解决此问题published,这会导致 Docker 为每个任务分配一个随机端口。

此外,如果您使用mode=host或不使用 --mode=globalon 标志docker service create,则很难知道哪些节点正在运行服务以将工作路由到它们。

示例:在每个 swarm 节点上运行 nginx Web 服务器服务

nginx是一个开源反向代理、负载均衡器、HTTP 缓存和 Web 服务器。如果您使用路由网格将 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 节点上启动另一个服务或容器。

笔记

这纯粹是说明性示例。为多层服务创建应用程序层路由框架非常复杂,超出了本主题的范围。

将服务连接到覆盖网络

您可以使用覆盖网络来连接群内的一项或多项服务。

docker network create 首先,使用带有标志的命令在管理器节点上创建覆盖网络--driver overlay

$ docker network create --driver overlay my-network

在集群模式下创建覆盖网络后,所有管理器节点都可以访问该网络。

您可以创建一个新服务并传递--network标志以将该服务附加到覆盖网络:

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

群扩展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 群模式覆盖网络安全模型

授予服务对机密的访问权限

要创建可以访问 Docker 管理的机密的服务,请使用该--secret 标志。有关更多信息,请参阅 管理 Docker 服务的敏感字符串(机密)

自定义服务的隔离模式

重要的

此设置仅适用于 Windows 主机,对于 Linux 主机将被忽略。

Docker 允许您指定 swarm 服务的隔离模式。隔离模式可以是以下之一:

  • default:使用为 Docker 主机配置的默认隔离模式,如中的-exec-opt标志或exec-opts数组配置daemon.json。如果守护进程未指定隔离技术,process则为 Windows Server 的默认选项,并且hyperv是 Windows 10 的默认(且唯一)选择。

  • process:将服务任务作为主机上的单独进程运行。

    笔记

    process隔离模式仅在 Windows Server 上受支持。 Windows 10 仅支持hyperv隔离模式。

  • hyperv:将服务任务作为独立hyperv任务运行。这增加了开销,但提供了更多的隔离。

您可以在创建或更新新服务时使用该--isolation标志指定隔离模式。

控制服务安置

Swarm 服务提供了几种不同的方法来控制不同节点上服务的规模和放置。

  • 您可以指定服务是否需要运行特定数量的副本,或者应该在每个工作节点上全局运行。请参阅 复制或全局服务

  • 您可以配置服务的 CPU或内存要求,并且该服务仅在能够满足这些要求的节点上运行。

  • 放置约束允许您将服务配置为仅在具有特定(任意)元数据集的节点上运行,如果不存在适当的节点,则会导致部署失败。例如,您可以指定您的服务仅应在任意标签 pci_compliant设置为 的节点上运行true

  • 通过放置首选项,您可以将具有一系列值的任意标签应用到每个节点,并使用算法将服务的任务分散到这些节点上。目前,唯一支持的算法是spread,它试图将它们均匀地放置。例如,如果您使用rack值为 1-10 的标签来标记每个节点,然后指定以 为键的放置首选项rack,则在采用其他放置约束后,服务任务将尽可能均匀地放置在带有标签 的所有节点上rack,考虑放置首选项和其他特定于节点的限制。

    与约束不同,放置首选项是尽力而为的,如果没有节点可以满足该首选项,则服务不会部署失败。如果您为服务指定放置首选项,则当 swarm 管理器决定哪些节点应运行服务任务时,与该首选项匹配的节点的排名会更高。其他因素(例如服务的高可用性)也会影响调度哪些节点来运行服务任务。例如,如果您有 N 个带有机架标签的节点(以及其他一些节点),并且您的服务配置为运行 N+1 个副本,则 +1 计划将安排在尚未具有该服务的节点上,如果无论该节点是否有标签,都有一个rack

复制或全局服务

Swarm 模式有两种类型的服务:复制服务和全局服务。对于复制服务,您可以指定 swarm 管理器调度到可用节点上的副本任务数量。对于全局服务,调度程序将一项任务放置在满足服务的 放置约束资源要求的每个可用节点上。

您可以使用该标志来控制服务类型--mode。如果您不指定模式,则服务默认为replicated。对于复制服务,您可以使用该标志指定要启动的副本任务的数量--replicas。例如,要启动具有 3 个副本任务的复制 nginx 服务:

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

要在每个可用节点上启动全局服务,请传递--mode globaldocker 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

您还可以在文件constraint中使用服务级别密钥compose.yml

如果指定多个放置约束,则服务仅部署到全部满足这些约束的节点上。以下示例限制服务在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:3.0.6

笔记

缺少用于传播的标签的节点仍然会收到任务分配。作为一个组,这些节点接收的任务比例与由特定标签值标识的任何其他组的比例相同。从某种意义上说,缺失标签与附加了空值的标签相同。如果服务只应在标签用于扩展首选项的节点上运行,则首选项应与约束结合起来。

您可以指定多个放置首选项,它们将按遇到的顺序进行处理。以下示例设置具有多个放置首选项的服务。任务首先分布在各个数据中心,然后分布在机架上(如相应标签所示):

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

您还可以将布局首选项与布局约束或 CPU/内存约束结合使用。请注意不要使用无法实现的设置。

下图说明了放置首选项的工作原理:

展示位置偏好如何运作

使用 更新服务时docker service update--placement-pref-add 会在所有现有放置首选项之后附加新的放置首选项。 --placement-pref-rm删除与参数匹配的现有放置首选项。

配置服务的更新行为

创建服务时,您可以指定滚动更新行为,以便在运行时 swarm 应如何将更改应用到服务docker service update。您还可以将这些标志指定为更新的一部分,作为 的参数 docker service update

--update-delay标志配置服务任务或任务集更新之间的时间延迟。您可以将时间描述为秒数、分钟数或小时T数的组合。因此表示延迟 10 分 30 秒。TsTmTh10m30s

默认情况下,调度程序一次更新 1 个任务。您可以通过该 --update-parallelism标志来配置调度程序同时更新的服务任务的最大数量。

当对单个任务的更新返回状态 时RUNNING,调度程序将通过继续另一个任务来继续更新,直到更新所有任务。如果在更新过程中的任何时间任务返回FAILED,调度程序就会暂停更新。您可以使用或--update-failure-action 标志来控制行为。docker service createdocker service update

在下面的示例服务中,调度程序一次最多将更新应用于 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-monitor30 秒,这意味着任务启动后前 30 秒内失败将计入服务更新失败阈值,之后的失败不计入。

回滚到服务的先前版本

如果服务的更新版本无法按预期运行,可以使用 docker service update's--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当某个任务回滚失败时,是否要回滚pausecontinue尝试回滚其他任务。
--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 群模式调度程序可以在满足资源可用性要求并满足您指定的所有约束和放置首选项的任何计算机上调度容器。

  • 如果您正在运行的服务容器变得不健康或无法访问,Docker swarm 模式调度程序可能会随时重新调度它们。

  • 主机绑定安装是不可移植的。当您使用绑定安装时,无法保证您的应用程序在开发中的运行方式与在生产中的运行方式相同。

使用模板创建服务

您可以使用 Go 的text/templateservice create包提供的语法 对 的某些标志使用模板 。

支持以下标志:

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

Go 模板的有效占位符是:

占位符描述
.Service.ID服务编号
.Service.Name服务名称
.Service.Labels服务标签
.Node.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

了解更多