Introducing Nomad Pack!

We’re excited to announce a tech preview of a new tool we’re building for Nomad called Nomad Pack.

Nomad Pack is a templating and packaging tool used to:

  • Easily deploy popular applications to Nomad
  • Re-use common patterns across internal applications
  • Find and share job specifications with the Nomad community

More detailed information about Nomad Pack can be found in the Nomad Pack repository.

We would love any feedback you have on the tool. Please feel free to open Issues in the GitHub repository or to leave feedback on this thread.

Additionally, we have made a Nomad Pack Community Registry repository on GitHub. This is meant to be the go-to space for community-made and maintained Packs. We encourage you to provide feedback on which packs you want via GitHub issues and to submit Pull Requests with packs that you have written. To learn how to write your own packs, see the Writing Custom Packs Guide.

A Tech Preview release will be available in the coming weeks. For now, to use the tool, users will have to build it from the source code. See the Contribution Guide for details on how to make a local build.

To learn more about Nomad Pack, please see the Nomad Pack Repository and the Detailed Usage Guide.

Thanks in advance for any feedback or contributions! We’re looking forward to seeing how the community uses Nomad Pack.

6 Likes

Hello,

Loving all things Nomad, so work is much appreciated!

I have previously had a look at Levant, and I’m now evaluating nomad-pack. Last time around I ended up writing the job-templates in Terraform over Levant.

As we already use terraform in our environment, I struggling to see any benefit to replacing current terraform-templates with nomad-packs. Even the syntax is very similar.
I see the registries as a nice feature, but terraform has terraform registry serving a similar role.

If anyone has some input as to what can be gained from using nomad-pack vs just using terraform, that would be much appreciated. Would love to have a good reason to use a shiny new tool.

Example TERRAFORM version of the “hello_world” pack below.

FILE: hello_world.nomad.tpl

# =================================================================================================
# CUSTOMIZE JOB (HELPERS)
# =================================================================================================

locals {
  region      = "${lookup(OPT,"region","global")}"
  datacenters = ${jsonencode(lookup(OPT,"datacenters",["dc1"]))}
  count       = ${lookup(OPT,"count",1)}
  
  # OPT.register_service defaults to false
  service_name = "${lookup(OPT,"service_name","hello-world")}"
  service_tags = ${jsonencode(lookup(OPT,"service_tags",[]))}

  image = "${lookup(OPT,"image","traefik/whoami:latest")}"
  name  = "${lookup(OPT,"name","")}"
}

# =================================================================================================
# NOMAD JOB
# =================================================================================================

job "${~ JOB_NAME ~}" {
  region = local.region
  datacenters = local.datacenters
  type = "service"

# -------------------------------------------------------------------------------------------------
# GROUP app
# -------------------------------------------------------------------------------------------------

  group "app" {
    count = local.count

    network {
      port "http" {
        to = 80
      }
    }

%{~ if lookup(OPT,"register_service",false) ~}
# -------------------------------------------------------------------------------------------------
# CONSUL settings
# -------------------------------------------------------------------------------------------------

    service {
      name = local.service_name
      tags = local.service_tags
      port = "http"

      check {
        name     = "alive"
        type     = "http"
        path     = "/health"
        interval = "10s"
        timeout  = "2s"
      }
    }
%{~ endif ~}

    restart {
      attempts = 2
      interval = "30m"
      delay = "15s"
      mode = "fail"
    }

# -------------------------------------------------------------------------------------------------
# TASK server
# -------------------------------------------------------------------------------------------------

    task "server" {
      driver = "docker"

      env {
        WHOAMI_NAME = local.name
      }

      config {
        image = local.image
        ports = ["http"]
      }
    }
  }
}

FILE: main.tf

# Example variable defining 2 jobs using template
variable nomad_jobs {
  type = any
  default = {
    hello_world1 = {
      template = "templates/hello_world.nomad.tpl"
      required = {}
      optional = {
        register_service = true
        service_tags = [
          "traefik.enable=false",
        ]
      }
    }
    hello_world2 = {
      template = "templates/hello_world.nomad.tpl"
      required = {}
    }
  }
}

# =================================================================================================
# NOMAD JOB(S)
# =================================================================================================

resource nomad_job "JOB" {
  for_each = var.nomad_jobs

  purge_on_destroy = true

  hcl2 {
    enabled  = true
    allow_fs = false
  }

  jobspec = templatefile(each.value.template,{
    JOB_NAME = each.key
    REQ = each.value.required,
    OPT = lookup(each.value,"optional",{}),
  })
}

/* uncomment to render job-file to disk
resource local_file "JOB" {
  for_each = var.nomad_jobs
  filename = "${path.module}/rendered.${each.key}.nomad"
  content = templatefile(each.value.template,{
    JOB_NAME = each.key
    REQ = each.value.required,
    OPT = lookup(each.value,"optional",{}),
  })
}
*/
1 Like

Hey @kds-rune, sorry for the delayed reply on this! Thanks for the thoughtful question.

You’re definitely right that there’s some overlap in terms of functionality with both Levant and Terraform. I think a lot of what historically kept us from making something like Nomad Pack was that we would say “just use Terraform” as the official response to requests for something like “Helm for Nomad”.

Unfortunately, there are several downsides that have kept that answer from being sufficient. I’ll go through them here:

  • A non-trivial amount of Nomad users don’t know Terraform that well. Pulling in a module from the registry is pretty trivial for an experienced user, but for a totally new TF user it can be a big hurdle. The answer to “How do I run Jenkins on Nomad?” is ideally something like “run this one line command” and not “Go learn Terraform, figure out how to store TF state, figure out how modules work, then find and run the module”. So for that set of users, I think we needed something different.
  • HCL2 allows for more complex logic than 1, but for Packs we go the sense that people wanted even more complex logic. Using go-template should allow for more flexibility here.
  • The TF Registry, while great, has a lot of noise if you’re just looking for Nomad jobs or groups of Nomad jobs.
  • We plan to integrate Pack further into Nomad itself in both the CLI and the UI. On the CLI-side, we didn’t want to embed TF in Nomad itself or have to figure out what to do with TF state (especially when Nomad can store the state we need in it). On the UI-side, we’ll likely modify the pack & variable definitions with metadata to help get to the UX we want. That’s something that wouldn’t have been possible if we conformed to the TF spec.

So all of these add up to us making the decision to make a new tool.

But, that doesn’t answer the question of “Should I use Pack or TF right now?”. Long term, I think we’ll point everybody towards Pack, and the community/network effect will make than an obvious choice. In the short term, I think you’re fine continuing to use TF! If you have a workflow that is working for you, I’d keep running with it. I would keep checking in from time to time as the Pack registry, community, and tool will all continue to mature. At some point you might want to switch over.

Hope that helps shed some light on the differences and why you would use one over the other!

2 Likes

Hello, and thank you for taking the time to provide some insight; very useful!

You provide some valid points, and I will try integrating some packs to the pipelines to keep up to speed.

Do you see nomad-pack integrating with Waypoint down the road as well, e.g. similar to Helm for K8s, or the JobSpec for Nomad?

1 Like

+1 to Waypoint + Nomad Pack! :grinning:

1 Like