服务如何工作

当 Docker Engine 处于 Swarm 模式时,要部署应用程序镜像,您需要创建一个服务。通常,该服务是某个大型应用程序上下文中微服务的镜像。服务的示例可能包括 HTTP 服务器、数据库,或您希望在分布式环境中运行的任何其他类型的可执行程序。

创建服务时,您需要指定要使用的容器镜像以及在运行中的容器内执行的命令。此外,您还需要定义服务的以下选项:

  • Swarm 将服务暴露到外部所使用的端口
  • 用于服务连接到群集中其他服务的覆盖网络
  • CPU 和内存限制与预留
  • A rolling update policy
  • Swarm 中要运行的镜像副本数量

服务、任务和容器

当您将服务部署到 Swarm 时,Swarm 管理器会将您的服务定义接受为该服务的期望状态。然后,它会在 Swarm 中的节点上将服务调度为一个或多个副本任务。这些任务在 Swarm 的节点上独立运行。

例如,假设您希望在三个 HTTP 监听器实例之间进行负载均衡。下图显示了一个包含三个副本的 HTTP 监听器服务。这三个监听器实例中的每一个都是集群中的一个任务。

 HTTP listener service with three replicas

容器是一个隔离的进程。在Swarm模式下,每个任务恰好启动一个容器。任务类似于调度器放置容器的“插槽”。一旦容器运行起来,调度器就会识别出该任务处于运行状态。如果容器健康检查失败或终止,任务也会随之终止。

任务与调度

任务是群集内调度的基本单位。当您通过创建或更新服务来声明期望的服务状态时,编排器(orchestrator)会通过调度任务来实现该期望状态。例如,您可以定义一项服务,指示编排器始终运行三个 HTTP 监听器实例。作为响应,编排器会创建三个任务。每个任务都是一个槽位,调度器通过启动一个容器来填充它。该容器即为任务的实例化。如果某个 HTTP 监听器任务随后在健康检查中失败或崩溃,编排器将创建一个新的副本任务以启动一个新的容器。

任务是一种单向机制。它会单调地通过一系列状态:已分配、已准备、运行中等。如果任务失败,编排器将移除该任务及其容器,然后根据服务指定的期望状态创建一个新任务来替换它。

Docker Swarm 模式的底层逻辑是一个通用调度器和编排器。服务和任务的抽象本身并不了解它们所实现的容器。从理论上讲,您可以实现其他类型的任务,例如虚拟机任务或非容器化进程任务。调度器和编排器对任务类型不敏感。然而,当前版本的 Docker 仅支持容器任务。

下图展示了 Swarm 模式如何接收服务创建请求,并将任务调度到工作节点。

Services flow

待处理的服务

服务可能被配置为当前集群中没有任何节点可以运行其任务。在这种情况下,服务的状态将保持为 pending。 以下是服务可能保持在状态 pending 的一些示例。

提示

如果您的唯一目的是阻止服务部署,请将服务缩容至 0,而不是尝试将其配置为保持在 pending

  • 如果所有节点都处于暂停或 drained(排空)状态,当您创建服务时,该服务将处于待处理状态,直到有节点可用。实际上,第一个变为可用的节点会接收所有任务,因此在生产环境中不建议这样做。

  • 您可以为服务预留特定数量的内存。如果群集中的任何节点都没有所需的内存量,则该服务将保持挂起状态,直到有可用节点可以运行其任务为止。如果您指定非常大的值(例如 500 GB),除非您确实有一个能够满足该要求的节点,否则该任务将永远处于挂起状态。

  • 您可以对服务施加部署约束,但这些约束在特定时间点可能无法得到满足。

此行为表明,您的任务要求和配置并未与当前群集的状态紧密绑定。作为群集管理员,您只需声明群集的期望状态,管理器便会协同群集中的节点来实现该状态。您无需对群集中的任务进行微观管理。

复制和全局服务

存在两种类型的服务部署:复制集(replicated)和全局(global)。

对于复制服务,您需要指定要运行的相同任务的数量。例如,您决定部署一个 HTTP 服务,包含三个副本,每个副本提供相同的内容。

全局服务是指在每个节点上运行一个任务的服务。任务数量没有预先指定。每次向集群添加节点时,编排器都会创建一个任务,并由调度器将该任务分配给新节点。监控代理、防病毒扫描器或其他需要在集群中每个节点上运行的容器类型,都是全局服务的理想候选者。

下图显示了灰色表示的三服务副本和黑色表示的全局服务。

Global vs replicated services

了解更多

  • 阅读有关 Swarm 模式如何 节点 工作的内容。
  • Learn how PKI works in Swarm mode.