adesso Blog

Orchestrierung ist in aller Munde und aus vielen Bereichen nicht mehr wegzudenken - aber gibt es neben dem Platzhirsch Kubernetes eigentlich noch Alternativen? In diesem Blog-Beitrag werde ich mich mit dem Job Scheduler Nomad von HashiCorp beschäftigen und anhand von einfachen Beispielen beschreiben, welche Möglichkeiten dieser bietet. Anschließend gehe ich auf Deployments und weiterführende Themen wie Service Discovery und Canary Deployments ein.

Was genau ist Nomad?

Nomad ist ein kleiner Job Scheduler und Orchestrator, der im Gegensatz zu Kubernetes nicht nur Container, sondern über Plugins im Prinzip alles Mögliche verwalten kann.

Dies wird durch Task Driver realisiert, die sowohl von der Community beigesteuert werden, als auch von Haus aus enthalten sind. Neben den üblichen Verdächtigen wie Docker und Podman gibt es beispielsweise einen Task Driver speziell für Java-Anwendungen sowie Raw/Exec für alle anderen ausführbaren Anwendungen.Bevor wir nun in ein Beispiel einsteigen, wollen wir kurz auf die Konfiguration eingehen.

Konfiguration ohne YAML

Im Gegensatz zum rein deklarativen Ansatz von Kubernetes, bei dem YAML Dateien den gewünschten Zielzustand beschreiben, verwendet Nomad die hauseigene Konfigurationssprache HCL. Ursprünglich für den Einsatz bei Terraform gedacht, bringt sie Logikfunktionen und Operatoren mit, über die auch komplexe Szenarien abgebildet werden können. Daher ist ein Einsatz von weiteren Hilfsmitteln wie kustomize nicht erforderlich.

Natürlich steht mit Nomad Pack ein vergleichbares Pendant zu Helm zur Verfügung, sodass wir auch hier versionierte Artefakte erstellen können.

Hier dazu ein einfaches Beispiel zu HCL:

	
	company = "adesso"
		message = "Hallo "
		loud_message = upper(message)
		colors = [ "red", "blue" ]
		options = {
		  color: element(colors, 1),
		  amount: 100
		}
		configuration {
		  service "greeter" {
		    message = loud_message
		    options = var.override_options ? var.override_options : var.options
		  }
		}
	

NOTE: Eine vollständige Dokumentation findest du auf der offiziellen Projektseite.

Alles über Jobs

Jobs stellen in Nomad die eigentliche Arbeitseinheit dar und können über verschiedene Wege an den Server geschickt werden - dazu aber später mehr.

Grundsätzlich läuft die Einreichung eines Jobs wie folgt ab: Nach erfolgter Übermittlung findet zunächst die Evaluation statt und es werden die notwendigen Schritte erfasst und aufbereitet. Anschließend startet die Allocation. Dabei wird ein Ausführplan erstellt und eine Task Group angelegt und somit auch die Zuweisung eines Jobs zu einem aktiven Client erstellt.

NOTE: Diese Schritte sollte man zumindest einmal gehört haben, denn sie begegnen einem durchaus als Status im täglichen Umgang mit Nomad.

Wie sieht ein Job aus?

Jobs beziehungsweise die eigentlichen Job-Files bestehen aus verschiedensten Objekten (auch Stanza genannt) und lassen sich am einfachsten an konkreten Beispielen erklären.

Als groben Rahmen für die nächsten Abschnitte nutzen wir eine Quarkus-basierte Backendanwendung, mit der über eine einfache REST API Todo-Einträge erstellt und verwaltet werden können.

NOTE: Die passende OpenAPI-Spezifikation zum Beispiel findet ihr hier.

Hier jetzt unser erstes Job-File:

	
	job "todo" {
		  datacenters = ["dc1"] # <1>
		  group "web" { # <2>
		    count = 1 # <3>
		    task "todo" { # <4>
		      driver = "java" # <5>
		      config { # <6>
		        jar_path = "/Users/christoph.kappel/Projects/showcase-nomad-quarkus/target/showcase-nomad-quarkus-0.1-runner.jar"
		        jvm_options = ["-Xmx256m", "-Xms256m"]
		      }
		      resources { # <7>
		        memory = 256
		      }
		    }
		    network { # <8>
		      port "http" `
		        static = 8080
		      }
		    }
		  }
		}
	

<1> Nomad teilt Clients in Datacenter auf - ist somit Datacenter-aware.

<2> Gruppen können aus verschiedenen Tasks bestehen und werden stets auf demselben Client ausgeführt.

<3> Hier starten wir maximal eine Instanz dieser Gruppe.

<4> Ein Task stellt die kleinste Einheit in Nomad dar - vergleichbar mit einem Pod.

<5> Der Java Task Driver startet ein Jar in einer JVM-Instanz.

<6> Die meisten Task Driver können konfiguriert werden - hier setzen wir JVM-Optionen.

<7> Resource Limits können ebenfalls gesetzt werden.

<8> Und abschließend setzen wir noch den Netzwerkport - diesen brauchen wir später.

NOTE: Für die nächsten Schritte benötigst du eine laufende Nomad-Instanz - solltest du hierbei noch Probleme haben, wirf am besten einen Blick in die offizielle Anleitung.

Wie reiche ich einen Job ein?

Für die meisten Aktionen bei Nomad stehen folgende drei Wege zur Verfügung:

Mit dem Browser

Die einfachste Möglichkeit, eine Aktion durchzuführen, ist über den Browser und das mitgelieferte Webinterfaces, das direkt nach dem Start von Nomad unter folgender Adresse erreichbar ist: http://locahost:4646

Über den Knopf Run Job oben rechts gelangt man zu einem Dialog, in den man die Job-Definition direkt abschicken kann, entweder mittels HCL oder JSON.

Mittels Plan wird ein Dry-Run ausgeführt und das Ergebnis unmittelbar angezeigt:

Und abschließend startet Run dann das finale Deployment:

Über die Kommandozeile

Für die Commandline-Liebhaberinnen und -Liebhaber unter euch bietet Nomad natürlich auch hier eine CLI:

	
	$ nomad job plan jobs/todo-java.nomad
		+ Job: "todo"
		+ Task Group: "web" (1 create)
		  + Task: "todo" (forces create)
		Scheduler dry-run:
		- All tasks successfully allocated.
		$ nomad job run jobs/todo-java.nomad
		==> 2022-07-18T17:48:36+02:00: Monitoring evaluation "2c21d49b"
		    2022-07-18T17:48:36+02:00: Evaluation triggered by job "todo"
		==> 2022-07-18T17:48:37+02:00: Monitoring evaluation "2c21d49b"
		    2022-07-18T17:48:37+02:00: Evaluation within deployment: "83abca16"
		    2022-07-18T17:48:37+02:00: Allocation "d9ec1c42" created: node "d419df0b", group "web"
		    2022-07-18T17:48:37+02:00: Evaluation status changed: "pending" -> "complete"
		==> 2022-07-18T17:48:37+02:00: Evaluation "2c21d49b" finished with status "complete"
		==> 2022-07-18T17:48:37+02:00: Monitoring deployment "83abca16"
		  ✓ Deployment "83abca16" successful
		    2022-07-18T17:48:47+02:00
		    ID          = 83abca16
		    Job ID      = todo
		    Job Version = 0
		    Status      = successful
		    Description = Deployment completed successfully
		    Deployed
		    Task Group  Desired  Placed  Healthy  Unhealthy  Progress Deadline
		    web         1        1       1        0          2022-07-18T17:58:46+02:00
	

NOTE: Die verwendeten Nomad-Beispiel könnt ihr auch direkt hier finden:https://github.com/unexist/showcase-nomad-quarkus/tree/master/deployment/jobs

Über die API

Und analog zu Kubernetes können wir Nomad auch direkt über die Job API ansprechen - beispielsweise mittels curl:

	
	$ curl --request POST --data @jobs/todo-java.json http://localhost:4646/v1/jobs
		{"EvalCreateIndex":228,"EvalID":"bd809b77-e2c6-c336-c5ca-0d1c15ff6cce","Index":228,"JobModifyIndex":228,"KnownLeader":false,"LastContact":0,"NextToken":"","Warnings":""}
	

NOTE: Und die entsprechende JSON-Variante findet ihr schließlich hier: https://github.com/unexist/showcase-nomad-quarkus/blob/master/deployment/jobs/todo-java.json

Alle genannten Wege übermitteln unseren Job an Nomad und starten dann eine einzelne Instanz auf einem Client des Datacenters dc1.

Status eines Jobs überprüfen

Auskunft über den Status eines Jobs bekommt man direkt über das Webinterface, aber natürlich kann man auch in gewohnter Weise den Status des Jobs über die Commandline erfragen:

	
	$ nomad job status
		ID    Type     Priority  Status   Submit Date
		todo  service  50        running  2022-07-18T17:48:36+02:00
	

Alternativ kann man auch direkt auf den REST Service zugreifen - beispielsweise erneut via curl:

	
	$ curl -v -H "Accept: application/json" http://localhost:8080/todo
		*   Trying ::1...
		* TCP_NODELAY set
		* Connected to localhost (::1) port 8080 (#0)
		> GET /todo HTTP/1.1
		> Host: localhost:8080
		> User-Agent: curl/7.64.1
		> Accept: application/json
		`
		< HTTP/1.1 204 No Content
		<
		* Connection #0 to host localhost left intact
		* Closing connection 0
	

Jobs stoppen

Und ebenso leicht kann man den Job auch wieder stoppen:

	
	$ nomad job stop todo
		==> 2022-07-18T18:04:55+02:00: Monitoring evaluation "efe42497"
		    2022-07-18T18:04:55+02:00: Evaluation triggered by job "todo"
		==> 2022-07-18T18:04:56+02:00: Monitoring evaluation "efe42497"
		    2022-07-18T18:04:56+02:00: Evaluation within deployment: "577c3e71"
		    2022-07-18T18:04:56+02:00: Evaluation status changed: "pending" -> "complete"
		==> 2022-07-18T18:04:56+02:00: Evaluation "efe42497" finished with status "complete"
		==> 2022-07-18T18:04:56+02:00: Monitoring deployment "577c3e71"
		  ✓ Deployment "577c3e71" successful
		    2022-07-18T18:04:56+02:00
		    ID          = 577c3e71
		    Job ID      = todo
		    Job Version = 2
		    Status      = successful
		    Description = Deployment completed successfully
		    Deployed
		    Task Group  Desired  Placed  Healthy  Unhealthy  Progress Deadline
		    web         1        1       1        0          2022-07-18T18:12:24+02:00
	

Themen für Fortgeschrittene

Bisher haben wir uns mit den Grundlagen beschäftigt und können nun einfache Jobs erstellen, starten und auch wieder beenden. Darauf aufbauend werden wir uns nun im nächsten Abschnitt mit fortgeschrittenen Themen beschäftigen - schon allein, um den angestrebten Vergleich mit Kubernetes zu ermöglichen.

Scaling out

Für einfache Anwendungsfälle reicht diese eine Instanz völlig aus, aber im Arbeitsalltag stoßen wir damit natürlich schnell an eine Grenze.

Bisher haben wir mit dem Parameter count = 1 eine maximale Anzahl von einer Instanz festgelegt, und das wird sicher niemanden überraschen, aber natürlich können hier auch beliebige Werte verwendet werden - zum Beispiel 5:

	
	group "web" {
		  count = 5
		}
	

Da es grundsätzlich nicht schadet, bei allen Änderungen einen Probelauf durchzuführen, und man mit guten Gewohnheiten nicht früh genug anfangen kann - machen wir es gleich:

Dieser Fehler kommt nun völlig unerwartet, denn schließlich haben wir in unserem Job nur einen einzigen statischen Port definiert und streben hier ein Deployment von fünf Instanzen auf einem einzigen Client an. Das kann natürlich nicht funktionieren, Nomad weist uns hier folgerichtig auf dieses Problem hin.

Abhilfe schafft hier Dynamic Port Mapping, das dynamische Ports anlegt und den Instanzen dann automatisch zuweist.

Auf unserer Seite sind dazu lediglich zwei kleinere Anpassungen notwendig.Zunächst entfernen wir unseren statischen Port:

	
	 network {
		   port "http" {}
		 }
	

Und anschließend teilen wir unserer Quarkus-Anwendung noch mit, unter welchem Port sie jetzt genau erreichbar ist. Eine der einfachsten Möglichkeiten ist hier, über Umgebungsvariablen zu arbeiten:

	
	 config {
		   jar_path = "/U`ers/christoph.kappel/Projects/showcase-nomad-quarkus/target/showcase-nomad-quarkus-0.1-runner.jar"
		   jvm_options = [
		     "-Xmx256m", "-Xms256m",
		     "-Dquarkus.http.port=" # <1>
		   ]
		 }
	

<1> Hier verwenden wir eine Magic Variable von Nomad, die den passenden dynamischen Port enthält.

Lassen wir nach diesen beiden Änderungen erneut einen Dry-Run laufen, sehen wir folgendes:

Und wenn wir das Deployment schließlich über Run ausführen, sehen wir nach ein paar Sekunden unsere fünf Instanzen:

Sinnvollerweise sollten wir jetzt als nächstes irgendeine Art von Load-Balancer vor unsere fünf Instanzen schalten, damit diese erreicht werden können und damit die Last gleichmäßig verteilt werden kann.

Das bedeutet in den meisten Fällen manuelle Arbeit beim Einrichten der Ports und beim Zusammentragen der Adressen. Da es sich aber auch hier um ein für uns bereits gelöstes Problem handelt, können wir auf eine bewährte Lösung zurückgreifen.

Service Discovery

Service Discovery ist im Wesentlichen ein Katalog, in den sich Anwendungen mit ihren angebotenen Diensten eintragen und aus dem andere Anwendungen Informationen über bekannte Dienste abrufen können.

Auch hier gibt es zahlreiche Alternativen, eine der bekanntesten mit hervorragender Integration und ebenfalls von HashiCorp ist Consul. Wir könnten Consul jetzt regulär auf unserem System installieren. Zur Übung verwenden wir aber die Artifact Stanza und lassen Nomad die Anwendung direkt aus dem Internet laden und direkt über den Raw/Exec Driver ausführen:

	
	job "consul" {
		  datacenters = ["dc1"]
		  group "consul" {
		    count = 1
		    task "consul" {
		      driver = "raw_exec" # <1>
		      config {
		        command = "consul"
		        args    = ["agent", "-dev"]
		      }
		      artifact { # <2>
		        source = "https://releases.hashicorp.com/consul/1.12.3/consul_1.12.3_darwin_amd64.zip"
		      }
		    }
		  }
		}
	

<1> Zunächst benötigen wir einen neuen Task mit dem Raw/Exec-Driver.

<2> Und anschließend legen wir die Source unseres Artefakts fest.

Mittlerweile sollte das Deployment dieses Jobs ziemlich selbsterklärend sein:

	
	$ nomad job run jobs/consul.nomad
		==> 2022-07-20T12:15:24+02:00: Monitoring evaluation "eb0330c5"
		    2022-07-20T12:15:24+02:00: Evaluation triggered by job "consul"
		    2022-07-20T12:15:24+02:00: Evaluation within deployment: "c16677f8"
		    2022-07-20T12:15:24+02:00: Allocation "7d9626b8" created: node "68168a84", group "consul"
		    2022-07-20T12:15:24+02:00: Evaluation status changed: "pending" -> "complete"==> 2022-07-20T12:15:24+02:00: Evaluation "eb0330c5" finished with status "complete"
		==> 2022-07-20T12:15:24+02:00: Monitoring deployment "c16677f8"
		  ✓ Deployment "c16677f8" successful
		    2022-07-20T12:15:36+02:00
		    ID          = c16677f8
		    Job ID      = consul
		    Job Version = 0
		    Status      = successful
		    Description = Deployment completed successfully
		    Deployed
		    Task Group  Desired  Placed  Healthy  Unhealthy  Progress Deadline
		    consul      1        1       1        0          2022-07-20T12:25:34+02:00
	

Nach ein paar Sekunden sollte Consul dann gestartet und über folgende URL im Browser aufrufbar sein: http://localhost:8500:

Unter dem Reiter Services werden dann alle bekannten Dienste aufgelistet. Dazu gehören auch Consul und Nomad - leider nicht für unsere Instanzen. Zum jetzigen Zeitpunkt sind die Services unserer Instanzen für Nomad noch unbekannt und es müssen weitere Informationen nachgeliefert werden. Dies tun wir dann über die Service Stanza:

	
	service {
		  name = "todo"
		  port = "http"
		  tags = [
		    "urlprefix-/todo", # <1>
		  ]
		  check { # <2>
		    type     = "http"
		    path     = "/"
		    interval = "2s"
		    timeout  = "2s"
		  }
		}
	

<1> Nomad erlaubt es, Tagss zu vergeben, die sich in etwa so verhalten wie Label bei Kubernetes. Was es mit diesem konkreten Tag auf sich hat, erfahrt ihr im nächsten Kapitel.

<2> Über das Check Stanza legen wir fest, wie Healthchecks durchführt werden.

Danach führen wir schnell noch einen neuen Dry-Run aus, um weitere Überraschungen auszuschließen:

Hier werden noch einmal alle Parameter aufgelistet und man bekommt einen Eindruck davon, welche weiteren Konfigurationsmöglichkeiten die obige Stanzung noch mit sich bringt.

Wenn wir alles überprüft haben, können wir den Job starten und sehen hoffentlich nach kurzer Zeit neue Einträge in Consul:

NOTE: Diese Übersicht liefert uns dann auch direkt die Port Bindings unserer Instanzen.

Das ist auch geschafft. Jetzt fehlt noch Traffic auf unseren Instanzen.

Load-balancing

Für den nächsten Teil greifen wir wieder auf ein anderes Tool zurück, da wir hier den Aufgabenbereich von Nomad verlassen. Eine der einfachsten Lösungen mit ebenfalls hervorragender Integration in Nomad und Consul ist der Proxy Fabio. In gewohnter Manier können wir uns auch hier zurücklehnen und Nomad die Arbeit machen lassen:

	
	job "fabio" {
		  datacenters = ["dc1"]
		  group "fabio" {
		    count = 1
		    task "fabio" {
		      driver = "raw_exec"
		      config {
		        command = "fabio"
		        args    = ["-proxy.strategy=rr"] # <1>
		      }
		      artifact {
		        source      = "https://github.com/fabiolb/fabio/releases/download/v1.6.1/fabio-1.6.1-darwin_amd64"
		        destination = "local/fabio"
		        mode        = "file"
		      }
		    }
		  }
		}
	

<1> Hiermit legen wir Round-Robin als Verteilungsstrategie fest.

Ein kurzer Dry-Run, gefolgt von einem Deployment und schon sehen wir Fabio in der Liste der bekannten Services:

	
	$ nomad job plan jobs/fabio.nomad
		+ Job: "fabio"
		+ Task Group: "fabio" (1 create)
		  + Task: "fabio" (forces create)
		Scheduler dry-run:
		- All tasks successfully allocated.
		$ nomad job run jobs/fabio.nomad
		==> 2022-07-19T15:53:33+02:00: Monitoring evaluation "eb13753c"
		    2022-07-19T15:53:33+02:00: Evaluation triggered by job "fabio"
		    2022-07-19T15:53:33+02:00: Allocation "d923c41d" created: node "dd051c02", group "fabio"
		==> 2022-07-19T15:53:34+02:00: Monitoring evaluation "eb13753c"
		    2022-07-19T15:53:34+02:00: Evaluation within deployment: "2c0db725"
		    2022-07-19T15:53:34+02:00: Evaluation status changed: "pending" -> "complete"
		==> 2022-07-19T15:53:34+02:00: Evaluation "eb13753c" finished with status "complete"
		==> 2022-07-19T15:53:34+02:00: Monitoring deployment "2c0db725"
		  ✓ Deployment "2c0db725" successful
		    2022-07-19T15:53:46+02:00
		    ID          = 2c0db725
		    Job ID      = fabio
		    Job Version = 0
		    Status      = successful
		    Description = Deployment completed successfully
		    Deployed
		    Task Group  Desired  Placed  Healthy  Unhealthy  Progress Deadline
		    fabio       1        1       1        0          2022-07-19T16:03:45+02:00
	

Falls ihr euch jetzt fragt, weshalb alles überhaupt ohne weitere Konfiguration funktioniert: Einer der großen Vorteile von Fabio ist, Routen können über Service Tags festgelegt werden. Und schaut ihr jetzt genau hin, haben wir dies in unseren Beispielen auch schon gemacht: urlprefix-/todo

Über diesen Service Tag teilen wir Fabio mit, wie es mit Requests für die Route /todo umgehen und anhand der konfigurierten Strategie verteilen soll.

NOTE: Weitere Konfigurationsmöglichkeiten findet ihr im entsprechenden Quickstart Guide.

Update Strategien

Unsere Anwendung läuft jetzt erfolgreich auf einem einzelnen Client. Zudem haben wir die Ausfallwahrscheinlichkeit reduziert und die Lastverteilung eingeführt, indem wir unsere fünf Instanzen in einem gemeinsamen Load-Balancer-Verbund zusammengefasst haben. Soweit, so gut - aber wie können wir hier jetzt am geschicktesten Updates durchführen? Grundsätzlich stehen dafür verschiedene Ansätze zur Verfügung. Der einfachste ist natürlich, alle Instanzen in einem Rutsch zu aktualisieren.

NOTE: Hier spricht man auch von Batch-Size und diese wäre in unserem Beispiel 5.

Wählen wir diesen Ansatz, negieren wir vermutlich einige der vorhin angesprochenen Vorteile und enden im Fehlerfall möglicherweise mit einer zu geringen Anzahl an Instanzen für unseren Workload. Ein besserer Weg besteht darin, eine möglichst kleine Batch-Size zu wählen und die Instanzen rollierend - sprich nach und nach - zu aktualisieren.

Standardmäßig führt Nomad ein Rolling Update durch, allerdings lassen sich viele weitere Strategien über das Update Stanza realisieren.

	
	update {
		  canary       = 1 # <1>
		  max_parallel = 5 # <2>
		}
	

<1> Dies legt die Anzahl der Instanzen fest, die in einem Canary Update aktualisiert werden.

<2> Und hiermit wird die Batch-Size des Updates festgelegt.

Bevor wir jetzt als einfaches Beispiel ein Canary-Update durchführen, sollten wir noch einmal kurz in uns gehen und überlegen, wie wir sicherstellen können, dass ein Update den gewünschten Erfolg gebracht hat.

Ein Canary-Update mit canary = 1 bedeutet, unser Orchestrator startet eine neue Instanz und wartet anschließend auf die Bestätigung, fortzufahren. Bei der Überprüfung, ob diese neue Instanz korrekt funktioniert, stoßen wir natürlich wieder auf das bekannte Problem der zufälligen Zuweisung durch den Load-Balancer.

Vorhin hat der Trick mit dem HTTP Header hervorragend geklappt - nutzen wir dieses Vorgehen also erneut:

	
	config {
		  jar_path = "/Users/christoph.kappel/Projects/showcase-nomad-quarkus/target/showcase-nomad-quarkus-0.1-runner.jar"
		  jvm_options = [
		    "-Xmx256m", "-Xms256m",
		    "-Dquarkus.http.port=",
		    "-Dquarkus.http.header.TodoServer.value=:",
		    "-Dquarkus.http.header.TodoServer.path=/todo",
		    "-Dquarkus.http.header.TodoServer.methods=GET",
		    "-Dquarkus.http.header.TodoServerCanary.value=yes", # <1>
		    "-Dquarkus.http.header.TodoServer.path=/todo",
		    "-Dquarkus.http.header.TodoServer.methods=GET"
		  ]
		}
	

<1> Unser neuer HTTP Header für das Update.

Wir führen erneut einen Dry-Run gefolgt von einem Deployment aus:

	
	$ nomad job plan jobs/todo-java-scaled-service-header-canary.nomad
		+/- Job: "todo"
		+/- Task Group: "web" (1 canary, 5 ignore)
		  +/- Update {
		        AutoPromote:      "false"
		        AutoRevert:       "false"
		    +/- Canary:           "0" => "1"
		        HealthCheck:      "checks"
		        HealthyDeadline:  "300000000000"
		    +/- MaxParallel:      "1" => "5"
		        MinHealthyTime:   "10000000000"
		        ProgressDeadline: "600000000000"
		      }
		  +/- Task: "todo" (forces create/destroy update)
		    +/- Config {
		        jar_path:       "/Users/christoph.kappel/Projects/showcase-nomad-quarkus/target/showcase-nomad-quarkus-0.1-runner.jar"
		        jvm_options[0]: "-Xmx256m"
		        jvm_options[1]: "-Xms256m"
		        jvm_options[2]: "-Dquarkus.http.port="
		        jvm_options[3]: "-Dquarkus.http.header.TodoServer.value=:"
		        jvm_options[4]: "-Dquarkus.http.header.TodoServer.path=/todo"
		        jvm_options[5]: "-Dquarkus.http.header.TodoServer.methods=GET"
		      + jvm_options[6]: "-Dquarkus.http.header.TodoServerCanary.value=yes"
		      + jvm_options[7]: "-Dquarkus.http.header.TodoServer.path=/todo"
		      + jvm_options[8]: "-Dquarkus.http.header.TodoServer.methods=GET"
		        }
		Scheduler dry-run:
		- All tasks successfully allocated.
		$ nomad job run jobs/todo-java-scaled-service-header-canary.nomad
		==> 2022-07-20T17:11:53+02:00: Monitoring evaluation "43bdfab2"
		    2022-07-20T17:11:53+02:00: Evaluation triggered by job "todo"
		    2022-07-20T17:11:53+02:00: Allocation "4963b7fc" created: node "9293fb2f", group "web"
		==> 2022-07-20T17:11:54+02:00: Monitoring evaluation "43bdfab2"
		    2022-07-20T17:11:54+02:00: Evaluation within deployment: "a0c1e782"
		    2022-07-20T17:11:54+02:00: Allocation "4963b7fc" status changed: "pending" -> "running" (Tasks are running)
		    2022-07-20T17:11:54+02:00: Evaluation status changed: "pending" -> "complete"
		==> 2022-07-20T17:11:54+02:00: Evaluation "43bdfab2" finished with status "complete"
		==> 2022-07-20T17:11:54+02:00: Monitoring deployment "a0c1e782"
		  ⠇ Deployment "a0c1e782" in progress...
		    2022-07-21T15:12:10+02:00
		    ID          = a0c1e782
		    Job ID      = todo
		    Job Version = 6
		    Status      = running
		    Description = Deployment is running but requires manual promotion
		    Deployed
		    Task Group  Promoted  Desired  Canaries  Placed  Healthy  Unhealthy  Progress Deadline
		    web         false     5        1         1       1        0          2022-07-20T17:22:06+02:00
	

Der spannende Teil hier ist, dass Nomad das Deployment unterbricht und wir die nötige Zeit bekommen, um zu prüfen, ob unsere neue Version ordnungsgemäß funktioniert:

Haben wir uns davon ausreichend überzeugt, können wir Nomad anweisen, das Deployment fortzusetzen und auch die verbleibenden Instanzen auszurollen. Hierfür stehen uns wie bisher verschiedene Wege zur Verfügung, allerdings ist dies im Webinterface sehr anschaulich:

Mit Promote Canary setzen wir das unterbrochene Deployment dann schließlich fort:

Fazit

Nomad ist ein einfacher und flexibler Job-Scheduler, der durch die Integration weiterer Produkte praxistaugliche Lösungen für gängige Probleme liefert und sich somit in keiner Weise hinter dem großen Bruder Kubernetes verstecken muss.

Sämtliche Beispiele dieses Beitrags könnt ihr in folgendem Repository einsehen:https://github.com/unexist/showcase-nomad-quarkus

Weitere spannende Themen aus der adesso-Welt findet ihr in unseren bisher erschienenen Blog-Beiträgen.

Bild Christoph  Kappel

Autor Christoph Kappel

Christoph Kappel arbeitet als Softwarearchitekt in der LoB Cross Industries und beschäftigt sich in seiner Freizeit auch mal mit Technologie.

Diese Seite speichern. Diese Seite entfernen.