将服务部署到群集

Swarm 服务使用声明式模型,这意味着您定义服务的期望状态,并依赖 Docker 来维护此状态。状态包括(但不限于)以下信息:

  • 服务容器应运行的镜像名称和标签
  • 有多少容器参与了服务
  • 是否有任何端口暴露给集群外部的客户端
  • 服务是否应在 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日志。有了这些信息,节点能够登录到注册表并拉取镜像。

为托管服务账户提供凭证规范

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

注意

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

凭证规范文件在运行时应用,消除了对基于主机的凭证规范文件或注册表条目的需求 - 没有gMSA凭证被写入工作节点的磁盘。您可以在容器启动之前使凭证规范对运行swarm kit工作节点的Docker Engine可用。当使用基于gMSA的配置部署服务时,凭证规范直接传递给该服务中容器的运行时。

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

  • file://: 引用的文件必须存在于docker数据目录中的CredentialSpecs子目录中,该目录在Windows上默认为C:\ProgramData\Docker\。例如,指定file://spec.json会加载C:\ProgramData\Docker\CredentialSpecs\spec.json
  • registry://: 凭据规范从守护程序主机上的Windows注册表中读取。
  • config://: 配置名称在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是一个网络服务,如果你将端口80发布给群集外部的客户端,它会工作得更好。你可以在创建服务时使用-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),这个特性尤为重要,因为它确保所有服务任务使用相同版本的镜像。

注意

如果 内容信任 是 启用的,客户端实际上在联系群管理器之前会将镜像的标签解析为摘要,以验证镜像是否已签名。 因此,如果您使用内容信任,群管理器会收到预先解析的请求。 在这种情况下,如果客户端无法将镜像解析为摘要,请求将失败。

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

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

要查看图像的当前摘要,请发出命令 docker inspect : 并查找 RepoDigests 行。以下是撰写此内容时 ubuntu:latest 的当前摘要。为清晰起见,输出已被截断。

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

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

创建后更新服务的镜像

每个标签代表一个摘要,类似于Git哈希。一些标签,如latest,经常更新以指向新的摘要。其他标签,如ubuntu:16.04,代表发布的软件版本,通常不会更新以指向新的摘要。当您创建服务时,它被限制为使用特定摘要的图像创建任务,直到您使用带有--image标志的service update更新服务。

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

注意

如果您使用 内容信任,Docker 客户端会解析镜像,并且swarm管理器接收镜像和摘要, 而不是标签。

通常,管理者可以将标签解析为新的摘要,并且服务会更新,重新部署每个任务以使用新的镜像。如果管理者无法解析标签或发生其他问题,接下来的两个部分将概述预期的内容。

如果经理解决了标签

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

  • 如果一个工作器已经缓存了该摘要的图像,它会使用它。

  • 如果不是,它会尝试从Docker Hub或私有注册表中拉取镜像。

    • 如果成功,任务将使用新镜像进行部署。

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

如果管理者无法解析标签

如果群管理器无法将镜像解析为摘要,并不意味着一切都丢失了:

  • 经理指示工作节点使用该标签的镜像重新部署任务。

  • 如果工作节点有一个本地缓存的镜像可以解析到该标签,它将使用该镜像。

  • 如果工作节点没有本地缓存的解析到该标签的镜像,工作节点会尝试连接到Docker Hub或私有注册表以拉取该标签的镜像。

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

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

发布端口

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

  • 您可以依赖路由网格。 当您发布一个服务端口时,swarm 使服务在每个节点的目标端口上可访问, 无论该节点上是否有该服务的任务正在运行。这较为简单,并且是许多类型服务的正确选择。

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

继续阅读以获取更多信息以及每种方法的使用案例。

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

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

示例:在10节点群集上运行一个三任务的Nginx服务

想象一下,你有一个10节点的集群,并且你在一个10节点的集群上部署了一个运行三个任务的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节点上发布服务的端口

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

注意

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

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

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

nginx 是一个开源的逆向代理、负载均衡器、HTTP缓存和网页服务器。如果你使用路由网格将nginx作为服务运行,连接到任何swarm节点上的nginx端口将显示(实际上)运行该服务的随机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任务将在其上启动。您无法在任何Swarm节点上启动另一个绑定到8080端口的服务或容器。

注意

这是一个纯示例性的例子。为多层服务创建应用层路由框架是复杂的,超出了本主题的范围。

将服务连接到覆盖网络

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

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

$ 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 swarm 模式覆盖网络安全模型

授予服务访问机密的权限

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

自定义服务的隔离模式

重要

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

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

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

  • process: 在主机上以单独的进程运行服务任务。

    注意

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

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

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

控制服务放置

Swarm 服务提供了几种不同的方式,让你可以控制不同节点上服务的规模和放置。

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

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

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

  • 放置偏好 允许你为每个节点应用一个带有值范围的任意标签,并使用算法将你的服务任务分布在这些节点上。目前,唯一支持的算法是 spread,它尝试将它们均匀放置。例如,如果你用标签 rack 标记每个节点,该标签的值范围为1-10,然后指定一个基于 rack 的放置偏好,那么在考虑其他放置约束、放置偏好和其他节点特定限制后,服务任务将尽可能均匀地分布在所有带有 rack 标签的节点上。

    与约束不同,放置偏好是尽力而为的,如果没有节点能够满足偏好,服务也不会部署失败。如果您为服务指定了放置偏好,当群集管理器决定哪些节点应运行服务任务时,匹配该偏好的节点会被优先考虑。其他因素,如服务的高可用性,也会影响哪些节点被调度运行服务任务。例如,如果您有N个带有机架标签的节点(以及其他一些节点),并且您的服务配置为运行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 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秒的延迟。

默认情况下,调度程序一次更新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-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 的其他标志一起使用。

如果更新失败则自动回滚

您可以配置服务,使得如果服务的更新导致重新部署失败,服务可以自动回滚到先前的配置。这有助于保护服务的可用性。您可以在服务创建或更新时设置以下一个或多个标志。如果您没有设置值,则使用默认值。

FlagDefaultDescription
--rollback-delay0sAmount of time to wait after rolling back a task before rolling back the next one. A value of 0 means to roll back the second task immediately after the first rolled-back task deploys.
--rollback-failure-actionpauseWhen a task fails to roll back, whether to pause or continue trying to roll back other tasks.
--rollback-max-failure-ratio0The failure rate to tolerate during a rollback, specified as a floating-point number between 0 and 1. For instance, given 5 tasks, a failure ratio of .2 would tolerate one task failing to roll back. A value of 0 means no failure are tolerated, while a value of 1 means any number of failure are tolerated.
--rollback-monitor5sDuration after each task rollback to monitor for failure. If a task stops before this time period has elapsed, the rollback is considered to have failed.
--rollback-parallelism1The maximum number of tasks to roll back in parallel. By default, one task is rolled back at a time. A value of 0 causes all tasks to be rolled back in parallel.

以下示例配置了一个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

为服务提供对卷或绑定挂载的访问权限

为了获得最佳性能和可移植性,您应避免将重要数据直接写入容器的可写层。相反,您应使用数据卷或绑定挂载。此原则也适用于服务。

你可以在群集中为服务创建两种类型的挂载,volume 挂载或 bind 挂载。无论你使用哪种类型的挂载,都可以在创建服务时使用 --mount 标志进行配置,或者在更新现有服务时使用 --mount-add--mount-rm 标志进行配置。如果你没有指定类型,默认是数据卷。

数据量

数据卷是独立于容器存在的存储。在Swarm服务下的数据卷生命周期与容器下的类似。数据卷的生命周期长于任务和服务,因此它们的删除必须单独管理。数据卷可以在部署服务之前创建,或者如果在任务调度到特定主机时该主机上不存在数据卷,则会根据服务上的数据卷规范自动创建。

要将现有数据卷与服务一起使用,请使用 --mount 标志:

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

如果在任务被调度到特定主机时,名为的卷不存在,则会创建一个。默认的卷驱动是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 将此路径挂载到容器中。在群集初始化任务的容器之前,文件系统路径必须存在。

以下示例展示了绑定挂载语法:

  • 挂载一个读写绑定:

    $ 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模式调度程序可能随时重新调度它们。

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

使用模板创建服务

您可以使用模板来处理service create的一些标志,使用Go的 text/template 包提供的语法。

支持以下标志:

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

Go模板的有效占位符有:

PlaceholderDescription
.Service.IDService ID
.Service.NameService name
.Service.LabelsService labels
.Node.IDNode ID
.Node.HostnameNode hostname
.Task.NameTask name
.Task.SlotTask 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

了解更多