4.1. Einleitung
Dieses Kapitel bietet einen Überblick über Nomad, ein leistungsstarkes Open-Source-Tool für die Orchestrierung von Anwendungen und Arbeitslasten. Nomad wurde von HashiCorp entwickelt und hat sich zu einem beliebten Tool in der Entwickler- und DevOps-Community entwickelt. Mit Nomad können Entwickler und DevOps-Teams die Bereitstellung und Verwaltung von Anwendungen in einer Vielzahl von Umgebungen automatisieren und skalieren, sei es in der Cloud, im Rechenzentrum oder in hybriden Umgebungen.
Nomad zeichnet sich durch seine einfache Konfiguration und seinen deklarativen Charakter aus. Ähnlich wie bei Terraform, welches wir im letzten Kapitel behandelt haben, können Benutzer den gewünschten Zustand ihrer Infrastruktur oder Anwendungen in einer Konfigurationsdatei definieren. Nomad liest diese Datei und übernimmt die Aufgabe, Anwendungen auf den verfügbaren Ressourcen zu planen, zu verteilen und auszuführen. Dies vereinfacht das manuelle Deployment von Anwendungen und die Handhabung von Skalierung und Load Balancing erheblich.
4.1.1. Motivation
Als Team haben wir uns für Nomad entschieden, weil wir erkannt haben, dass die effiziente Verwaltung und Skalierung von Anwendungen in einer dynamischen und agilen Umgebung entscheidend ist. Unternehmen stehen heute vor der Herausforderung, flexibel zu sein und schnell auf sich ändernde Anforderungen reagieren zu können. Nomad ermöglicht es uns, die Bereitstellung unserer Anwendungen zu automatisieren und, ähnlich zu Terraform, die Vorteile von Infrastructure as Code zu nutzen.
4.2. Grundlagen
4.2.1. Architektur
Die Architektur von Nomad basiert auf einem dezentralen Ansatz, bei dem die Aufgabenverteilung und -ausführung in einem Cluster von Nomad-Agenten erfolgt. Nomad verwendet eine Client-Server-Architektur, bei der der Nomad-Server die Konfiguration und Planung der Workloads verwaltet, während die Nomad-Agenten die eigentliche Ausführung der Aufgaben übernehmen.
Nomad bedient sich, ähnlich wie Terraform, dem HCL-Format für die Konfigurationsdateien. Diese Konfigurationsdateien enthält Informationen über die zu verwaltenden Workloads, Ressourcenanforderungen, Skalierungsoptionen und andere relevante Einstellungen des jeweiligen Deployments. Nomad unterstützt auch die Verwendung von Vorlagedateien, um die Konfiguration zu parametrisieren und wiederholbare Implementierungen zu ermöglichen. Wie bei Terraform ist es auch hier einfach, in den Syntax der HCL reinzukommen, wie man später in der Versuchsdurchführung sehen wird.
Die Architektur von Nomad ermöglicht eine hoch skalierbare und verteilte Ausführung von Workloads. Nomad-Agenten werden auf den Ziel-Hosts installiert und kommunizieren mit dem Nomad-Server, um die aktuelle Auslastung der Ressourcen zu liefern. Der Nomad-Server analysiert die Konfiguration und plant die Aufgaben auf der Grundlage von Ressourcenanforderungen, verfügbarem Speicherplatz und anderen Kriterien. Anschließend werden die Aufgaben an die Agenten der jeweiligen “Worker-Nodes” verteilt und von diesen ausgeführt.
4.2.2. Wichtige Begriffe
Job: Ein Job in Nomad repräsentiert eine einzelne Arbeitslast oder eine Gruppe von Aufgaben, die zusammen ausgeführt werden sollen.
Task: Ein Task definiert die auszuführende Aufgabe, einschließlich des auszuführenden Befehls, der Ressourcenanforderungen und anderer Parameter.
Group: Eine Group ist eine Sammlung von Aufgaben innerhalb eines Jobs, die gemeinsame Eigenschaften oder Abhängigkeiten haben.
Allocation: Eine Allocation enthält Informationen über den Zustand der Aufgabe, die zugewiesenen Ressourcen und andere relevante Metadaten.
Scheduler: Der Scheduler berücksichtigt die Ressourcenanforderungen, Prioritäten, Ausfallsicherheit und andere Faktoren, um die optimale Verteilung der Aufgaben zu gewährleisten.
State: Der State speichert Informationen über die Allokationen, den Fortschritt der Aufgaben und andere relevante Daten.
4.2.3. Warum Nomad anstelle von Kubernetes?
Nomad und Kubernetes sind zwei beliebte Tools für die Orchestrierung von Containern und Workloads, aber es gibt Gründe, warum man Nomad wählen sollte.
Nomad zeichnet sich durch seine Einfachheit und Benutzerfreundlichkeit aus. Im Vergleich zu Kubernetes ist Nomad weniger komplex in der Einrichtung und Konfiguration geht schneller und eingängiger von statten. Nomad bietet eine leichtgewichtige und minimalistische Lösung für die Container-Orchestrierung, die sich gut für kleinere oder weniger komplexe Umgebungen eignet.
Ein weiterer Vorteil von Nomad ist seine Flexibilität. Nomad unterstützt verschiedene Arten von Workloads, darunter Container, virtuelle Maschinen und sogar nicht containerisierte Anwendungen. Nomad lässt sich außerdem nahtlos in andere HashiCorp-Tools wie Consul und Vault integrieren und bietet so eine umfassende Lösung für Service Discovery, Konfigurationsmanagement und Sicherheit.
Außerdem bietet Nomad auch eine native Integration mit Terraform an, was bedeutet, dass Sie Infrastrukturressourcen und Workload-Orchestrierung in einem einzigen Workflow definieren und verwalten können. Diese Integration erleichtert die Verwaltung und Automatisierung der gesamten Infrastruktur und fördert die Konsistenz der Infrasturktur.
Darüber hinaus verfügt Nomad über eine wachsende Community, die aktiv an der Entwicklung und Verbesserung des Tools beteiligt ist. Die Community bietet Support, Guides und Ressourcen, um bei Fragen und Probleme zu helfen.
Insgesamt ist Nomad eine attraktive Alternative zu Kubernetes, insbesondere für Unternehmen, die eine einfache, flexible und gut integrierte Lösung für die Orchestrierung ihrer Workloads suchen und man z.B. bereits auf Terraform setzt.
4.3. Nomad verwenden
Um Nomad zu nutzen, muss es auf dem System installiert werden. Die Installation von Nomad erfolgt über den Bezug der Binärdateien von der offiziellen Website https://developer.hashicorp.com/nomad/downloads.
4.3.1. Die Basics
Die Konfiguration von Nomad erfolgt über sogenannte Job-Dateien, in denen die gewünschten Arbeitslasten und deren Anforderungen definiert werden. Jeder Job definiert eine oder mehrere Aufgaben, die auf den verfügbaren Ressourcen ausgeführt werden sollen. Ein Beispiel für einen einfachen Nomad-Job könnte wie folgt aussehen:
job "example" {
datacenters = ["dc1"]
group "webapp" {
count = 3
task "app" {
driver = "docker"
config {
image = "myapp:latest"
port_map {
http = 8080
}
}
}
}
}
In diesem Beispiel wird ein Job mit dem Namen “example” definiert. Der Job besteht aus einer Gruppe mit dem Namen “webapp”, die aus drei Instanzen der Aufgabe “app” besteht. Die Aufgabe wird mit dem Docker-Treiber konfiguriert und verwendet das Docker-Image “myapp:latest”. Außerdem wird der Port 8080 auf die HTTP-Anwendung innerhalb des Containers gemappt.
4.3.1.1. Ressourcenverwaltung
Nomad bietet verschiedene Möglichkeiten zur Ressourcenverwaltung, um sicherzustellen, dass Arbeitslasten entsprechend ihren Anforderungen platziert werden. Einige wichtige Aspekte der Ressourcenverwaltung in Nomad:
Constraints: Durch die Verwendung von Constraints können spezifische Anforderungen an die Platzierung von Arbeitslasten definiert werden, z.B. die Zuordnung zu bestimmten Rechenressourcen oder der Ausschluss von bestimmten Maschinen.
Task Groups: Task Groups ermöglichen die Gruppierung von Aufgaben und definieren gemeinsame Eigenschaften wie die Anzahl der Instanzen und die Platzierungseinschränkungen.
Allocation Strategies: Nomad bietet verschiedene Allokationsstrategien, um die Verteilung von Aufgaben auf verfügbare Ressourcen zu steuern. Beispiele dafür sind bin packing, spread oder random.
4.3.1.2. Skalierbarkeit und Verfügbarkeit
Nomad wurde mit Fokus auf Skalierbarkeit und Verfügbarkeit entwickelt. Es unterstützt die horizontale Skalierung von Arbeitslasten durch die einfache Definition von Gruppen und die Anpassung der Anzahl der Instanzen. Nomad überwacht automatisch den Zustand der Arbeitslasten und kann fehlerhafte Instanzen neu starten oder auf anderen Ressourcen neu platzieren, um die Verfügbarkeit sicherzustellen.
Nomad integriert sich nahtlos mit anderen HashiCorp-Tools wie Consul und Vault, um Funktionen wie Service Discovery und Secrets Management bereitzustellen. Dadurch wird die Gesamtlösung zur Bereitstellung und Verwaltung von Anwendungen und Infrastruktur weiter verbessert.
Insgesamt bietet Nomad eine einfache und flexible Möglichkeit, die Bereitstellung und Verwaltung von Arbeitslasten in einer skalierbaren und zuverlässigen Umgebung zu automatisieren. Es ist gut geeignet für Szenarien, in denen eine leichtgewichtige Orchestrierungslösung benötigt wird und die Integration mit anderen HashiCorp-Tools von Vorteil ist.
4.3.2. Versuchsdurchführung 1
4.3.2.1. Installation von Nomad auf Control Host
Als erstes müssen wir ein neues Verzeichnis für Nomad erstellen.
$ mkdir ~/nomad
$ cd ~/nomad
Als nächstes soll Nomad heruntergeladen & extrahiert werden.
$ wget https://releases.hashicorp.com/nomad/1.5.6/nomad_1.5.6_linux_amd64.zip
$ unzip nomad_*_linux_amd64.zip
Damit Nomad nun auch außerhalb des ~/nomad-Verzeichnisses aufgerufen werden kann, müssen wir den Pfad noch zu unserem Profil hinzufügen
$ echo 'export PATH="$PATH:$HOME/nomad"' >> ~/.profile
$ source ~/.profile
Nun sollte Nomad aufrufbar sein und Output zurückgeben
$ nomad -v
Nomad v1.5.0
BuildDate 2023-03-01T10:11:42Z
Revision fc40c491cacec3d8ec3f2f98cd82b9068a50797c
4.3.3. Versuchsdurchführung 2
4.3.3.1. Infrastructure as Code
Als erstes müssen die Server-Instanzen in der Cloud erstellt werden. Diese werden via Terraform (siehe letzter Versuch) gemanaged.
resource "linode_instance" "nomad_server" {
count = 3
image = "linode/debian11"
label = "nomad-server-${count.index}"
group = "Nomad Server"
region = "eu-central"
type = "g6-standard-1"
authorized_keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDAA3Ww8kpBtsr2At9TwIxAorgv5scoEqdJ59JL1Gi6aC4dst1GsTnUTWvH7s2TR3qEPY4YgMrOSQsNLdxPHllUEmWwewpWkVE+fzqQGeG+BlyXueG/pRX7KeMBefUkKs8dmA6KD6i/OFhxfn52u/WabzrxP4JZRQC0msz7LlZMtH/ZanhkhxyQfAbXlkN5DugJAcr1mdHqaJ1juzD176EE9sH/cK3NFOoDq37KEVsWrj/tBmtwGuULd6ZCA09gg8a7owf5H4oJNOAercZA7l50CJnXzwx4S+jJAjLJW/7m9Zrj6lJMZRn2EvmX4MKgS5ixmCmPstlsrBGb+vpmaT4tFyPRZOYM2JSC7AucbhlEarzksScRvrRsmhKsemPCzBdscqz25yNjQZXcYXD9OvCI4DQrSPB/EzOCd8/DKPbm4h+aN5uZHkYIaMUefQoDEPMjkLm8XV/ZjqFi9667dDpTjT7Fqn2w5GZA1dPqvixIQaKLqPJjnIlgx1OYI4A1NNTLsxrh4jw1hgN5JcTjWp7BhnmFLdp27dlib8SxYWZxYBviSyFP+x+OG9IPzKrw8d7TfTej0pxgeauLELcCyv+FYVEg7Ou7Wm2HnGWDQRpYhoQwbl0ff7w6/3FtUB4DH7vpVig6fUwGuruZzgZcruvhPag121q2MtfmCKeqI4QKyQ== monitor@fabianhammerschmidt.de" ]
root_pass = "WeLoveTerraform"
tags = ["nomad","server"]
}
resource "linode_instance" "nomad_client" {
count = 5
image = "linode/debian11"
label = "nomad-client-${count.index}"
group = "Nomad Clients"
region = "eu-central"
type = "g6-standard-1"
authorized_keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDAA3Ww8kpBtsr2At9TwIxAorgv5scoEqdJ59JL1Gi6aC4dst1GsTnUTWvH7s2TR3qEPY4YgMrOSQsNLdxPHllUEmWwewpWkVE+fzqQGeG+BlyXueG/pRX7KeMBefUkKs8dmA6KD6i/OFhxfn52u/WabzrxP4JZRQC0msz7LlZMtH/ZanhkhxyQfAbXlkN5DugJAcr1mdHqaJ1juzD176EE9sH/cK3NFOoDq37KEVsWrj/tBmtwGuULd6ZCA09gg8a7owf5H4oJNOAercZA7l50CJnXzwx4S+jJAjLJW/7m9Zrj6lJMZRn2EvmX4MKgS5ixmCmPstlsrBGb+vpmaT4tFyPRZOYM2JSC7AucbhlEarzksScRvrRsmhKsemPCzBdscqz25yNjQZXcYXD9OvCI4DQrSPB/EzOCd8/DKPbm4h+aN5uZHkYIaMUefQoDEPMjkLm8XV/ZjqFi9667dDpTjT7Fqn2w5GZA1dPqvixIQaKLqPJjnIlgx1OYI4A1NNTLsxrh4jw1hgN5JcTjWp7BhnmFLdp27dlib8SxYWZxYBviSyFP+x+OG9IPzKrw8d7TfTej0pxgeauLELcCyv+FYVEg7Ou7Wm2HnGWDQRpYhoQwbl0ff7w6/3FtUB4DH7vpVig6fUwGuruZzgZcruvhPag121q2MtfmCKeqI4QKyQ== monitor@fabianhammerschmidt.de" ]
root_pass = "WeLoveTerraform"
tags = ["nomad","client"]
}
output.tf file:
output "server_ips" {
value = linode_instance.nomad_server[*].ip_address
description = "The IP addresses of the Nomad servers."
}
output "client_ips" {
value = linode_instance.nomad_client[*].ip_address
description = "The IP addresses of the Nomad clients."
}
output "all_ips" {
value = concat(linode_instance.nomad_server[*].ip_address, linode_instance.nomad_client[*].ip_address)
description = "The IP addresses of all the Nomad servers and clients."
}
4.3.3.2. Dynamische Erstellung des Inventories
Wir müssen aufgrund der dynamischen IPv4-Adressen der Hosts unser Inventory File genererieren, bevor wir das Ansible-Playbook ausführen können.
Das Playbook:
- name: Generate Ansible Inventory
hosts: localhost
connection: local
gather_facts: false
tasks:
- name: Write Terraform output to file
shell: terraform output -json > output.json
args:
chdir: ~/terraform/
- name: Read Terraform output from file
command: cat ~/terraform/output.json
register: terraform_output
- name: Print Terraform output
debug:
var: terraform_output.stdout | from_json
- name: Create Ansible inventory file
template:
src: ~/ansible/nomadagent/inventory_template.j2
dest: ~/ansible/nomadagent/inventory.ini
vars:
nomad_servers: "{{ (terraform_output.stdout | from_json).server_ips.value }}"
nomad_clients: "{{ (terraform_output.stdout | from_json).client_ips.value }}"
Template zum Parsen des Inventories:
# Ansible Inventory
[nomad_servers]
{% for server in nomad_servers %}
server_{{ loop.index }} ansible_host={{ server }}
{% endfor %}
[nomad_clients]
{% for client in nomad_clients %}
client_{{ loop.index }} ansible_host={{ client }}
{% endfor %}
Ein Beispiel:
# Ansible Inventory // Bogus IPs
[nomad_servers]
server_1 ansible_host=172.104.135.238
server_2 ansible_host=172.105.93.65
server_3 ansible_host=172.105.93.191
[nomad_clients]
client_1 ansible_host=172.104.135.232
client_2 ansible_host=172.105.93.92
client_3 ansible_host=139.144.78.26
client_4 ansible_host=172.105.93.123
client_5 ansible_host=172.105.93.166
4.3.3.3. Playbook zur Erstellung des Nomad Clusters
# install_nomad.yaml
---
- hosts: all
remote_user: root
vars:
ansible_ssh_private_key_file: ~/.ssh/linode
nomad_version: "1.1.4"
tasks:
- name: Aktualisiere APT-Paketlisten
apt: update_cache=yes
- name: Installiere notwendige Pakete
apt:
name: ['curl', 'unzip', 'software-properties-common','gpg','lsb-release']
state: present
- name: Füge den HashiCorp GPG-Schlüssel hinzu
apt_key:
url: https://apt.releases.hashicorp.com/gpg
state: present
- name: Füge das offizielle HashiCorp Linux Repository hinzu
apt_repository:
repo: "deb [arch=amd64] https://apt.releases.hashicorp.com {{ ansible_distribution_release }} main"
state: present
- name: Aktualisiere APT-Paketlisten
apt: update_cache=yes
- name: Installiere Nomad
apt:
name: nomad
state: present
- name: Start Nomad client service
service:
name: nomad
state: started
- name: Install ufw
apt:
name: ufw
state: present
- name: Allow Nomad communication
ufw:
rule: allow
port: '{{ item }}'
proto: '{{ "tcp" if item != 4648 else "udp" }}'
with_items:
- 4646
- 4647
- 4648
- name: Erstelle Nomad Konfigurationsverzeichnis
file:
path: /etc/nomad.d
state: directory
- name: Set leader IP
set_fact:
leader_ip: "{{ hostvars[groups['nomad_servers'][0]].ansible_host }}"
# - name: Setze Nomad Konfiguration
# copy:
# dest: /etc/nomad.d/config.hcl
# content: |
# data_dir = "/var/nomad"
# bind_addr = "0.0.0.0"
# Add your specific configuration here
- name: Configure Nomad
template:
src: ~/ansible/nomadagent/config_template.j2
dest: /etc/nomad.d/config.hcl
owner: root
group: root
mode: '0644'
- hosts: nomad_servers
remote_user: root
tasks:
- name: Install Nomad
apt:
name: nomad
state: present
update_cache: yes
- name: Create Nomad job file
copy:
content: |
job "http-echo" {
datacenters = ["dc1"]
group "example" {
count = 1
task "http-echo" {
driver = "docker"
config {
image = "hashicorp/http-echo"
args = ["-text", "Hello, World!"]
port_map {
http = 5678
}
}
resources {
network {
port "http" {
static = 5678
}
}
}
}
}
}
dest: /tmp/http-echo.nomad
- name: Run Nomad job
command: nomad job run /tmp/http-echo.nomad
- hosts: nomad_clients
remote_user: root
tasks:
- name: Install Nomad
apt:
name: nomad
state: present
update_cache: yes
- name: Start Nomad client service
service:
name: nomad
state: started
Nomad Config Template:
data_dir = "/var/nomad"
advertise {
# Use the actual IP address of the server
http = "{{ ansible_host }}:4646"
rpc = "{{ ansible_host }}:4647"
serf = "{{ ansible_host }}:4648" # <- This is the Serf advertise address
}
server {
enabled = true
bootstrap_expect = 3
server_join {
retry_join = ["{{ leader_ip }}:4648"]
}
}
4.3.4. Literaturverzeichnis
https://developer.hashicorp.com/nomad/tutorials, abgerufen am 22.05.2023
https://www.nomadproject.io/, abgerufen am 10.05.2023
https://www.devoteam.com/expert-view/is-hashicorp-nomad-a-smart-choice-for-your-container-orchestration/, abgerufen am 21.05.2023