服务如何工作
当 Docker Engine 处于 Swarm 模式时,要部署应用程序镜像,你需要创建一个服务。服务通常是某个更大应用程序上下文中的微服务镜像。服务的示例可能包括 HTTP 服务器、数据库或任何你希望在分布式环境中运行的其他可执行程序类型。
创建服务时,你需要指定要使用的容器镜像以及在运行的容器内执行的命令。你还可以定义服务的选项,包括
- 集群将服务暴露给外部的端口
- 用于服务连接集群中其他服务的 overlay 网络
- CPU 和内存限制及预留
- 滚动更新策略
- 在集群中运行的镜像副本数量
服务、任务和容器
将服务部署到集群时,集群管理器将你的服务定义作为服务的期望状态。然后,它在集群中的节点上将服务调度为一个或多个副本任务。这些任务在集群中的节点上彼此独立运行。
例如,假设你想要在三个 HTTP 监听器实例之间进行负载均衡。下图展示了一个具有三个副本的 HTTP 监听器服务。监听器的三个实例中的每一个都是集群中的一个任务。


容器是一个隔离的进程。在 Swarm 模式模型中,每个任务恰好调用一个容器。任务类似于调度器放置容器的“槽位”。一旦容器启动,调度器就会识别任务处于运行状态。如果容器健康检查失败或终止,任务也会终止。
任务和调度
任务是集群中调度的原子单元。当你通过创建或更新服务来声明期望的服务状态时,协调器 (orchestrator) 通过调度任务来实现该期望状态。例如,你定义一个服务,指示协调器始终保持三个 HTTP 监听器实例运行。协调器通过创建三个任务来响应。每个任务都是一个槽位,调度器通过生成一个容器来填充它。容器是任务的实例化。如果一个 HTTP 监听器任务随后健康检查失败或崩溃,协调器会创建一个新的副本任务,该任务会生成一个新的容器。
任务是一种单向机制。它单调地按顺序通过一系列状态:assigned(已分配)、prepared(已准备)、running(运行中)等。如果任务失败,协调器会移除该任务及其容器,然后根据服务指定的期望状态创建一个新任务来替换它。
Docker Swarm 模式的底层逻辑是一个通用的调度器和协调器。服务和任务抽象本身并不知道它们实现的容器。假设,你可以实现其他类型的任务,例如虚拟机任务或非容器化进程任务。调度器和协调器不关心任务的类型。但是,当前版本的 Docker 只支持容器任务。
下图展示了 Swarm 模式如何接受服务创建请求并将任务调度到工作节点。


待定服务
服务的配置方式可能导致当前集群中的任何节点都无法运行其任务。在这种情况下,服务将保持 pending
(待定)状态。以下是服务可能保持 pending
状态的一些示例:
提示
如果你只是想阻止服务部署,请将服务副本数设置为 0,而不是尝试通过配置使其保持
pending
状态。
如果所有节点都已暂停或清空,并且你创建了一个服务,它将保持待定状态,直到有节点可用。实际上,第一个可用的节点将获得所有任务,因此这在生产环境中不是一个好的做法。
你可以为服务预留特定量的内存。如果集群中没有节点具有所需的内存量,服务将保持待定状态,直到有可用节点能够运行其任务。如果你指定一个非常大的值,例如 500 GB,任务将永远保持待定,除非你确实有一个节点可以满足它。
你可以对服务施加放置约束,并且这些约束可能在特定时间无法满足。
这种行为表明,你的任务的要求和配置与集群的当前状态没有紧密关联。作为集群管理员,你声明了集群的期望状态,管理器会与集群中的节点协作创建该状态。你无需对集群中的任务进行微管理。
复制服务和全局服务
服务部署有两种类型:复制服务 (replicated) 和全局服务 (global)。
对于复制服务,你指定要运行的相同任务的数量。例如,你决定部署一个具有三个副本的 HTTP 服务,每个副本提供相同的内容。
全局服务是一种在每个节点上运行一个任务的服务。没有预先指定的任务数量。每次向集群添加节点时,协调器都会创建一个任务,调度器会将任务分配给新节点。全局服务的良好候选者是监控代理、杀毒软件或其他你希望在集群中每个节点上运行的容器类型。
下图显示了灰色的三个服务副本和黑色的全局服务。

