Nomad Workshop 1 - Hello World

In our getting started post we got Nomad and Consul installed and reviewed each stanza of a Nomad job specification. In this workshop we're going to deploy a 'Hello World' style app, make some changes to it's configuration, and then re-deploy it.

Feeling a little lost?
This workshop is part of a series. You can always start at the beginning.

Install the greet binary

These lessons make use of greet, a simple web server that will respond with Hello, <name> when you send it an HTTP GET request. Ensure that you've got it installed before continuing.

If you've got Go v1.17 installed and your $GOPATH in you $PATH then you should be able to go install it like so:

$ go install github.com/letsencrypt/hashicorp-lessons/greet@latest

Ensure greet is now in our $PATH.

$ which greet

Check the plan output for the hello-world job

Running the plan subcommand will help us understand what actions the Nomad
Scheduler is going to take on our behalf. Now you're probably seeing a whole lot of changes here that were not included in our job specification. This is because, in the absence of their explicit definition, Nomad will fill in some defaults for required values.

$ nomad job plan -verbose -var-file=./1_HELLO_WORLD/vars.go ./1_HELLO_WORLD/job.go
+ Job: "hello-world"
+ AllAtOnce:  "false"
+ Dispatched: "false"
+ Name:       "hello-world"
+ Namespace:  "default"
+ Priority:   "50"
+ Region:     "global"
+ Stop:       "false"
+ Type:       "service"
+ Datacenters {
  + Datacenters: "dev-general"
  }
+ Task Group: "greeter" (1 create)
  + Count: "1" (forces create)
  + RestartPolicy {
    + Attempts: "2"
    + Delay:    "15000000000"
    + Interval: "1800000000000"
    + Mode:     "fail"
    }
  + ReschedulePolicy {
    + Attempts:      "0"
    + Delay:         "30000000000"
    + DelayFunction: "exponential"
    + Interval:      "0"
    + MaxDelay:      "3600000000000"
    + Unlimited:     "true"
    }
  + EphemeralDisk {
    + Migrate: "false"
    + SizeMB:  "300"
    + Sticky:  "false"
    }
  + Update {
    + AutoPromote:      "false"
    + AutoRevert:       "false"
    + Canary:           "0"
    + HealthCheck:      "checks"
    + HealthyDeadline:  "300000000000"
    + MaxParallel:      "1"
    + MinHealthyTime:   "10000000000"
    + ProgressDeadline: "600000000000"
    }
  + Network {
      Hostname: ""
    + MBits:    "0"
      Mode:     ""
    + Static Port {
      + HostNetwork: "default"
      + Label:       "http"
      + To:          "0"
      + Value:       "1234"
      }
    }
  + Service {
    + AddressMode:       "auto"
    + EnableTagOverride: "false"
    + Name:              "hello-world-greeter"
    + Namespace:         "default"
    + OnUpdate:          "require_healthy"
    + PortLabel:         "http"
      TaskName:          ""
    + Check {
        AddressMode:            ""
        Body:                   ""
        Command:                ""
      + Expose:                 "false"
      + FailuresBeforeCritical: "0"
        GRPCService:            ""
      + GRPCUseTLS:             "false"
        InitialStatus:          ""
      + Interval:               "3000000000"
        Method:                 ""
      + Name:                   "ready-http"
      + OnUpdate:               "require_healthy"
      + Path:                   "/"
      + PortLabel:              "http"
        Protocol:               ""
      + SuccessBeforePassing:   "0"
      + TLSSkipVerify:          "false"
        TaskName:               ""
      + Timeout:                "2000000000"
      + Type:                   "http"
      }
    + Check {
        AddressMode:            ""
        Body:                   ""
        Command:                ""
      + Expose:                 "false"
      + FailuresBeforeCritical: "0"
        GRPCService:            ""
      + GRPCUseTLS:             "false"
        InitialStatus:          ""
      + Interval:               "3000000000"
        Method:                 ""
      + Name:                   "ready-tcp"
      + OnUpdate:               "require_healthy"
        Path:                   ""
      + PortLabel:              "http"
        Protocol:               ""
      + SuccessBeforePassing:   "0"
      + TLSSkipVerify:          "false"
        TaskName:               ""
      + Timeout:                "2000000000"
      + Type:                   "tcp"
      }
    }
  + Task: "greet" (forces create)
    + Driver:        "raw_exec"
    + KillTimeout:   "5000000000"
    + Leader:        "false"
    + ShutdownDelay: "0"
    + Config {
      + args[0]: "-c"
      + args[1]: "${NOMAD_ALLOC_DIR}/config.yml"
      + command: "greet"
      }
    + Resources {
      + CPU:         "100"
      + Cores:       "0"
      + DiskMB:      "0"
      + IOPS:        "0"
      + MemoryMB:    "300"
      + MemoryMaxMB: "0"
      }
    + LogConfig {
      + MaxFileSizeMB: "10"
      + MaxFiles:      "10"
      }
    + Template {
      + ChangeMode:   "restart"
        ChangeSignal: ""
      + DestPath:     "${NOMAD_ALLOC_DIR}/config.yml"
      + EmbeddedTmpl: "---\nname: \"Samantha\"\nport: 1234\n\n"
      + Envvars:      "false"
      + LeftDelim:    "{{"
      + Perms:        "0644"
      + RightDelim:   "}}"
        SourcePath:   ""
      + Splay:        "5000000000"
      + VaultGrace:   "0"
      }

Scheduler dry-run:
- All tasks successfully allocated.

Run the hello-world job

We expect that running our job should succeed because the plan output above stated that all of our tasks would be successfully allocated. Let's find out!

$ nomad job run -verbose -var-file=./1_HELLO_WORLD/vars.go ./1_HELLO_WORLD/job.go

Visit the the greeter URL in your browser

  1. Open http://localhost:1234
  2. You should see:
    Hello, Samantha
    

For our first change, let's make it greet you, instead of me

Edit the value of name in 1_HELLO_WORLD/vars.go:

---
name: "YOUR NAME"
port: 1234

Check the plan output for the hello-world job

$ nomad job plan -verbose -var-file=./1_HELLO_WORLD/vars.go ./1_HELLO_WORLD/job.go
+/- Job: "hello-world"
+/- Task Group: "greeter" (1 create/destroy update)
  +/- Task: "greet" (forces create/destroy update)
    +/- Template {
          ChangeMode:   "restart"
          ChangeSignal: ""
          DestPath:     "${NOMAD_ALLOC_DIR}/config.yml"
      +/- EmbeddedTmpl: "---\nname: \"Samantha\"\nport: 1234\n\n" => "---\nname: \"YOUR NAME\"\nport: 1234\n\n"
          Envvars:      "false"
          LeftDelim:    "{{"
          Perms:        "0644"
          RightDelim:   "}}"
          SourcePath:   ""
          Splay:        "5000000000"
          VaultGrace:   "0"
        }

Scheduler dry-run:
- All tasks successfully allocated.

Looks like it's going to work out just fine!

Deploy our updated hello-world job

$ nomad job run -verbose -var-file=./1_HELLO_WORLD/vars.go ./1_HELLO_WORLD/job.go

Visit the the greeter URL in your browser

  1. Open http://localhost:1234
  2. You should see:
    Hello, YOUR NAME
    

Ready to scale our job?

Continue on to Nomad Workshop 2 - Scaling Allocations.

Show Comments