若把 Nomad 讲成 HashiCorp 的调度器,这个分类并没有错,错在它把架构读浅了。顺着系统真正运转的方式往里看,Nomad 更适合从一条 reconciliation loop 来理解,而并非从一个产品标签来理解。Job 负责表达 desired state,task group 划出不可拆分的边界,evaluation 把集群里的变化转换成可以被调度器消费的工作,allocation 则把“这一组任务应当落在这台 client 上运行”写成具体承诺。到了最后,leader 再用 plan queue 把并行调度限制在不会互相踩踏真实容量的范围内。[1][2][3][4]

这条读法放在 2026 年尤其有意义,因为 Nomad 仍是一套持续受压的活系统,并非一件被基础设施史回收的旧工具。截至 2026-04-24T01:39:27Z UTC,GitHub API 显示 hashicorp/nomad 仓库有 16,444 stars、2,074 forks、1,664 个 open issues,最近一次 push 时间是 2026-04-23T19:50:53Z。[6] 公开版本也在继续推进:v2.0.02026-04-21 发布,之前是 2026-04-17v2.0.0-rc.12026-03-19v2.0.0-beta.1。[7] 这些数字并不能替代架构判断,却足以说明,Nomad 的设计边界仍在真实运维表面上不断受到检验。

配图说明:题图没有使用控制台截图或 logo,而是一张真实 GitHub 肖像。这个选择是合适的,因为本文关心的并非界面装饰,而是 HashiCorp 基础设施产品线内部的系统谱系,同时也让图像使用继续停留在真实摄影这一层。[8]

真正的单元并非容器,而是 task group

Nomad 的文档把 job 写得很清楚:用户表达的是“什么应当运行”,至于“它应当落在哪儿运行”,交给系统来决定。[2] 这一点先把很多表面印象拨正了。Job 并非一份主机级放置说明,它是一份 desired-state 文档,里面有 tasks、资源要求与约束条件。[2][3] 在这份文档内部,最关键的边界是 task group。HashiCorp 在 glossary 里写得很直白:task group 是调度单位,整个 group 必须落在同一台 client node 上,而且不能被拆开。[3]

顺着这条边界回头看,Nomad 许多行为就不再显得随意。Task group 回答的是一个非常具体的运维问题:哪些进程需要共享故障、共享局部性、共享生命周期。一个 web 进程与它的 log shipper、sidecar 或辅助任务,并非在某种抽象意义上“属于同一个应用”而已;在 Nomad 里,它们可以被定义成一个不可拆分的调度整体。[3] 这时,架构关心的重点就不再是“如何运行容器”,而是“在调度器观察容量之前,先把哪一组工作划成必须共同落地的边界”。

这也是 Nomad 对混合工作负载长期保持吸引力的原因之一。GitHub 上的项目描述到今天仍强调,它能够部署 microservice、batch、containerized 与 non-containerized applications。[6] 官方 task driver 文档把这件事继续往下说明:task driver plugins 扩展 Nomad 的执行能力,为 job tasks 提供 resource isolation,而且 driver architecture 明确是 pluggable 的。[5] 换言之,系统边界落在多种执行方式的上层。核心对象依旧是 job 及其 task groups,而并非某一种狭窄的打包格式。[2][3][5][6]

Evaluation 才是这台机器真正的中枢

调度文档把 Nomad 的四个主要组成部分列得很清楚:jobs、nodes、allocations 与 evaluations。[4] 这组名词比“orchestrator”更能暴露结构。Job 表达 desired state,node 提供容量,allocation 把工作映射到真实 client,evaluation 则让这些对象在变化之中持续运转。[4]

HashiCorp 对 evaluation 的描述非常紧。只要 external state 发生变化,evaluation 就会被创建;变化既可以来自 desired state 一侧,例如新 job 被提交、旧 job 被更新或注销,也可以来自 emergent state 一侧,例如 client 失效。[4] 这里正是 Nomad 的重心。系统并不把每一次变化都留给人重新思考一遍,而是持续把集群变化翻译成一队可强制执行的 reconciliation work。于是,调度器更像一个 evaluation processor,而不只是一个一次性的放置计算器。[4]

这一点也解释了 allocation 在 Nomad 词汇里的分量。文档把 allocation 定义为“一组任务应当在某个特定 node 上运行”的声明。[4] 也就是说,allocation 是 desired state 变成操作性承诺的地方。它不只是内部记录,更是 server 向 client 下达工作、client 再把存活状态与执行状态回传上来的那层对象。[1][4]

Leader 的价值不在中央计划,而在安全的并行

Nomad 的 server 模型初看像中心化系统,可官方架构页给出的重点更细。Server 负责接收 jobs、管理 clients、计算 placements;每个 region 可以连接多个 datacenters 里的 clients;不同 regions 彼此独立,不共享 jobs、clients 或 state。[1] 在单个 region 内部,servers 组成一个共识组并选出 leader。Leader 处理 queries 与 transactions,而整个系统依旧保持 optimistic concurrency:多个 servers 并行参与调度决策,leader 负责补上必要协调,避免 clients 被 oversubscribe。[1]

调度文档把这份协调放得更具体。Nomad 默认按每个 CPU core 一个 worker 来运行 scheduling workers,再把每个 evaluation 分派给合适的 scheduler:service 负责长期服务,batch 负责批处理快速放置,system 与 sysbatch 负责需要跑在每个 node 上的作业,core 则负责内部维护。[4] 这说明并行并非偶然现象,而是设计里的显式方向。[4]

并行一旦成为默认方向,问题也立刻出现:两个 schedulers 完全或许同时盯上同一台 node。Nomad 的答案是 leader 侧的 plan queue。HashiCorp 说明,plan queue 负责管理待处理 plans、提供优先级顺序、处理并发竞争;因为系统在没有锁与预留的情况下并行运行多个 schedulers,重叠工作会造成 resource over-subscription,而 leader 可以对 plan 做部分或全部拒绝。[4] 这里是 Nomad 最值得细看的地方。Leader 的意义,并不主要在于“它是最高控制者”,而在于它让系统在大部分时间保持快速与乐观,直到真实容量冲突出现时,再以一条明确的协调边界把冲突收住。

为什么运维团队仍会选择它

最好的外部印证,并不来自仓库自述,而来自真正把它跑进生产环境的团队。Cloudflare 那篇文章把 Nomad 放在一个非常具体的位置上:它是一套 dynamic task scheduling system,被用来提升分布在多个 data centers 中的 management services 可用性。[9] 这个场景与前面的结构刚好咬合。运维团队一旦需要同时处理变化中的 desired state、异构工作负载与大规模地域分布机器,Nomad 这套模型就会显得很清楚。Job 说明哪些东西应当放在一起,evaluation 说明世界何时发生了变化,allocation 把结果压到 clients 上,leader 侧的 queue 则在并行压力下维持整体诚实。[1][3][4][9]

它的边界条件也同样明确。若团队规模很小,只维护少量长期运行容器,而且能够接受手工管理放置,那么 Nomad 未必会显出它的形状。它更适合那些已经需要认真思考 failure domains、placement constraints,以及 declarative intent 与真实 client capacity 之间区别的团队。[2][3][4] 同一套让 Nomad 保持灵活的结构,也要求团队把 grouping、资源请求与 scheduler 行为想清楚。输入若是含混的,系统本身的整洁无法代替这部分判断。

所以,把 Nomad 读成“HashiCorp 的 Kubernetes 替代品”,这句概括还是太宽了。更有用的读法,是把它看成一套围绕几道明确边界建立起来的 reconciliation system:job 负责意图,task group 负责不可拆分的放置边界,evaluation 负责变化处理,allocation 负责具体分派,leader 协调下的 plan queue 负责让 optimistic concurrency 安全落地。[1][2][3][4] 顺着这些边界回看,Nomad 显出的并非一个泛化工作负载平台,而是一份非常鲜明的工程回答:面对真实机器上的多种工作,怎样在不丢失工作自身形状的前提下,让它们持续流动起来。

来源

  1. HashiCorp Nomad 架构文档 —— servers、regions、clients、region 独立性、leader 职责,以及每个 region 建议使用三台或五台 servers。
  2. HashiCorp Nomad job 概念文档 —— jobs 作为 desired state、jobspec,以及资源分配行为。
  3. HashiCorp Nomad glossary,《Task Group》—— task group 作为调度单位,必须落在同一台 client node 上,且不能拆分。
  4. HashiCorp Nomad 调度文档 —— jobs、nodes、allocations、evaluations、按 CPU core 配置的 workers、scheduler 类型、ranking,以及 leader 侧的 plan queue。
  5. HashiCorp Nomad task driver plugin 文档 —— resource isolation 与可插拔的 driver architecture。
  6. GitHub API,hashicorp/nomad 仓库快照 —— 本文写作时的仓库描述、stars、forks、open issues 与最近 push 时间。
  7. GitHub releases,hashicorp/nomad —— 最近 v2.0.0、候选版与 beta 的发布时间。
  8. Armon Dadgar 的 GitHub 个人页 —— 本文题图所用肖像的来源页面。
  9. Cloudflare 博客,《How we use HashiCorp Nomad》—— 从运维侧观察 Nomad 作为 dynamic task scheduling system 在多数据中心中的部署。