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+ 指定要公开给服务的密钥 | |
--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+ 分配伪 TTY | |
--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 代理 | |
-w, --workdir | 容器内的工作目录 |
示例
创建服务
$ docker service create --name redis redis:3.0.6
dmu1ept4cxcfe8k8lhtux3ro3
$ docker service create --mode global --name redis2 redis:3.0.6
a8q9dasaafudfs8q8w32udass
$ docker service ls
ID NAME MODE REPLICAS IMAGE
dmu1ept4cxcf redis replicated 1/1 redis:3.0.6
a8q9dasaafud redis2 global 1/1 redis:3.0.6
使用私有注册表上的镜像创建服务 (--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
这将登录令牌从本地客户端传递到部署服务的 Swarm 节点,使用加密的 WAL 日志。有了这些信息,节点就可以登录到注册表并拉取镜像。
创建具有 5 个副本任务的服务 (--replicas)
使用--replicas
标志设置复制服务的副本任务数量。以下命令创建一个具有5
个副本任务的redis
服务
$ docker service create --name redis --replicas=5 redis:3.0.6
4cdgfyky7ozwh3htjfw0d12qv
上述命令设置服务的 *期望* 任务数量。即使命令立即返回,服务的实际扩展也可能需要一些时间。REPLICAS
列显示服务的实际和期望副本任务数量。
在下面的示例中,期望状态为5
个副本,但当前RUNNING
任务数量为3
$ docker service ls
ID NAME MODE REPLICAS IMAGE
4cdgfyky7ozw redis replicated 3/5 redis:3.0.7
一旦所有任务创建完毕并RUNNING
,实际任务数量将等于期望数量
$ docker service ls
ID NAME MODE REPLICAS IMAGE
4cdgfyky7ozw redis replicated 5/5 redis:3.0.7
使用密钥创建服务 (--secret)
使用--secret
标志允许容器访问密钥。
创建指定密钥的服务
$ docker service create --name redis --secret secret.json redis:3.0.6
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:3.0.6
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:3.0.6
使用配置创建服务并指定目标位置和文件模式
$ docker service create --name redis \
--config source=redis-conf,target=/etc/redis/redis.conf,mode=0400 redis:3.0.6
要授予服务对多个配置的访问权限,请使用多个--config
标志。
如果未指定目标,则配置位于容器中的/
目录下。如果未指定目标,则配置的名称将用作容器中文件的文件名。如果指定了目标,则该目标将用作文件名。
使用滚动更新策略创建服务
$ docker service create \
--replicas 10 \
--name redis \
--update-delay 10s \
--update-parallelism 2 \
redis:3.0.6
运行service update时,调度程序一次最多更新2个任务,更新之间间隔10s
。有关更多信息,请参阅滚动更新教程。
设置环境变量 (-e, --env)
这将为服务中的所有任务设置一个环境变量。例如
$ docker service create \
--name redis_2 \
--replicas 5 \
--env MYVAR=foo \
redis:3.0.6
要指定多个环境变量,请指定多个--env
标志,每个标志都带有一对单独的键值对。
$ docker service create \
--name redis_2 \
--replicas 5 \
--env MYVAR=foo \
--env MYVAR2=bar \
redis:3.0.6
使用特定主机名创建服务 (--hostname)
此选项将Docker服务容器的主机名设置为特定字符串。例如
$ docker service create --name redis --hostname myredis redis:3.0.6
在服务上设置元数据 (-l, --label)
标签是一个key=value
对,用于将元数据应用于服务。要为服务标记两个标签
$ docker service create \
--name redis_2 \
--label com.example.foo="bar" \
--label bar=baz \
redis:3.0.6
有关标签的更多信息,请参阅应用自定义元数据。
添加绑定挂载、卷或内存文件系统 (--mount)
Docker 支持三种不同的挂载方式,允许容器读取或写入文件或目录,这些文件或目录位于主机操作系统上或内存文件系统上。这些类型包括数据卷(通常简称为卷)、绑定挂载、tmpfs和命名管道。
绑定挂载使主机上的文件或目录可用于挂载它的容器。绑定挂载可以是只读的或读写的。例如,容器可以通过主机/etc/resolv.conf
的绑定挂载共享其主机的信息,或者容器可以将其日志写入主机/var/log/myContainerLogs
目录。如果您使用绑定挂载,并且您的主机和容器对权限、访问控制或其他此类细节有不同的概念,则会遇到可移植性问题。
命名卷是一种机制,用于将容器所需的持久性数据与用于创建容器的镜像和主机分离。命名卷由Docker创建和管理,即使当前没有容器使用它,命名卷也会持续存在。命名卷中的数据可以在容器和主机之间共享,也可以在多个容器之间共享。Docker使用卷驱动程序来创建、管理和挂载卷。您可以使用Docker命令备份或恢复卷。
tmpfs在容器内挂载一个tmpfs用于易失性数据。
npipe将主机上的命名管道挂载到容器中。
假设您的镜像启动一个轻量级Web服务器。您可以将该镜像用作基础镜像,复制网站的HTML文件,并将其打包到另一个镜像中。每次网站更改时,您都需要更新新镜像并重新部署所有提供网站服务的容器。更好的解决方案是将网站存储在命名卷中,并在Web服务器容器启动时将其附加到每个容器。要更新网站,只需更新命名卷即可。
有关命名卷的更多信息,请参阅数据卷。
下表描述了适用于服务中绑定挂载和命名卷的选项
选项 | 必需 | 描述 |
---|---|---|
类型 | 挂载类型,可以是volume, bind, tmpfs或npipe。默认为volume如果没有指定类型。
| |
src或source | 对于type=bind和type=npipe |
|
dst或destination或target | 是 | 容器内的挂载路径,例如/some/path/in/container/。如果容器的文件系统中不存在该路径,则引擎会在挂载卷或绑定挂载之前在指定位置创建一个目录。 |
readonly或ro | 引擎挂载绑定和卷读写除非readonly选项在挂载绑定或卷时给出。请注意,设置readonly对于绑定挂载可能不会使其子挂载readonly取决于内核版本。另请参阅bind-recursive.
|
绑定挂载选项
以下选项只能用于绑定挂载 (type=bind
)
选项 | 描述 |
---|---|
bind-propagation | 请参阅绑定传播部分。 |
一致性 | 挂载的一致性要求;其中之一
|
bind-recursive | 默认情况下,子挂载也会递归绑定挂载。但是,当使用readonly选项配置绑定挂载时,此行为可能会令人困惑,因为子挂载可能不会以只读方式挂载,这取决于内核版本。设置bind-recursive以控制递归绑定挂载的行为。 一个值是其中之一
|
bind-nonrecursive | bind-nonrecursive自 Docker Engine v25.0 起已弃用。请改用bind-recursive。 值是可选的
|
绑定传播
绑定传播是指在给定的绑定挂载或命名卷中创建的挂载是否可以传播到该挂载的副本。考虑挂载点/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
)
选项 | 描述 |
---|---|
volume-driver | 用于卷的卷驱动程序插件名称。默认为"local",如果卷不存在,则使用本地卷驱动程序创建卷。 |
volume-label | 创建卷时要应用的一个或多个自定义元数据(“标签”)。例如:volume-label=mylabel=hello-world,my-other-label=hello-mars。有关标签的更多信息,请参考 应用自定义元数据。 |
volume-nocopy | 默认情况下,如果将空卷附加到容器,并且容器的挂载路径中已存在文件或目录(dst),引擎会将这些文件和目录复制到卷中,允许主机访问它们。设置为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
标志支持 -v
或 --volume
标志对 docker run
支持的大多数选项,但有一些重要的例外。
--mount
标志允许您*每个卷*指定一个卷驱动程序和卷驱动程序选项,而无需预先创建卷。相比之下,docker run
允许您使用--volume-driver
标志指定单个卷驱动程序,该驱动程序由所有卷共享。--mount
标志允许您在创建卷之前为卷指定自定义元数据(“标签”)。当您将
--mount
与type=bind
一起使用时,主机路径必须引用主机上的*现有*路径。路径不会为您创建,如果路径不存在,服务将失败并显示错误。--mount
标志不允许您使用Z
或z
标志重新标记卷,这些标志用于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:3.0.6
指定服务约束(--constraint)
您可以通过定义约束表达式来限制可以调度任务的节点集。约束表达式可以使用*匹配* (==
) 或*排除* (!=
) 规则。多个约束查找满足每个表达式的节点(AND 匹配)。约束可以匹配节点或 Docker 引擎标签,如下所示
节点属性 | 匹配 | 示例 |
---|---|---|
node.id | 节点 ID | node.id==2ivku8v2gvtg4 |
node.hostname | 节点主机名 | node.hostname!=node-2 |
node.role | 节点角色 (manager /worker ) | 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.labels.operatingsystem==ubuntu-24.04 |
engine.labels
应用于 Docker 引擎标签,如操作系统、驱动程序等。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:3.0.6
如果服务约束排除了集群中的所有节点,则会打印一条消息,指出未找到合适的节点,但调度程序将启动协调循环,并在合适的节点可用后部署服务。
在下面的示例中,没有找到满足约束的节点,导致服务无法与所需状态协调。
$ 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:3.0.6
这使用带有spread
策略的--placement-pref
(当前唯一支持的策略)来在datacenter
节点标签的值上平均分配任务。在此示例中,我们假设每个节点都附加了datacenter
节点标签。如果 Swarm 中节点的此标签有三个不同的值,则三分之一的任务将放置在与每个值关联的节点上。即使一个值比另一个值有更多节点,也是如此。例如,考虑以下节点集
- 三个节点具有
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:3.0.6
使用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
标志设置可以在节点上运行的最大副本任务数。以下命令创建一个具有 2 个副本任务但每个节点只有一个副本任务的 nginx 服务。
一个可以使用此功能的示例是结合--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)
您可以使用覆盖网络连接集群中的一个或多个服务。
首先,在管理器节点上使用 docker network create 命令创建一个覆盖网络
$ docker network create --driver overlay my-network
etjpu59cykrptrgw0z0hk5snf
在集群模式下创建覆盖网络后,所有管理器节点都可以访问该网络。
当您创建服务并将--network
标志传递给它以将其附加到覆盖网络时
$ docker service create \
--replicas 3 \
--network my-network \
--name my-web \
nginx
716thylsndqma81j6kkkb5aus
集群会将 my-network 扩展到运行该服务的每个节点。
同一网络上的容器可以使用服务发现相互访问。
--network
的长格式语法允许指定别名和驱动程序选项列表:--network name=my-network,alias=web1,driver-opt=field1=value1
将服务端口发布到集群外部(-p,--publish)
您可以使用--publish
标志发布服务端口,以使其可供集群外部访问。--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 | 容器中的目标端口以及将其映射到节点上的端口,使用路由网格(入口)或主机级网络。更多选项将在本表后面提供。键值语法是首选,因为它具有一定的自文档性。 |
模式 | 无法使用简短语法设置。 | --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
模式发布服务端口时,集群路由网格使服务可在每个节点上的已发布端口上访问,无论该节点上是否正在运行该服务的任务。如果您使用host
模式,则端口仅绑定在运行该服务的节点上,并且节点上的给定端口只能绑定一次。您只能使用长语法设置发布模式。有关更多信息,请参阅使用集群模式路由网格。
为托管服务帐户提供凭据规范(--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
。
使用registry://<value-name>
格式时,凭据规范将从守护进程主机上的 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 服务器)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-job
或global-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
表示。
请注意,在创建全局作业后,添加到集群的任何新节点都将启动来自该作业的任务。全局作业本身没有“完成”状态,除非每个满足作业约束的节点都具有已完成的任务。