Provides a minimal interface to the Nomad API, facilitating the planning and deployment of Nomad jobs.

Summary

The slomad Go module is a key component of my lab setup. This package is specifically designed for use in my lab environment, though the general approach is applicable to any Nomad cluster. The focus is on simplicity and ease of use, it generates valid Job specs from a type definition and set of defaults, also responsible for deploying those jobs to the cluster.

It’s been a great project to work on, and I’ve gone through a number of iterations trying out different file organization patterns and tools to manage the deploys. It’s tailor made to address my workflow and needs. The main goal being to have a simple easy to understand job definition, and a straightforward way to deploy those jobs to the cluster.

Details

Job Type Definition

The Job type is leaner than the official Nomad API definition, and is designed to be used as a template for generating job specs. The Job type is defined as follows:

type Job struct {
	Name            string
	Type            JobType
	Shape           TaskResource
	Target          DeployTarget
	Priv            bool
	Ports           []*Port
	Volumes         []Volume
	Args            []string
	Env             map[string]string
	User            string
	Templates       map[string]string
	GroupServices   map[string]string
	TaskServiceTags map[string][]string
}

Allowing for the following basic job definition:

var SpeedtestJob = smd.Job{
	Name:   "speedtest",
	Type:   smd.SERVICE,
	Target: smd.NODE,
	Ports:  smd.BasicPortConfig(80),
	Shape:  smd.XTINY_TASK,
}

For examples of how I define jobs with slomad, check out the registry/ directory and take a look around!

Memorable Challenges

  • In the past when I ran a multi-node cluster configuring persistent shared storage was a nightmare, hence some bespoke handling of storage volume creation and mounting. There’s still some work to be done here, but it’s much better than it was.
  • I was never quite able to get a Job spec for Traefik to generate correctly, so I did that one manually, though it’s not currently used.

Appendix

Job type definition from official Nomad go docs1:

type Job struct {
	Region           *string                 `hcl:"region,optional"`
	Namespace        *string                 `hcl:"namespace,optional"`
	ID               *string                 `hcl:"id,optional"`
	Name             *string                 `hcl:"name,optional"`
	Type             *string                 `hcl:"type,optional"`
	Priority         *int                    `hcl:"priority,optional"`
	AllAtOnce        *bool                   `mapstructure:"all_at_once" hcl:"all_at_once,optional"`
	Datacenters      []string                `hcl:"datacenters,optional"`
	NodePool         *string                 `mapstructure:"node_pool" hcl:"node_pool,optional"`
	Constraints      []*Constraint           `hcl:"constraint,block"`
	Affinities       []*Affinity             `hcl:"affinity,block"`
	TaskGroups       []*TaskGroup            `hcl:"group,block"`
	Update           *UpdateStrategy         `hcl:"update,block"`
	Multiregion      *Multiregion            `hcl:"multiregion,block"`
	Spreads          []*Spread               `hcl:"spread,block"`
	Periodic         *PeriodicConfig         `hcl:"periodic,block"`
	ParameterizedJob *ParameterizedJobConfig `hcl:"parameterized,block"`
	Reschedule       *ReschedulePolicy       `hcl:"reschedule,block"`
	Migrate          *MigrateStrategy        `hcl:"migrate,block"`
	Meta             map[string]string       `hcl:"meta,block"`
	ConsulToken      *string                 `mapstructure:"consul_token" hcl:"consul_token,optional"`
	VaultToken       *string                 `mapstructure:"vault_token" hcl:"vault_token,optional"`

	Stop                     *bool
	ParentID                 *string
	Dispatched               bool
	DispatchIdempotencyToken *string
	Payload                  []byte
	ConsulNamespace          *string `mapstructure:"consul_namespace"`
	VaultNamespace           *string `mapstructure:"vault_namespace"`
	NomadTokenID             *string `mapstructure:"nomad_token_id"`
	Status                   *string
	StatusDescription        *string
	Stable                   *bool
	Version                  *uint64
	SubmitTime               *int64
	CreateIndex              *uint64
	ModifyIndex              *uint64
	JobModifyIndex           *uint64
}