Nomad Service Discovery

I don't know, whether it is the completion of the IBM Hashicop acquisition or just a normal gain of "visibility" of Hashicorp Nomad: Recently two "Hashicorp Nomad vs. Kubernetes" comparisons streamed through my timeline:

I know, that most probably more people know about Kubernetes than about Nomad and I understand that it it might be easier for them to get to know Nomad concepts while comparing them to Kubernetes concepts.

And both comparisons do a good job, I think. Maybe the latter is a little more comprehensive.

But both miss a Nomad feature (that they should mention): Nomad Service Discovery.

Both comparisons are quite recent – both from 2025 – I, guess. But when it comes to service discovery, they both (only) refer to Nomads Consul integration:

While this is not wrong – Nomad has a integration with Consul – I would recommend to use the "native" approach first and try Nomad Service Discovery because:

The native service discovery catalog is embedded in Nomad and requires no additional infrastructure.

The respective documentation can be found under Service Discovery in the Hashicorp developer documentation for Nomad.

It is pretty easy to define a serivce and a service check like I did here for the nomad-autoscaler service:

[...]
service {
    name = "nomad-autoscaler"
    port = "http"
    provider = "nomad"
    tags = ["${node.datacenter}"]

    check {
      type     = "http"
      path     = "/v1/health"
      interval = "3s"
      timeout  = "1s"
    }
  }
  [...]

Just choose the provider "nomad" and you're done. Your service will appear in the Nomad service catalog:

02:07:23 toens@laptop nomad-jobs ±|main ✗|→ nomad service list
Service Name       Tags
haste              [prod4]
haste-caddy        [prod4]
memcached-de-gt-2  [de-gt-2]
memcached-prod1    [prod1]
memcached-prod4    [prod4]
memcached-proxy    [prod1,prod4]
nomad-autoscaler   [prod1,prod4]
yopa               [prod1]

You can/will refer to these services in your job files. For example, I use them in the configuration template for the memcached-proxy using the "strange" go template syntax:

     template {
        data = <<EOH
pools{
    set_all = {
        {  backends = { 
            {{- range nomadService "memcached-prod1" }}
              "{{ .Address }}:{{ .Port }}"{{- end}} 
            } 
        },
        {  backends = {
            {{- range nomadService "memcached-prod4" }}
              "{{ .Address }}:{{ .Port }}"{{- end}}
           }
        },
        {  backends = {
            {{- range nomadService "memcached-de-gt-2" }}
              "{{ .Address }}:{{ .Port }}"{{- end}}
           }
        },
    } 
}
routes{
    cmap = {
        get = route_failover{
            children = "set_all",
            stats = true,
            miss = true,
            shuffle = true,
            failover_count = 2
        },
    },
    default = route_allsync{ 
            children = "set_all",
    }, 
}
            EOH           
            destination = "local/config.lua"
         } 

Thus you can skip the integration of Consul, if you just need service discovery. If you need service discovery via DNS or Consul service mesh, you have to use Consul, though (which has it's own quirks as you know, if you follow my blog).

On another note I found out, that PMM (Percona Monitoring and Management) is using (or planning to use) Nomad "to enable future extensibility and enhanced service capabilities". PMM is already a tool I really like - and now it might get even better by using Nomad to extend it to multiple nodes...