docker service create

描述创建一个新的服务
用法docker service create [OPTIONS] IMAGE [COMMAND] [ARG...]

Swarm 此命令适用于 Swarm 编排器。

描述

根据指定的参数创建一个服务。

注意

这是一个集群管理命令,必须在 Swarm 管理节点上执行。要了解有关管理者和工作节点的信息,请参阅文档中的Swarm 模式部分

选项

选项默认值描述
--cap-addAPI 1.41+ 添加 Linux 能力
--cap-dropAPI 1.41+ 移除 Linux 能力
--configAPI 1.30+ 指定要向服务公开的配置
--constraint放置约束
--container-label容器标签
--credential-specAPI 1.29+ 用于托管服务帐户的凭据规范 (仅限 Windows)
-d, --detachAPI 1.29+ 立即退出,而不是等待服务收敛
--dnsAPI 1.25+ 设置自定义 DNS 服务器
--dns-optionAPI 1.25+ 设置 DNS 选项
--dns-searchAPI 1.25+ 设置自定义 DNS 搜索域
--endpoint-modevip端点模式 (vip 或 dnsrr)
--entrypoint覆盖镜像的默认 ENTRYPOINT
-e, --env设置环境变量
--env-file从文件读取环境变量
--generic-resource用户定义资源
--groupAPI 1.25+ 为容器设置一个或多个补充用户组
--health-cmdAPI 1.25+ 用于检查健康状况的命令
--health-intervalAPI 1.25+ 运行检查之间的时间间隔 (ms|s|m|h)
--health-retriesAPI 1.25+ 报告不健康所需的连续失败次数
--health-start-intervalAPI 1.44+ 在启动期间运行检查之间的时间间隔 (ms|s|m|h)
--health-start-periodAPI 1.29+ 容器在计数不稳定重试之前进行初始化的启动周期 (ms|s|m|h)
--health-timeoutAPI 1.25+ 允许一次检查运行的最长时间 (ms|s|m|h)
--hostAPI 1.25+ 设置一个或多个自定义主机到 IP 的映射 (host:ip)
--hostnameAPI 1.25+ 容器主机名
--initAPI 1.37+ 在每个服务容器内使用 init 来转发信号和回收进程
--isolationAPI 1.35+ 服务容器隔离模式
-l, --label服务标签
--limit-cpu限制 CPU
--limit-memory限制内存
--limit-pidsAPI 1.41+ 限制最大进程数 (默认 0 = 无限制)
--log-driver服务的日志驱动程序
--log-opt日志驱动程序选项
--max-concurrentAPI 1.41+ 并发运行的作业任务数 (默认等于 --replicas)
--modereplicated服务模式 (replicated, global, replicated-job, global-job)
--mount将文件系统挂载附加到服务
--name服务名称
--network网络附加
--no-healthcheckAPI 1.25+ 禁用容器指定的 HEALTHCHECK
--no-resolve-imageAPI 1.30+ 不查询注册表以解析镜像摘要和支持的平台
--oom-score-adjAPI 1.46+ 调整主机的 OOM 偏好设置 (-1000 到 1000)
--placement-prefAPI 1.28+ 添加放置偏好
-p, --publish将端口发布为节点端口
-q, --quiet抑制进度输出
--read-onlyAPI 1.28+ 以只读方式挂载容器的根文件系统
--replicas任务数
--replicas-max-per-nodeAPI 1.40+ 每节点的最大任务数 (默认 0 = 无限制)
--reserve-cpu保留 CPU
--reserve-memory保留内存
--restart-condition满足条件时重启 (none, on-failure, any) (默认 any)
--restart-delay重启尝试之间的延迟 (ns|us|ms|s|m|h) (默认 5s)
--restart-max-attempts放弃前的最大重启次数
--restart-window用于评估重启策略的时间窗口 (ns|us|ms|s|m|h)
--rollback-delayAPI 1.28+ 任务回滚之间的延迟 (ns|us|ms|s|m|h) (默认 0s)
--rollback-failure-actionAPI 1.28+ 回滚失败时的操作 (pause, continue) (默认 pause)
--rollback-max-failure-ratioAPI 1.28+ 回滚期间可容忍的失败率 (默认 0)
--rollback-monitorAPI 1.28+ 每次任务回滚后监测故障的持续时间 (ns|us|ms|s|m|h) (默认 5s)
--rollback-orderAPI 1.29+ 回滚顺序 (start-first, stop-first) (默认 stop-first)
--rollback-parallelism1API 1.28+ 同时回滚的最大任务数 (0 表示一次回滚全部)
--secretAPI 1.25+ 指定要向服务公开的 secrets
--stop-grace-period强制终止容器前等待的时间 (ns|us|ms|s|m|h) (默认 10s)
--stop-signalAPI 1.28+ 停止容器的信号
--sysctlAPI 1.40+ Sysctl 选项
-t, --ttyAPI 1.25+ 分配一个伪终端
--ulimitAPI 1.41+ Ulimit 选项
--update-delay更新之间的延迟 (ns|us|ms|s|m|h) (默认 0s)
--update-failure-action更新失败时的操作 (pause, continue, rollback) (默认 pause)
--update-max-failure-ratioAPI 1.25+ 更新期间可容忍的失败率 (默认 0)
--update-monitorAPI 1.25+ 每次任务更新后监测故障的持续时间 (ns|us|ms|s|m|h) (默认 5s)
--update-orderAPI 1.29+ 更新顺序 (start-first, stop-first) (默认 stop-first)
--update-parallelism1同时更新的最大任务数 (0 表示一次更新全部)
-u, --user用户名或 UID (格式: <name|uid>[:<group|gid>])
--with-registry-auth将注册表认证详情发送给 swarm agent
-w, --workdir容器内的工作目录

示例

创建一个服务

$ docker service create --name redis redis:7.4.1

dmu1ept4cxcfe8k8lhtux3ro3

$ docker service create --mode global --name redis2 redis:7.4.1

a8q9dasaafudfs8q8w32udass

$ docker service ls

ID            NAME    MODE        REPLICAS  IMAGE
dmu1ept4cxcf  redis   replicated  1/1       redis:7.4.1
a8q9dasaafud  redis2  global      1/1       redis:7.4.1

使用私有注册表上的镜像创建服务 (--with-registry-auth)

如果你的镜像在一个需要登录的私有注册表上可用,在登录后,使用带有 --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 节点。通过这些信息,节点能够登录到注册表并拉取镜像。

创建具有 5 个副本任务的服务 (--replicas)

使用 --replicas 标志设置复制服务的副本任务数。以下命令创建一个具有 5 个副本任务的 redis 服务:

$ docker service create --name redis --replicas=5 redis:7.4.1

4cdgfyky7ozwh3htjfw0d12qv

上述命令设置了服务的期望任务数。即使命令立即返回,服务的实际扩容可能需要一些时间。REPLICAS 列显示了服务的实际和期望副本任务数。

在下面的示例中,期望状态是 5 个副本,但当前 RUNNING 任务数为 3

$ docker service ls

ID            NAME   MODE        REPLICAS  IMAGE
4cdgfyky7ozw  redis  replicated  3/5       redis:7.4.1

一旦所有任务创建并处于 RUNNING 状态,实际任务数等于期望任务数

$ docker service ls

ID            NAME   MODE        REPLICAS  IMAGE
4cdgfyky7ozw  redis  replicated  5/5       redis:7.4.1

创建带 secrets 的服务 (--secret)

使用 --secret 标志为容器授予访问 secret 的权限。

创建指定 secret 的服务

$ docker service create --name redis --secret secret.json redis:7.4.1

4cdgfyky7ozwh3htjfw0d12qv

创建指定 secret、target、用户/组 ID 和 mode 的服务

$ docker service create --name redis \
    --secret source=ssh-key,target=ssh \
    --secret source=app-key,target=app,uid=1000,gid=1001,mode=0400 \
    redis:7.4.1

4cdgfyky7ozwh3htjfw0d12qv

要授予服务访问多个 secrets 的权限,使用多个 --secret 标志。

如果未指定 target,secrets 位于容器中的 /run/secrets 路径下。如果未指定 target,secret 的名称将用作容器中的内存文件名称。如果指定了 target,则将其用作文件名。在上面的示例中,为指定的每个 secret target 创建了两个文件:/run/secrets/ssh/run/secrets/app

创建带 configs 的服务 (--config)

使用 --config 标志为容器授予访问 config 的权限。

创建带 config 的服务。config 将被挂载到 redis-config 中,由在容器内运行命令的用户拥有(通常是 root),文件模式为 0444 或全局可读。可以将 uidgid 指定为数字 ID 或名称。使用名称时,提供的组/用户名必须已存在于容器中。mode 指定为 4 位数字序列,例如 0755

$ docker service create --name=redis --config redis-conf redis:7.4.1

创建带 config 并指定 target 位置和文件模式的服务

$ docker service create --name redis \
  --config source=redis-conf,target=/etc/redis/redis.conf,mode=0400 redis:7.4.1

要授予服务访问多个 configs 的权限,使用多个 --config 标志。

如果未指定 target,configs 位于容器中的 / 路径下。如果未指定 target,config 的名称将用作容器中的文件名称。如果指定了 target,则将其用作文件名。

创建具有滚动更新策略的服务

$ docker service create \
  --replicas 10 \
  --name redis \
  --update-delay 10s \
  --update-parallelism 2 \
  redis:7.4.1

当你运行 service update 时,调度器一次最多更新 2 个任务,更新间隔为 10s。更多信息,请参阅滚动更新教程

设置环境变量 (-e, --env)

这将为服务中的所有任务设置一个环境变量。例如:

$ docker service create \
  --name redis_2 \
  --replicas 5 \
  --env MYVAR=foo \
  redis:7.4.1

要指定多个环境变量,请使用多个 --env 标志,每个标志指定一个独立的键值对。

$ docker service create \
  --name redis_2 \
  --replicas 5 \
  --env MYVAR=foo \
  --env MYVAR2=bar \
  redis:7.4.1

创建具有特定主机名的服务 (--hostname)

此选项将 docker 服务容器的主机名设置为特定字符串。例如:

$ docker service create --name redis --hostname myredis redis:7.4.1

在服务上设置元数据 (-l, --label)

标签是一个 key=value 对,用于向服务应用元数据。要为服务添加两个标签:

$ docker service create \
  --name redis_2 \
  --label com.example.foo="bar" \
  --label bar=baz \
  redis:7.4.1

有关标签的更多信息,请参阅应用自定义元数据

添加绑定挂载、卷或内存文件系统 (--mount)

Docker 支持三种不同的挂载类型,允许容器读写文件或目录,无论是在主机操作系统上还是在内存文件系统上。这些类型是数据卷(通常简称为卷)、绑定挂载、tmpfs 和命名管道。

绑定挂载使主机上的文件或目录对挂载在其内的容器可用。绑定挂载可以是只读或读写。例如,容器可以通过绑定挂载主机的 /etc/resolv.conf 来共享主机的 DNS 信息,或者容器可以将日志写入主机的 /var/log/myContainerLogs 目录。如果你使用绑定挂载,并且你的主机和容器在权限、访问控制或其他类似细节上有不同的概念,你将会遇到可移植性问题。

命名卷是一种机制,用于将容器所需的持久数据与用于创建容器的镜像以及主机分离。命名卷由 Docker 创建和管理,即使没有容器正在使用它,命名卷也会持久存在。命名卷中的数据可以在容器和主机之间共享,也可以在多个容器之间共享。Docker 使用卷驱动程序来创建、管理和挂载卷。可以使用 Docker 命令备份或恢复卷。

tmpfs 在容器内部挂载一个 tmpfs 文件系统,用于存放易失性数据。

npipe 将主机上的命名管道挂载到容器中。

考虑一种情况,你的镜像启动了一个轻量级 Web 服务器。你可以使用该镜像作为基础镜像,复制网站的 HTML 文件,并将其打包到另一个镜像中。每次网站发生变化时,你需要更新新镜像并重新部署所有为你的网站提供服务的容器。一个更好的解决方案是将网站存储在一个命名卷中,并在每个 Web 服务器容器启动时将其附加到容器。要更新网站,只需更新命名卷即可。

有关命名卷的更多信息,请参阅数据卷

下表描述了适用于服务中的绑定挂载和命名卷的选项:

选项必需描述
type

挂载类型,可以是volume, bind, tmpfs,或npipe。默认为volume,如果未指定类型。

  • volume:将一个托管卷挂载到容器中。
  • bind:将主机上的目录或文件绑定挂载到容器中。
  • tmpfs:在容器中挂载一个 tmpfs
  • npipe:将主机上的命名管道挂载到容器中 (仅限 Windows 容器)。
srcsource对于type=bindtype=npipe
  • type=volume: src是指定卷名称的可选方式(例如,src=my-volume)。如果指定的命名卷不存在,将自动创建。如果没有src被指定,则卷将被分配一个随机名称,该名称在主机上保证唯一,但在整个集群中可能不唯一。随机命名的卷与其容器具有相同的生命周期,并在容器被销毁时销毁(这发生在service update 时,或缩容/重新均衡服务时)service update,或缩容/重新均衡服务时)
  • type=bind: src是必需的,指定要绑定挂载的文件或目录的绝对路径(例如,src=/path/on/host/)。如果文件或目录不存在,将产生错误。
  • type=tmpfs: src不受支持。

dstdestinationtarget

容器内部的挂载路径,例如/some/path/in/container/。如果容器文件系统中不存在该路径,Engine 会在挂载卷或绑定挂载之前在指定位置创建一个目录。

readonlyro

Engine 挂载绑定和卷时默认为read-write,除非readonly选项被指定。请注意,设置readonly对于绑定挂载可能不会使其子挂载也变为readonly,取决于内核版本。另请参阅bind-recursive.

  • true1或无值:以只读方式挂载绑定或卷。
  • false0:以读写方式挂载绑定或卷。

绑定挂载选项

以下选项仅适用于绑定挂载 (type=bind)

选项描述
bind-propagation

请参阅绑定传播部分

consistency

挂载的一致性要求;以下之一:

  • default:等同于consistent.
  • consistent:完全一致性。容器运行时和主机始终保持对挂载的完全一致视图。
  • cached:主机的挂载视图是权威的。主机上的更新可能需要延迟才能在容器内可见。
  • delegated:容器运行时的挂载视图是权威的。容器中的更新可能需要延迟才能在主机上可见。
bind-recursive默认情况下,子挂载也会递归地绑定挂载。但是,当绑定挂载配置了readonly选项时,这种行为可能会令人困惑,因为子挂载可能不会以只读方式挂载,具体取决于内核版本。设置bind-recursive以控制递归绑定挂载的行为。

值为以下之一:

  • <enabled: 启用递归绑定挂载。如果内核版本为 v5.12 或更高,只读挂载也会被递归地设为只读。否则,它们不会被递归地设为只读。
  • <disabled: 禁用递归绑定挂载。
  • <writable: 启用递归绑定挂载。只读挂载不会被递归地设为只读。
  • <readonly: 启用递归绑定挂载。如果内核版本为 v5.12 或更高,只读挂载会被递归地设为只读。否则,Engine 会报错。
未指定此选项时,默认行为等同于设置enabled.
bind-nonrecursivebind-nonrecursive自 Docker Engine v25.0 起已弃用。请使用bind-recursive代替。

值是可选的

  • true1:等同于bind-recursive=disabled.
  • false0:等同于bind-recursive=enabled.
绑定传播 (Bind propagation)

绑定传播 (Bind propagation) 指的是在给定绑定挂载或命名卷内创建的挂载是否可以传播到该挂载的副本。考虑一个挂载点 /mnt,它同时也被挂载到 /tmp。传播设置控制是否将 /tmp/a 上的挂载也提供给 /mnt/a。每个传播设置都有一个递归对应项。在递归的情况下,假设 /tmp/a 也被挂载为 /foo。传播设置控制 /mnt/a 和/或 /tmp/a 是否会存在。

bind-propagation 选项对于绑定挂载和卷挂载都默认为 rprivate,且仅可用于绑定挂载进行配置。换句话说,命名卷不支持绑定传播。

  • shared(共享):原始挂载的子挂载会暴露给副本挂载,副本挂载的子挂载也会传播到原始挂载。
  • slave(从属):类似于共享挂载,但只在一个方向上。如果原始挂载暴露了一个子挂载,副本挂载可以看到它。但是,如果副本挂载暴露了一个子挂载,原始挂载无法看到它。
  • private(私有):挂载是私有的。其中的子挂载不暴露给副本挂载,副本挂载的子挂载也不暴露给原始挂载。
  • rshared(递归共享):与 shared 相同,但传播也延伸到原始或副本挂载点内嵌套的挂载点之间。
  • rslave(递归从属):与 slave 相同,但传播也延伸到原始或副本挂载点内嵌套的挂载点之间。
  • rprivate(递归私有):默认值。与 private 相同,意味着原始或副本挂载点内任何地方的挂载点都不会向任何方向传播。

有关绑定传播的更多信息,请参阅 Linux 内核共享子树文档

命名卷的选项

以下选项仅可用于命名卷 (type=volume)

选项描述
volume-driver

用于卷的卷驱动插件名称。默认为"local",以便在卷不存在时使用本地卷驱动创建该卷。

volume-label创建卷时应用的一个或多个自定义元数据(“标签”)。例如:volume-label=mylabel=hello-world,my-other-label=hello-mars。有关标签的更多信息,请参阅 应用自定义元数据
volume-nocopy默认情况下,如果您将一个空卷挂载到容器,并且容器中挂载路径(dst)已经存在文件或目录,Engine 会将这些文件和目录复制到卷中,从而允许主机访问它们。设置此选项以volume-nocopy禁用将文件从容器的文件系统复制到卷中,并挂载空卷。

值是可选的

  • true1: 如果您不提供值,此项为默认值。禁用复制。
  • false0: 启用复制。
volume-opt特定于给定卷驱动程序的选项,在创建卷时会传递给驱动程序。选项以逗号分隔的键/值对列表形式提供,例如:volume-opt=some-option=some-value,volume-opt=some-other-option=some-other-value。有关特定驱动程序的可用选项,请参阅该驱动程序的文档。

tmpfs 的选项

以下选项仅可用于 tmpfs 挂载 (type=tmpfs);

选项描述
tmpfs-sizetmpfs 挂载的大小(以字节为单位)。在 Linux 中默认为无限制。
tmpfs-modetmpfs 的文件模式(八进制)。(例如"700""0700"。)"1777"默认为

在 Linux 中。

"--mount" 与 "--volume" 的区别

  • --mount 标志支持 docker run 命令中 -v--volume 标志支持的大多数选项,但有一些重要的例外情况:

  • --mount 标志允许您按卷指定卷驱动程序和卷驱动程序选项,而无需预先创建卷。相比之下,docker run 允许您使用 --volume-driver 标志指定一个由所有卷共享的单个卷驱动程序。

  • --mount 标志允许您在卷创建之前为其指定自定义元数据(“标签”)。

  • 当您将 --mounttype=bind 一起使用时,主机路径必须指向主机上一个已存在的路径。系统不会为您创建该路径,如果路径不存在,服务将因错误而失败。

--mount 标志不允许您使用用于 selinux 标签的 Zz 标志重新标记卷。

使用命名卷创建服务

$ docker service create \
  --name my-service \
  --replicas 3 \
  --mount type=volume,source=my-volume,destination=/path/in/container,volume-label="color=red",volume-label="shape=round" \
  nginx:alpine

以下示例创建了一个使用命名卷的服务:

对于服务的每个副本,Engine 会从任务部署所在的默认("local")卷驱动请求名为 "my-volume" 的卷。如果卷不存在,Engine 会创建一个新卷并应用 "color" 和 "shape" 标签。

任务启动时,该卷会挂载到容器内的 /path/in/container/

请注意,默认("local")卷是一个本地范围的卷驱动程序。这意味着根据任务部署的位置,该任务可能会获得一个名为 "my-volume" 的卷,或者与同一服务的其他任务共享同一个 "my-volume"。如果容器内运行的软件未设计用于处理并发写入同一位置的进程,多个容器写入单个共享卷可能会导致数据损坏。此外,还要考虑到容器可能会被 Swarm 编排器重新调度并部署到不同的节点上。

创建使用匿名卷的服务

$ docker service create \
  --name my-service \
  --replicas 3 \
  --mount type=volume,destination=/path/in/container \
  nginx:alpine

以下命令创建了一个拥有三个副本的服务,并在 /path/in/container 处使用一个匿名卷:

在此示例中,未为卷指定名称(source),因此会为每个任务创建一个新卷。这确保了每个任务都有自己的卷,且卷不会在任务之间共享。匿名卷在使用它们的任务完成后会被移除。

创建使用绑定挂载主机目录的服务

$ docker service create \
  --name my-service \
  --mount type=bind,source=/path/on/host,destination=/path/in/container \
  nginx:alpine

以下示例在支持该服务的容器中,将主机目录绑定挂载到 /path/in/container

设置服务模式 (--mode)

服务模式决定了这是一个复制型服务 (replicated service) 还是一个全局型服务 (global service)。复制型服务运行指定数量的任务副本,而全局型服务在 swarm 集群中的每个活动节点上运行。

$ docker service create \
 --name redis_2 \
 --mode global \
 redis:7.4.1

以下命令创建了一个全局型服务:

指定服务约束 (--constraint)

您可以通过定义约束表达式来限制任务可以调度到的节点集合。约束表达式可以使用匹配 (==) 或排除 (!=) 规则。多个约束会找到满足所有表达式的节点(AND 匹配)。约束可以匹配节点或 Docker Engine 标签,如下所示:节点属性匹配项
示例node.id节点 ID
node.id==2ivku8v2gvtg4node.hostname节点主机名
node.hostname!=node-2node.role节点角色(manager/worker
node.role==managernode.platform.os节点操作系统
node.platform.os==windowsnode.platform.arch节点架构
node.platform.arch==x86_64node.labels用户自定义节点标签
node.labels.security==highengine.labelsDocker Engine 标签

engine.labels.operatingsystem==ubuntu-24.04

engine.labels 适用于 Docker Engine 标签,例如操作系统、驱动程序等。Swarm 管理员通过 docker node update 命令添加用于操作目的的 node.labels

$ docker service create \
  --name redis_2 \
  --constraint node.platform.os==linux \
  --constraint node.labels.type==queue \
  redis:7.4.1

例如,以下限制将 redis 服务的任务仅限于节点类型标签等于 queue 的节点:

如果服务约束排除了集群中的所有节点,将打印一条消息,表示未找到合适的节点,但调度器将启动协调循环,并在合适的节点可用时部署服务。

$ docker service create \
  --name web \
  --constraint node.labels.region==east \
  nginx:alpine

lx1wrhhpmbbu0wuk0ybws30bc
overall progress: 0 out of 1 tasks
1/1: no suitable node (scheduling constraints not satisfied on 5 nodes)

$ docker service ls
ID                  NAME     MODE         REPLICAS   IMAGE               PORTS
b6lww17hrr4e        web      replicated   0/1        nginx:alpine

在以下示例中,未找到满足约束的节点,导致服务未能协调到期望状态:

$ docker node update --label-add region=east yswe2dm4c5fdgtsrli1e8ya5l
yswe2dm4c5fdgtsrli1e8ya5l

$ docker service ls
ID                  NAME     MODE         REPLICAS   IMAGE               PORTS
b6lww17hrr4e        web      replicated   1/1        nginx:alpine

在集群中的一个节点上添加 region=east 标签后,服务将协调,并部署期望数量的副本:

指定服务放置偏好 (--placement-pref)

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

您可以设置服务,使其任务在不同类别的节点上均匀分布。一个有用的示例是将任务在多个数据中心或可用区之间进行平衡。以下示例说明了这一点:

  • 这使用 --placement-prefspread 策略(目前唯一支持的策略)将任务均匀分布到 datacenter 节点标签的不同值上。在此示例中,我们假设每个节点都附加了 datacenter 节点标签。如果 swarm 集群中的节点有三种不同的此标签值,则三分之一的任务将放置在与每个值关联的节点上。即使一个值关联的节点比另一个值多,情况也是如此。例如,考虑以下节点集合:
  • 三个带有 node.labels.datacenter=east 标签的节点
  • 两个带有 node.labels.datacenter=south 标签的节点

一个带有 node.labels.datacenter=west 标签的节点

由于我们在 datacenter 标签的值上进行分布,并且服务有 9 个副本,因此每个数据中心将分到 3 个副本。与值 east 关联的有三个节点,因此每个节点将获得为该值保留的三个副本中的一个。与值 south 关联的有两个节点,为该值保留的三个副本将在这两个节点之间分配,一个节点获得两个副本,另一个节点获得一个副本。最后,west 只有一个节点,它将获得为 west 保留的所有三个副本。

如果某一类别中的节点(例如,带有 node.labels.datacenter=south 标签的节点)由于约束或资源限制无法处理其应得的任务份额,则多余的任务(如果可能)将被分配到其他节点上。

placement preferences 支持 engine 标签和 node 标签。上面的示例使用了 node 标签,因为它被引用为 node.labels.datacenter。要在 engine 标签的值上进行分布,请使用 --placement-pref spread=engine.labels.<labelname>

可以为一个服务添加多个 placement preferences。这将建立一个偏好层级,以便任务首先在一个类别上进行划分,然后再在其他类别上进一步划分。一个可能有用的示例是将任务公平地分配到数据中心之间,然后将每个数据中心内的任务分配到选择的机架上。要添加多个 placement preferences,请多次指定 --placement-pref 标志。顺序很重要,placement preferences 将在进行调度决策时按照给定的顺序应用。

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

以下示例设置了一个具有多个 placement preferences 的服务。任务首先分布到各个数据中心,然后分布到机架上(如相应标签所示):

使用 docker service update 更新服务时,--placement-pref-add 会在所有现有 placement preferences 之后追加一个新的 placement preference。--placement-pref-rm 会删除与参数匹配的现有 placement preference。

指定服务的内存要求和约束 (--reserve-memory 和 --limit-memory)

如果您的服务需要最少量的内存才能正常运行,您可以使用 --reserve-memory 来指定服务只能调度到具有足够可保留内存的节点上。如果没有满足条件的节点可用,任务将不会被调度,而是保持待定状态。

$ docker service create --reserve-memory=4GB --name=too-big nginx:alpine

以下示例要求在给定节点上必须有 4GB 可用且可保留的内存,然后才能在该节点上调度服务运行。

管理器不会在单个节点上调度一组容器,如果它们的总保留内存超过该节点上可用的内存。

$ docker service create --limit-memory=4GB --name=too-big nginx:alpine

任务调度并运行后,--reserve-memory 不会强制执行内存限制。使用 --limit-memory 可确保任务在节点上使用的内存不超过给定数量。此示例将任务使用的内存量限制为 4GB。即使您的每个节点只有 2GB 内存,任务也会被调度,因为 --limit-memory 是上限。

使用 --reserve-memory--limit-memory 并不能保证 Docker 不会在主机上使用超出您期望的内存。例如,您可以创建许多服务,它们的总内存使用量可能会耗尽可用内存。

您可以通过考虑主机上运行的其他(非容器化)软件来防止此情况耗尽可用内存。如果 --reserve-memory 大于或等于 --limit-memory,Docker 将不会在内存不足的主机上调度服务。--limit-memory 会将服务的内存限制在此范围内,因此如果每个服务都设置了内存保留和限制,Docker 服务就不太可能使主机内存饱和。直接在 Docker 主机上运行的其他非服务容器或应用程序仍然可能耗尽内存。

这种方法也有缺点。保留内存还意味着您可能无法最佳利用节点上的可用内存。考虑一个服务,在正常情况下使用 100MB 内存,但根据负载可能会“峰值”达到 500MB。为该服务保留 500MB(以保证“峰值”时有 500MB 可用)会导致大部分时间有 400MB 内存被浪费。

  • 简而言之,您可以采用更保守或更灵活的方法:

  • 保守方法:保留 500MB,并限制为 500MB。这基本上是将服务容器视为虚拟机,您可能会失去容器的一个重要优势,即每个主机的服务密度更高。

灵活方法:将限制设置为 500MB,假设如果服务需要超过 500MB,则表明其出现故障。保留介于 100MB“正常”需求和 500MB“峰值”需求之间的某个值。这假定当该服务处于“峰值”时,其他服务或非容器化工作负载可能不会同时处于峰值。

您采用的方法在很大程度上取决于您的工作负载的内存使用模式。您应该在正常和峰值条件下进行测试,然后再确定采用何种方法。

在 Linux 上,您还可以使用 cgroups 或其他相关的操作系统工具,在主机操作系统层面限制服务在给定主机上的总内存占用。

指定每个节点的最大副本数 (--replicas-max-per-node)

使用 --replicas-max-per-node 标志来设置可以在一个节点上运行的最大副本任务数。以下命令创建了一个 nginx 服务,该服务有 2 个副本任务,但每个节点上只有一个副本任务。

一个有用的示例是结合 --placement-pref 将任务在多个数据中心之间进行平衡,并使用 --replicas-max-per-node 设置确保在维护或数据中心故障期间副本不会迁移到另一个数据中心。

$ docker service create \
  --name nginx \
  --replicas 2 \
  --replicas-max-per-node 1 \
  --placement-pref 'spread=node.labels.datacenter' \
  nginx

以下示例对此进行了说明:

将服务连接到现有网络 (--network)

您可以使用 overlay network 将 swarm 集群中的一个或多个服务连接起来。

$ docker network create --driver overlay my-network

etjpu59cykrptrgw0z0hk5snf

首先,在管理节点上使用 docker network create 命令创建一个 overlay network:

在 swarm 模式下创建 overlay network 后,所有管理节点都可以访问该网络。

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

716thylsndqma81j6kkkb5aus

创建服务并传递 --network 标志将服务连接到 overlay network 时:

swarm 集群会将 my-network 扩展到运行服务的每个节点。

同一网络上的容器可以使用 服务发现 相互访问。

--network 的长格式语法允许指定别名列表和驱动程序选项:--network name=my-network,alias=web1,driver-opt=field1=value1

将服务端口发布到 swarm 外部 (-p, --publish)

$ docker service create --name my_web --replicas 3 --publish 8080:80 nginx

您可以使用 --publish 标志发布服务端口,使其可从 swarm 集群外部访问。--publish 标志有两种不同的参数格式。短格式是基于位置的,允许您指定发布的端口和目标端口,用冒号 (:) 分隔。

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

还有一种长格式,更易于阅读,并允许指定更多选项。推荐使用长格式。使用短格式时无法指定服务的模式。以下是使用长格式发布与上面相同服务的示例:

选项您可以指定的选项如下:短格式描述
长格式发布端口和目标端口--publish 8080:80

--publish published=8080,target=80容器内的目标端口,以及使用路由网格(ingress

)或主机级网络将它映射到节点上的端口。此表中稍后还提供了更多选项。推荐使用键值语法,因为它在一定程度上具有自描述性。模式短格式无法设置。

--publish published=8080,target=80,mode=host容器内的目标端口,以及使用路由网格(用于绑定端口的模式,可以是。默认为容器内的目标端口,以及使用路由网格(host

或使用路由网格。协议--publish 8080:80/tcp

--publish published=8080,target=80,protocol=tcp要使用的协议, , tcp,或udp。默认为要使用的协议,sctp。要绑定同时支持这两种协议的端口,请指定-p或 --publish

标志两次。

当您使用 ingress 模式发布服务端口时,swarm 路由网格会使服务在每个节点上都可通过发布的端口访问,无论该节点上是否有服务的任务正在运行。如果使用 host 模式,端口仅绑定在服务正在运行的节点上,并且节点上的给定端口只能绑定一次。您只能使用长格式语法设置发布模式。有关详细信息,请参阅 使用 swarm 模式路由网格

为托管服务账户提供凭据规范 (--credentials-spec)

此选项仅用于使用 Windows 容器的服务。--credential-spec 必须采用 file://<filename>registry://<value-name> 格式。

当使用 file://<filename> 格式时,引用的文件必须存在于 Docker 数据目录的 CredentialSpecs 子目录中,在 Windows 上默认为 C:\ProgramData\Docker\。例如,指定 file://spec.json 会加载 C:\ProgramData\Docker\CredentialSpecs\spec.json

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\Containers\CredentialSpecs

当使用 registry://<value-name> 格式时,凭据规范将从守护进程主机上的 Windows 注册表中读取。指定的注册表值必须位于

使用模板创建服务

支持的标志如下:

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

Go 模板的有效占位符如下所列:

占位符描述
.Service.ID服务 ID
.Service.Name服务名称
服务名称服务标签
.Service.Labelsnode.id
服务标签.Node.ID
节点 ID.Node.Hostname
节点主机名.Task.ID
任务 ID.Task.Name

任务名称

.Task.Slot

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

va8ew30grofhjoychbr6iot8c

$ 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}}" 2e7a8a9c4da2-wo41w8hg8qanxwjwsg4kxpprj-hosttempl

x3ti0erg11rjpg64m75kej2mz-hosttempl

任务槽

模板示例

$ docker service create --name myservice --isolation=process microsoft/nanoserver

在此示例中,我们将根据服务的名称以及它所在的节点的 ID 和主机名来设置创建的容器的模板。

  • 在 Windows 上指定隔离模式 (--isolation)
  • 默认情况下,调度到 Windows 节点上的任务会使用针对该特定节点配置的默认隔离模式运行。要强制使用特定的隔离模式,您可以使用 --isolation 标志:
  • Windows 上支持的隔离模式有:

default:使用运行任务的节点上指定的默认设置

process:使用进程隔离(仅限 Windows Server)

$ docker service create \
    --name cuda \
    --generic-resource "NVIDIA-GPU=2" \
    --generic-resource "SSD=1" \
    nvidia/cuda

hyperv:使用 Hyper-V 隔离

创建请求通用资源的服务 (--generic-resources)

您可以使用 --generic-resource 标志(如果节点声明了这些资源)来缩小任务可以调度到的节点类型范围。

$ docker service create --name myjob \
                        --mode replicated-job \
                        bash "true"

作为作业运行

作业 (Job) 是一种特殊的服务,旨在运行操作直至完成然后停止,而不是运行长时间的守护进程。当属于某个作业的任务成功退出(返回值为 0)时,该任务将被标记为“已完成”,并且不会再次运行。

  • 作业可以通过两种模式之一启动:replicated-jobglobal-job
  • 此命令将运行一个任务,该任务将使用 bash 镜像执行命令 true,该命令将返回 0 然后退出。

尽管作业最终是不同类型的服务,但与其它服务相比,它们有一些注意事项:

所有更新或回滚配置选项均无效。作业可以更新,但不能推出或回滚,这使得这些配置选项变得没有意义。

作业在达到 Complete 状态后永远不会重新启动。这意味着对于作业,将 --restart-condition 设置为 any 与将其设置为 on-failure 是相同的。

作业支持复制型和全局型模式。

$ docker service create \
    --name mythrottledjob \
    --mode replicated-job \
    --replicas 10 \
    --max-concurrent 2 \
    bash "true"

复制型作业

复制型作业类似于复制型服务。设置 --replicas 标志将指定要执行的作业的总迭代次数。

默认情况下,复制型作业的所有副本将同时启动。要控制在任何时刻同时执行的副本总数,可以使用 --max-concurrent 标志:

上述命令总共将执行 10 个任务,但在任何给定时间只有其中 2 个任务会运行。