Actions in Nomad Jobs
In this tutorial you will create and run Nomad Actions in a job. Actions are commands that a job author writes, and take the same form as task config.
These actions live at Task level within a jobspec and run without variables or interactive input after execution. Like other executable commands, they may self-terminate or run until manually terminated by the running user. Nomad provides the CLI command, API, and Web UI to interact with Actions within the context of a Job or Task.
Challenge
In this tutorial, you will modify a Nomad job that runs a Redis instance and create repeatable Nomad Actions to:
- simplify common workflows to add and remove entries from the database
- monitor and report on attributes of those entries, as well as latency of the Redis instance
- modify core behaviour of the database
Prerequisites
- Nomad v1.7.0 or greater
- Nomad dev agent or Nomad cluster
- Docker installed and available as a task driver
Build the starting job file
Create a text file called redis-actions.nomad.hcl
with the following content:
This job creates a single Redis instance, with a port called "db" that Nomad dynamically assigns and a Nomad service health check in place. The task's config and template blocks start the redis server and report on current database size every 3 seconds.
Write your first Action
If you were a user with management or alloc-exec
privileges, you could add data to your Redis instance by ssh-ing into the running instance. However, this has several drawbacks:
- You might have to ssh into the instance several times to add data at different points, requiring you to remember how to do it. Or worse: another operator less familiar with the process may have to do so.
- There is no auditable record of manual additions. If you need to repeat or scale the workflow, you would have to do so manually.
- Your Nomad task may have access to Redis using managed secrets or environment variables, but you as a user may not. Passing credentials manually, either to access Redis or ssh into your Nomad instance, opens up a repeated access hole in the security of your workflow.
Instead of ssh
ing into the box and executing the redis-cli SET
command over and over again, you will commit it as an action to the jobspec's task. Add the following to the service
block of the task:
This action uses the redis-cli
command to set a key-value pair and then outputs a confirmation message.
Now, submit your job:
The job will update with a new action available. Use the Nomad CLI to execute it, supplying the job, group, task, and action name:
You should see the output described in our action to indicate the key was added:
You've just executed a command defined in the jobspec of your running Nomad job.
Simulate a repeatable workflow
An action that applies a constant state can be useful (an action that manually clears a cache, or that puts a site into maintenance mode, for example). However, for this example, simulate an action that someone might want to take many times. Instead of a constant key/value, modify the action to randomly generate strings. You can think of this action as a proxy for a real-world scenario where a persistent artifact is saved upon user sign-up, or another public-facing action.
This will add a random key/value to the database and report back. We can add a second action that differs only in that it prepends "temp_" to the key, to help illustrate further functionality:
Like our add-random-key
action, this new action might be thought of as a simulation of an application generating persistent artifacts. In the case of these temp keys, a real-world scenario might be keys to indicate user sign-up email verification. Soon, we will create a further Action that treats these random keys differently depending on their prefix.
These two actions will populate the database with random data of two different sorts. Now, create an action to view the keys we've added by appending the following code block:
Now, update your job:
If you have the Nomad Web UI running, accessing your Job page should show an Actions drop-down:
Selecting one of those actions will open a fly-out, complete with output from your selected action:
Next, append a new action block that creates a "safety valve" action to clear the temporary keys from our database. This uses our earlier add-random-key
and add-random-temporary-key
actions by differentiating between the artifacts they generated.
In a real-world scenario, for example, an action like this might filter and clear automatically-added entries, and report back on remaining keys or time taken to delete them.
You can run this job from the command line in two ways:
1: When your task is running on a single allocation, or you want to perform the action on a random allocation running your task:
2: When you want to perform the action on a specific, known allocation, first get its allocation ID:
Nomad CLI should show information about the jobspec, including the following:
Copy the ID from the Allocation displayed and run the following to perform the flush-temp-keys
action upon it:
If the action being run is not allocation dependent, use the first method. If your job hosted multiple instances of Redis and you need to clear the cache of a specific one, use the second method. In the real world, the method you chose will depend on your goal.
Actions can impact the running task
Some actions might not affect the current state of the application. For example, processing logs, reporting and sending server statistics, revoking tokens, etc. But, in this example, the action does impact the active state of the task. The Redis task has been writing its DBSIZE
to db_log.sh
and logging it every few seconds. Inspect the running job and get its allocation ID. Then, run the following:
Nomad outputs the logs for the allocation ID of the job:
Now add another action to impact a more low-level configuration option for our application. Redis lets us turn its persistence to disk on and off. Write an Action to check this and then flip it. Append the following action block:
Enabling RDB snapshotting with the above will modify the output in your application logs, too.
Nomad returns a confirmation that the action run and that saving to disk is enabled.
Access your server logs and find the lines that show Redis saving the snapshot:
Nomad Actions can impact the state and behaviour of the very task on which they're running. Keeping this in mind can help developers and platform teams separate business and operational logic in their applications.
Indefinite and self-terminating actions
All of the actions so far have been self-terminating: they execute a command that completes and signals its completion. However, Actions will wait for completion of the desired task, and the Nomad API and Web UI use websockets to facilitate this.
Add an action that runs until you manually stop it with a signal interruption, like ctrl + c
to observe the latency of the Redis instance:
Submit the job and run the action with the following:
The output should indicate the minimum, maximum, and average latency in ms for our Redis instance. Interrupting the signal or closing the websocket will end the action's execution.
Wrap-up
Find the complete Redis job with actions (with a few extras thrown in) below:
Experiment with duplicating and modifying these actions to explore the potential of an actions-based workflow in Nomad.
To further explore how Actions can be used in your workflows, consider the following:
- The examples above are mostly self-contained in that they run in isolation on a single allocation within a job with only one task group and task. Try creating a job with multiple groups and tasks whose actions can talk to one another by way of service discovery.
- Try using the GET job actions endpoint to see a list of actions available to a job and its groups and tasks
- Try writing an action that takes advantage of Nomad's environment variables: for example, the following actions are illustrative of how an operator might add shortcuts to their Nomad jobs to get a sense of system state:
Clean up
To stop your Nomad actions job, use the Nomad CLI:
The jobspec you wrote will remain on your filesystem, but the resources used by running the job will free up and Nomad will automatically garbage collect the stopped job after awhile.