Are you ready to build your first Nomad job? You have a docker image and now you want to deploy to your cluster, but you need to write your first job? Look no further. This post will give you all the basic pieces needed to build your first Nomad job.
This article also exists in video format. Further all code examples in this article appear in full on Github.
Software versions
Software versions used for this post:
- Vscode
- Nomad 1.9.2(cluster, standalone or dev)
- Docker 24
File extension
So the first thing to know about Nomad files is they use the HCL, or HashiCorp Language, for the jobs. Nomad job files typically end with the .nomad extension.
basic.nomad
myfirstjob.nomad
AnotherJob.nomad
What I appreciate about HCL, vs Kubernete’s Yaml or Python, is that it is generally NOT white space sensitive. This means that when copying and pasting code is easier as you don’t have to worry about matching white space.
First job
Now that we’ve named our file, let’s name our job, choosing a good name makes your jobs easier to navigate. Be sure to chose a name that clearly identifies/distinguishes the job while being very concise.
job "myFirstJob" {
}
In order to make this job useful, we must give it a task to execute. We’ll use the docker repository davidlublink/devopsgeneration:pretend-work this docker image is very simple and based on bash and will allow us to focus on building the Nomad job and not the image or the service the image is offering.
job "myFirstJob" {
task "mytask" {
driver = "docker"
config {
image = "davidlublink/devopsgeneration:pretend-work"
}
}
This job is a fully valid Nomad job. When run in the Nomad cluster, Nomad will download the image and deploy a docker container in the Nomad cluster.
Submitting first job via CLI
You can submit the job from the command line like this:
nomad plan myFirstJob.nomad
The output will look something like this:

In the above output you can see that it will create 1 allocation of your first job.
When you are ready, you can submit your job like this:
nomad run myFirstJob.nomad
Groups
Nomad groups help to logically separate tasks, this simple job is equivalent to the previous example as Nomad will assume a group if not specified.
job "first-nomad-job-basic" {
group "service" {
task "service" {
driver = "docker"
config {
image = "davidlublink/devopsgeneration:pretend-work"
}
}
}
}
The most basic use of the group stanza is to create multiple allocations of your container. There are two ways to do this, the first way is easy and makes sense if every allocation is identical.
job "first-nomad-job-basic" {
group "service" {
count = 10
task "service" {
driver = "docker"
config {
image = "davidlublink/devopsgeneration:pretend-work"
}
}
}
}
Notice the ‘count’ keyword that has appeared, in this case we are telling the cluster to deploy 10 allocations of this task.
When you add a ‘count’ keyword, the UI will tell you how many new allocations must be created:

Here is what this might look like in the Nomad Web UI:

The second way to increase the number of allocations, but with different configurations, is to use multiple groups, each with a unique name:
job "first-nomad-job-basic" {
group "service" {
task "service" {
driver = "docker"
config {
image = "davidlublink/devopsgeneration:pretend-work"
}
}
}
group "ssh" {
task "ssh" {
driver = "docker"
config {
image = "linuxserver/openssh-server"
}
}
}
}
In this example, we are running two containers with two different images. You can combine both patterns and set ‘count’ on either, or both, groups and get multiple allocations going for the same group.
Environment Variables
Now, at this point you can build a basic Nomad job, let’s see how we can use environment variable to configure a job. When running
You may be familiar with using environment variables to configure a docker container, such as this:
docker run -it -e var1=value -e var2=value
In Nomad environment variables can easily be set using the env stanza that belongs inside of the task stanza:
job "first-nomad-job-env" {
group "service" {
task "service" {
driver = "docker"
config {
image = "davidlublink/devopsgeneration:pretend-work"
force_pull = true
}
env {
MAX_SLEEP = 3
MAX_UNIT = 10
MAX_WORK = 20
}
}
}
}
In this case the variables MAX_SLEEP, MAX_UNIT, and MAX_WORK have been set to change the behavior of the container that is deployed. Since the environment variables affect the behavior of the container, you can have multiple groups with the same docker image but different environment variables.
Templates
Templates are stanzas that appear within the task stanza, the template stanza allows to create files with content. The template stanza can be invoked multiple times.
job "first-nomad-job-templated" {
group "service" {
task "service" {
driver = "docker"
config {
image = "davidlublink/devopsgeneration:pretend-work"
force_pull = true
}
template {
data = <<EOH
THIS IS A TEMPLATE BRO!
EOH
destination = "local/myfile.txt"
}
}
}
}
In this case a file with the content ‘THIS IS A TEMPLATE BRO!’ will appear in /local/myfile.txt inside the container. Template stanzas can be used to configure the image that is running when environment variables isn’t the right solution.
Resources
The final piece for a basic nomad job is the amount of resources each allocation will need. In Nomad CPU limits are generally soft limits and memory limits hard limits. If you under provision your memory, your container may be OOM killed, if you overprovision memory you’ll waste resources on your Nomad server.
Underprovisioned CPU will lead to overloaded Nomad clients, overprovisioned CPU will lead to wasted resources.
job "first-nomad-job-resources" {
group "service" {
task "service" {
driver = "docker"
config {
image = "davidlublink/devopsgeneration:pretend-work"
}
resources {
memory = 10
cpu = 1000
}
}
}
}
In this example we have reserved 10 megabytes of memory(the minimum Nomad will allow ) for this service and 1000mhz of CPU cycles.
Conclusion
That’s all there is to writing a really basic Nomad job! There are a lot of other stanzas that can be added to your job that can influence anything from reschedule policies, to deploy strategies, to how the job reacts after a cluster outage. Mastering a basic Nomad job is really only the first step, once you’ve mastered this, get ready to explore all the other possibilities!
Leave a Reply