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+ 指定要暴露给服务的秘密
--stop-grace-period强制终止容器前的等待时间(ns|us|ms|s|m|h)(默认 10s)
--stop-signalAPI 1.28+ 停止容器的信号
--sysctlAPI 1.40+ Sysctl 选项
-t, --ttyAPI 1.25+ 分配一个伪 TTY
--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 代理
-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)

如果您的镜像在需要登录的私有注册表上可用,请在登录后使用 `docker service create` 命令时带上 `--with-registry-auth` 标志。如果您的镜像存储在私有注册表 `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

创建带有秘密的服务(--secret)

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

创建一个指定秘密的服务

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

4cdgfyky7ozwh3htjfw0d12qv

创建一个服务,指定秘密、目标、用户/组 ID 和模式

$ 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

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

如果未指定目标,则秘密位于容器中的 `/run/secrets`。如果未指定目标,则秘密的名称用作容器中的内存文件。如果指定了目标,则将其用作文件名。在上面的示例中,为每个指定的秘密目标创建了两个文件:`/run/secrets/ssh` 和 `/run/secrets/app`。

创建带配置的服务(--config)

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

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

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

创建具有配置的服务并指定目标位置和文件模式

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

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

如果未指定目标,则配置位于容器中的 `/`。如果未指定目标,则配置的名称用作容器中文件的名称。如果指定了目标,则将其用作文件名。

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

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

当您运行 服务更新 时,调度程序一次最多更新 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 服务器容器启动时将其附加到每个容器。要更新网站,只需更新命名卷即可。

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

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

选项必需描述
类型

挂载类型,可以是, 绑定, tmpfs,或命名管道。如果未指定类型,则默认为

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

dstdestinationtarget

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

readonlyro

引擎以读写方式挂载绑定和卷,除非在挂载绑定或卷时给定readonly选项。请注意,为绑定挂载设置readonly可能不会使其子挂载readonly,具体取决于内核版本。另请参阅bind-recursive.

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

绑定挂载选项

以下选项只能用于绑定挂载 (type=bind)

选项描述
绑定传播

请参阅绑定传播部分

一致性

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

  • default:等同于consistent.
  • consistent:完全一致性。容器运行时和主机始终保持挂载的相同视图。
  • 缓存:主机的挂载视图具有权威性。主机上进行的更新在容器内可见之前可能会有延迟。
  • 委派:容器运行时的挂载视图具有权威性。在容器中进行的更新在主机上可见之前可能会有延迟。
bind-recursive默认情况下,子挂载也会递归绑定挂载。然而,当绑定挂载配置了readonly选项时,此行为可能会令人困惑,因为子挂载可能不会挂载为只读,具体取决于内核版本。设置bind-recursive以控制递归绑定挂载的行为。

值是以下之一

  • <已启用:启用递归绑定挂载。如果内核是 v5.12 或更高版本,则只读挂载会递归只读。否则,它们不会递归只读。
  • <已禁用:禁用递归绑定挂载。
  • <可写:启用递归绑定挂载。只读挂载不会递归只读。
  • <readonly:启用递归绑定挂载。如果内核是 v5.12 或更高版本,则只读挂载会递归只读。否则,引擎会引发错误。
未指定选项时,默认行为对应于设置已启用.
bind-nonrecursivebind-nonrecursive自 Docker Engine v25.0 起已弃用。请使用bind-recursive代替。

一个值是可选的

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

绑定传播是指在给定绑定挂载或命名卷中创建的挂载是否可以传播到该挂载的副本。考虑挂载点 `/mnt`,它也挂载在 `/tmp` 上。传播设置控制 `tmp/a` 上的挂载是否也会在 `/mnt/a` 上可用。每个传播设置都有一个递归的对应点。在递归的情况下,考虑 `/tmp/a` 也挂载为 `/foo`。传播设置控制 `/mnt/a` 和/或 `/tmp/a` 是否存在。

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

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

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

命名卷的选项

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

选项描述
卷驱动程序

用于卷的卷驱动程序插件名称。默认为"local",如果卷不存在,则使用本地卷驱动程序创建卷。

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

一个值是可选的

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

tmpfs 选项

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

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

"--mount" 和 "--volume" 之间的区别

--mount 标志支持 docker run-v--volume 标志支持的大部分选项,但有一些重要例外:

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

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

  • 当您将 `type=bind` 与 `--mount` 一起使用时,主机路径必须指向主机上*现有*的路径。该路径不会为您创建,如果路径不存在,服务将因错误而失败。

  • --mount 标志不允许您使用 Zz 标志重新标记卷,这些标志用于 selinux 标记。

创建使用命名卷的服务

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

$ 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

对于服务的每个副本,引擎会向默认(“local”)卷驱动程序请求一个名为“my-volume”的卷,该卷部署在任务所在的节点上。如果该卷不存在,引擎会创建一个新卷并应用“color”和“shape”标签。

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

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

创建一个使用匿名卷的服务

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

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

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

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

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

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

设置服务模式 (--mode)

服务模式决定这是*复制*服务还是*全局*服务。复制服务运行指定数量的任务,而全局服务在 Swarm 中的每个活动节点上运行。

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

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

指定服务约束(--constraint)

您可以通过定义约束表达式来限制任务可以调度到的节点集。约束表达式可以使用*匹配*(`==`)或*排除*(`!=`)规则。多个约束会找到满足所有表达式(AND 匹配)的节点。约束可以匹配节点或 Docker Engine 标签,如下所示:

节点属性匹配示例
node.id节点 IDnode.id==2ivku8v2gvtg4
node.hostname节点主机名node.hostname!=node-2
node.role节点角色(manager/workernode.role==manager
node.platform.os节点操作系统node.platform.os==windows
node.platform.arch节点架构node.platform.arch==x86_64
node.labels用户定义的节点标签node.labels.security==high
engine.labelsDocker Engine 的标签engine.labels.operatingsystem==ubuntu-24.04

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

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

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

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

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

$ 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

region=east 标签添加到集群中的节点后,服务会进行协调,并部署所需数量的副本。

$ 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

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

您可以将服务设置为将任务均匀地分配到不同类别的节点。其中一个有用的例子是跨数据中心或可用区平衡任务。下面的例子说明了这一点:

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

这使用 `spread` 策略(目前唯一支持的策略)的 `--placement-pref` 选项,将任务均匀地分布到 `datacenter` 节点标签的值上。在这个例子中,我们假设每个节点都附加了一个 `datacenter` 节点标签。如果 Swarm 中的节点有三个不同的 `datacenter` 标签值,那么三分之一的任务将放置在与每个值相关联的节点上。即使一个值比另一个值拥有更多的节点,这也是成立的。例如,考虑以下节点集:

  • 三个节点带有 node.labels.datacenter=east
  • 两个节点带有 node.labels.datacenter=south
  • 一个节点带有 node.labels.datacenter=west

由于我们正在根据 `datacenter` 标签的值进行扩展,并且服务有 9 个副本,因此每个数据中心将最终分配 3 个副本。有三个节点与值 `east` 相关联,因此每个节点将获得为其保留的三个副本中的一个。有两个节点带有值 `south`,为其保留的三个副本将在它们之间分配,其中一个节点获得两个副本,另一个节点仅获得一个。最后,`west` 有一个节点,将获得为其保留的所有三个副本。

如果某个类别中的节点(例如,带有 `node.labels.datacenter=south` 的节点)由于约束或资源限制而无法处理其公平份额的任务,那么如果可能,多余的任务将分配给其他节点。

引擎标签和节点标签都受放置偏好支持。上面的示例使用节点标签,因为该标签通过 `node.labels.datacenter` 引用。要根据引擎标签的值进行扩展,请使用 ` --placement-pref spread=engine.labels.<labelname>`。

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

以下示例设置了一个具有多个放置偏好的服务。任务首先分布在各个数据中心,然后分布在机架上(由各自的标签指示):

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

当使用 docker service update 更新服务时,--placement-pref-add 会在所有现有放置偏好之后添加一个新的放置偏好。--placement-pref-rm 会删除与参数匹配的现有放置偏好。

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

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

以下示例要求在将服务调度到特定节点运行之前,该节点上必须有 4GB 内存可用且可保留。

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

管理员不会将一组容器调度到单个节点上,其总保留量超过该节点上可用的内存。

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

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

使用 `--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)

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

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

$ docker network create --driver overlay my-network

etjpu59cykrptrgw0z0hk5snf

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

当您创建服务并传递 `--network` 标志以将服务附加到覆盖网络时:

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

716thylsndqma81j6kkkb5aus

Swarm 将 my-network 扩展到运行服务的每个节点。

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

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

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

您可以使用 `--publish` 标志将服务端口发布到 Swarm 外部。`--publish` 标志可以采用两种不同风格的参数。短版本是位置性的,允许您指定发布的端口和目标端口,用冒号(`:`)分隔。

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

还有一种长格式,更易于阅读并允许您指定更多选项。首选长格式。使用短格式时不能指定服务的模式。以下是上面相同服务的长格式示例:

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

您可以指定的选项有:

选项短语法长语法描述
发布的端口和目标端口--publish 8080:80--publish published=8080,target=80

容器内的目标端口以及使用路由网格(入口)或主机级网络映射到节点上的端口。本表稍后提供更多选项。首选键值语法,因为它具有一定的自文档性。

mode短语法无法设置。--publish published=8080,target=80,mode=host

用于绑定端口的模式,可以是入口host。如果未指定类型,则默认为入口使用路由网格。

协议--publish 8080:80/tcp--publish published=8080,target=80,protocol=tcp

要使用的协议,tcp , udp,或sctp。如果未指定类型,则默认为tcp。要绑定两个协议的端口,请指定-p--publish标志两次。

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

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

此选项仅用于使用 Windows 容器的服务。`--credential-spec` 必须采用 `file://` 或 `registry://` 格式。

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

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

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

使用模板创建服务

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

支持的标志如下:

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

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

占位符描述
.Service.ID服务 ID
.Service.Name服务名称
.Service.Labels服务标签
.Node.ID节点 ID
.Node.Hostname节点主机名
.Task.ID任务 ID
.Task.Name任务名称
.Task.Slot任务插槽

模板示例

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

$ 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

在 Windows 上指定隔离模式(--isolation)

默认情况下,调度到 Windows 节点上的任务将使用为该特定节点配置的默认隔离模式运行。要强制使用特定的隔离模式,您可以使用 `--isolation` 标志:

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

Windows 上支持的隔离模式有:

  • default:使用运行任务的节点上指定的默认设置
  • process:使用进程隔离(仅限 Windows Server)
  • hyperv:使用 Hyper-V 隔离

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

您可以使用 `--generic-resource` 标志(如果节点宣传这些资源)缩小任务可以登陆的节点类型。

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

作为作业运行

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

作业通过两种模式之一启动:replicated-jobglobal-job

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

此命令将运行一个任务,该任务将使用 `bash` 镜像执行 `true` 命令,该命令将返回 0 然后退出。

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

  • 所有更新或回滚配置选项均无效。作业可以更新,但不能推出或回滚,这使得这些配置选项毫无意义。
  • 作业在达到 Complete 状态时绝不会重新启动。这意味着对于作业,将 --restart-condition 设置为 any 与将其设置为 on-failure 相同。

作业在复制模式和全局模式下都可用。

复制作业

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

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

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

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

全局作业

全局作业与全局服务类似,即在每个匹配放置约束的节点上执行一次任务。全局作业由 `global-job` 模式表示。

请注意,在创建全局作业后,添加到集群的任何新节点都将启动该作业中的一个任务。全局作业作为一个整体没有“完成”状态,除非满足作业约束的每个节点都有一个已完成的任务。

© . This site is unofficial and not affiliated with Kubernetes or Docker Inc.