docker service create
描述 | 创建一个新的服务 |
---|---|
用法 | docker service create [OPTIONS] IMAGE [COMMAND] [ARG...] |
Swarm 此命令适用于 Swarm 编排器。
描述
根据指定的参数创建一个服务。
注意
这是一个集群管理命令,必须在 Swarm 管理节点上执行。要了解有关管理者和工作节点的信息,请参阅文档中的Swarm 模式部分。
选项
选项 | 默认值 | 描述 |
---|---|---|
--cap-add | API 1.41+ 添加 Linux 能力 | |
--cap-drop | API 1.41+ 移除 Linux 能力 | |
--config | API 1.30+ 指定要向服务公开的配置 | |
--constraint | 放置约束 | |
--container-label | 容器标签 | |
--credential-spec | API 1.29+ 用于托管服务帐户的凭据规范 (仅限 Windows) | |
-d, --detach | API 1.29+ 立即退出,而不是等待服务收敛 | |
--dns | API 1.25+ 设置自定义 DNS 服务器 | |
--dns-option | API 1.25+ 设置 DNS 选项 | |
--dns-search | API 1.25+ 设置自定义 DNS 搜索域 | |
--endpoint-mode | vip | 端点模式 (vip 或 dnsrr) |
--entrypoint | 覆盖镜像的默认 ENTRYPOINT | |
-e, --env | 设置环境变量 | |
--env-file | 从文件读取环境变量 | |
--generic-resource | 用户定义资源 | |
--group | API 1.25+ 为容器设置一个或多个补充用户组 | |
--health-cmd | API 1.25+ 用于检查健康状况的命令 | |
--health-interval | API 1.25+ 运行检查之间的时间间隔 (ms|s|m|h) | |
--health-retries | API 1.25+ 报告不健康所需的连续失败次数 | |
--health-start-interval | API 1.44+ 在启动期间运行检查之间的时间间隔 (ms|s|m|h) | |
--health-start-period | API 1.29+ 容器在计数不稳定重试之前进行初始化的启动周期 (ms|s|m|h) | |
--health-timeout | API 1.25+ 允许一次检查运行的最长时间 (ms|s|m|h) | |
--host | API 1.25+ 设置一个或多个自定义主机到 IP 的映射 (host:ip) | |
--hostname | API 1.25+ 容器主机名 | |
--init | API 1.37+ 在每个服务容器内使用 init 来转发信号和回收进程 | |
--isolation | API 1.35+ 服务容器隔离模式 | |
-l, --label | 服务标签 | |
--limit-cpu | 限制 CPU | |
--limit-memory | 限制内存 | |
--limit-pids | API 1.41+ 限制最大进程数 (默认 0 = 无限制) | |
--log-driver | 服务的日志驱动程序 | |
--log-opt | 日志驱动程序选项 | |
--max-concurrent | API 1.41+ 并发运行的作业任务数 (默认等于 --replicas) | |
--mode | replicated | 服务模式 (replicated , global , replicated-job , global-job ) |
--mount | 将文件系统挂载附加到服务 | |
--name | 服务名称 | |
--network | 网络附加 | |
--no-healthcheck | API 1.25+ 禁用容器指定的 HEALTHCHECK | |
--no-resolve-image | API 1.30+ 不查询注册表以解析镜像摘要和支持的平台 | |
--oom-score-adj | API 1.46+ 调整主机的 OOM 偏好设置 (-1000 到 1000) | |
--placement-pref | API 1.28+ 添加放置偏好 | |
-p, --publish | 将端口发布为节点端口 | |
-q, --quiet | 抑制进度输出 | |
--read-only | API 1.28+ 以只读方式挂载容器的根文件系统 | |
--replicas | 任务数 | |
--replicas-max-per-node | API 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-delay | API 1.28+ 任务回滚之间的延迟 (ns|us|ms|s|m|h) (默认 0s) | |
--rollback-failure-action | API 1.28+ 回滚失败时的操作 (pause , continue ) (默认 pause ) | |
--rollback-max-failure-ratio | API 1.28+ 回滚期间可容忍的失败率 (默认 0) | |
--rollback-monitor | API 1.28+ 每次任务回滚后监测故障的持续时间 (ns|us|ms|s|m|h) (默认 5s) | |
--rollback-order | API 1.29+ 回滚顺序 (start-first , stop-first ) (默认 stop-first ) | |
--rollback-parallelism | 1 | API 1.28+ 同时回滚的最大任务数 (0 表示一次回滚全部) |
--secret | API 1.25+ 指定要向服务公开的 secrets | |
--stop-grace-period | 强制终止容器前等待的时间 (ns|us|ms|s|m|h) (默认 10s) | |
--stop-signal | API 1.28+ 停止容器的信号 | |
--sysctl | API 1.40+ Sysctl 选项 | |
-t, --tty | API 1.25+ 分配一个伪终端 | |
--ulimit | API 1.41+ Ulimit 选项 | |
--update-delay | 更新之间的延迟 (ns|us|ms|s|m|h) (默认 0s) | |
--update-failure-action | 更新失败时的操作 (pause , continue , rollback ) (默认 pause ) | |
--update-max-failure-ratio | API 1.25+ 更新期间可容忍的失败率 (默认 0) | |
--update-monitor | API 1.25+ 每次任务更新后监测故障的持续时间 (ns|us|ms|s|m|h) (默认 5s) | |
--update-order | API 1.29+ 更新顺序 (start-first , stop-first ) (默认 stop-first ) | |
--update-parallelism | 1 | 同时更新的最大任务数 (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
或全局可读。可以将 uid
和 gid
指定为数字 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,如果未指定类型。
| |
src 或 source | 对于type=bind和type=npipe |
|
dst 或 destination 或 target | 是 | 容器内部的挂载路径,例如/some/path/in/container/。如果容器文件系统中不存在该路径,Engine 会在挂载卷或绑定挂载之前在指定位置创建一个目录。 |
readonly 或 ro | Engine 挂载绑定和卷时默认为read-write,除非readonly选项被指定。请注意,设置readonly对于绑定挂载可能不会使其子挂载也变为readonly,取决于内核版本。另请参阅bind-recursive.
|
绑定挂载选项
以下选项仅适用于绑定挂载 (type=bind
)
选项 | 描述 |
---|---|
bind-propagation | 请参阅绑定传播部分。 |
consistency | 挂载的一致性要求;以下之一:
|
bind-recursive | 默认情况下,子挂载也会递归地绑定挂载。但是,当绑定挂载配置了readonly选项时,这种行为可能会令人困惑,因为子挂载可能不会以只读方式挂载,具体取决于内核版本。设置bind-recursive以控制递归绑定挂载的行为。 值为以下之一:
|
bind-nonrecursive | bind-nonrecursive自 Docker Engine v25.0 起已弃用。请使用bind-recursive代替。 值是可选的
|
绑定传播 (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禁用将文件从容器的文件系统复制到卷中,并挂载空卷。 值是可选的
|
volume-opt | 特定于给定卷驱动程序的选项,在创建卷时会传递给驱动程序。选项以逗号分隔的键/值对列表形式提供,例如:volume-opt=some-option=some-value,volume-opt=some-other-option=some-other-value。有关特定驱动程序的可用选项,请参阅该驱动程序的文档。 |
tmpfs 的选项
以下选项仅可用于 tmpfs 挂载 (type=tmpfs
);
选项 | 描述 |
---|---|
tmpfs-size | tmpfs 挂载的大小(以字节为单位)。在 Linux 中默认为无限制。 |
tmpfs-mode | tmpfs 的文件模式(八进制)。(例如"700"或"0700"。)"1777"默认为 |
在 Linux 中。
"--mount" 与 "--volume" 的区别
--mount
标志支持docker run
命令中-v
或--volume
标志支持的大多数选项,但有一些重要的例外情况:--mount
标志允许您按卷指定卷驱动程序和卷驱动程序选项,而无需预先创建卷。相比之下,docker run
允许您使用--volume-driver
标志指定一个由所有卷共享的单个卷驱动程序。--mount
标志允许您在卷创建之前为其指定自定义元数据(“标签”)。当您将
--mount
与type=bind
一起使用时,主机路径必须指向主机上一个已存在的路径。系统不会为您创建该路径,如果路径不存在,服务将因错误而失败。
--mount
标志不允许您使用用于 selinux
标签的 Z
或 z
标志重新标记卷。
使用命名卷创建服务
$ 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==2ivku8v2gvtg4 | node.hostname | 节点主机名 |
node.hostname!=node-2 | node.role | 节点角色( |
node.role==manager | node.platform.os | 节点操作系统 |
node.platform.os==windows | node.platform.arch | 节点架构 |
node.platform.arch==x86_64 | node.labels | 用户自定义节点标签 |
node.labels.security==high | engine.labels | Docker 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-pref
和spread
策略(目前唯一支持的策略)将任务均匀分布到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.Labels | node.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-job
或global-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 个任务会运行。