若把 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.0 于 2026-04-21 发布,之前是 2026-04-17 的 v2.0.0-rc.1 与 2026-03-19 的 v2.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 显出的并非一个泛化工作负载平台,而是一份非常鲜明的工程回答:面对真实机器上的多种工作,怎样在不丢失工作自身形状的前提下,让它们持续流动起来。
来源
- HashiCorp Nomad 架构文档 —— servers、regions、clients、region 独立性、leader 职责,以及每个 region 建议使用三台或五台 servers。
- HashiCorp Nomad job 概念文档 —— jobs 作为 desired state、jobspec,以及资源分配行为。
- HashiCorp Nomad glossary,《Task Group》—— task group 作为调度单位,必须落在同一台 client node 上,且不能拆分。
- HashiCorp Nomad 调度文档 —— jobs、nodes、allocations、evaluations、按 CPU core 配置的 workers、scheduler 类型、ranking,以及 leader 侧的 plan queue。
- HashiCorp Nomad task driver plugin 文档 —— resource isolation 与可插拔的 driver architecture。
- GitHub API,
hashicorp/nomad仓库快照 —— 本文写作时的仓库描述、stars、forks、open issues 与最近 push 时间。 - GitHub releases,
hashicorp/nomad—— 最近v2.0.0、候选版与 beta 的发布时间。 - Armon Dadgar 的 GitHub 个人页 —— 本文题图所用肖像的来源页面。
- Cloudflare 博客,《How we use HashiCorp Nomad》—— 从运维侧观察 Nomad 作为 dynamic task scheduling system 在多数据中心中的部署。