Macie już kilkanaście usług i trzy–pięć serwerów. Kontenery startują przez docker compose, na każdej maszynie osobno. Deploy to ssh i skrypt, który rozumie jedna osoba. Gdy serwer pada, usługi na nim leżą, dopóki ktoś ręcznie nie przeniesie ich gdzie indziej.

Naturalny następny krok to orkiestrator. I wszyscy od razu mówią: Kubernetes. Tylko że dla zespołu dwóch–trzech programistów bez dedykowanego inżyniera platformy to często nowe źródło problemów: kilkanaście komponentów, własne abstrakcje na wszystko, aktualizacja klastra jako osobny projekt. Część zasobów skromnych serwerów zjada sam control plane, a nie wasze aplikacje.

Przy takiej skali stawiamy Nomada. Rozwiązuje ten sam problem — „uruchom te usługi, pilnuj ich, restartuj i aktualizuj bez przestojów” — a da się go ogarnąć w kilka dni.

Co robimy

Typowy układ na 3–10 serwerach (dedyki w OVH lub Hetznerze albo maszyny wirtualne na Proxmoksie):

  • Serwery Nomada — trzy węzły z konsensusem Raft. Decydują, co gdzie ma działać. Jeden serwer też zadziała, ale wtedy jest pojedynczym punktem awarii.
  • Klienci Nomada — pozostałe maszyny, na których działają wasze zadania. W małych klastrach obie role często dzielą te same węzły.
  • Consul — katalog usług i health checki. Każda usługa sama się rejestruje, a inne znajdują ją po nazwie, nie po IP.
  • Traefik — reverse proxy na wejściu. Czyta katalog Consula i sam buduje routing: pojawia się nowa usługa, Traefik już wie, dokąd kierować ruch. Certyfikaty Let’s Encrypt też załatwia sam.
  • Sekrety — Nomad Variables w prostych przypadkach albo Vault, jeśli potrzebne są dynamiczne hasła do bazy, rotacja i audyt.
  • Prometheus i Grafana — metryki Nomada, Consula, Traefika i samych aplikacji, alerty.

Maszyny tworzymy Terraformem, konfigurujemy Ansiblem, a job-pliki Nomada trzymamy w tym samym repozytorium infrastruktury. Cały klaster jest opisany kodem i da się go odtworzyć od zera.

Dlaczego Nomad i jak to działa

Nomad to jedna binarka. Serwer i klient to ten sam plik, różni je tylko konfiguracja. Aktualizacja polega na podmianie pliku i restarcie usługi po kolei na każdym węźle.

Zadania opisuje się w HCL, co czyta się prościej niż stos manifestów YAML. Fragment job-pliku z wdrożeniem canary:

group "api" {
  count = 3

  update {
    max_parallel = 1
    canary       = 1
    auto_promote = true
    auto_revert  = true
  }

  service {
    name = "shop-api"
    port = "http"
    tags = ["traefik.enable=true"]
    check {
      type     = "http"
      path     = "/health"
      interval = "10s"
      timeout  = "2s"
    }
  }
}

Przy aktualizacji Nomad najpierw stawia jedną nową kopię obok starych. Jeśli /health odpowiada poprawnie, wymienia kopie po jednej. Jeśli nowa wersja nie wstaje, Nomad sam wraca do poprzedniej. Nikt nie musi robić rollbacku w nocy.

Poza Dockerem Nomad uruchamia też zwykłe binarki przez sterowniki exec (z izolacją) i raw_exec (bez niej). Przydaje się, gdy część systemu to stara usługa w Javie albo binarka w Go, której nie ma sensu pakować w kontener.

Traefika zwykle instalujemy jako osobną usługę systemd na węzłach brzegowych, a nie jako zadanie w Nomadzie. Wejście do systemu nie zależy wtedy od schedulera: nawet gdy klaster ma gorszy dzień, proxy działa.

Deploy z GitLab CI to build obrazu i nomad job run z nowym tagiem. Wcześniej nomad job plan pokazuje, co dokładnie się zmieni. Token CI ma uprawnienia tylko do swojego namespace’u, nie do całego klastra.

Kompromisy, o których trzeba wiedzieć

Mniejszy ekosystem. Dla Kubernetesa jest chart Helma prawie na wszystko. Dla Nomada wiele rzeczy piszemy sami. Job-plik na 40 linii to nie dramat, ale to jednak praca.

Licencja. W 2023 roku HashiCorp przeniósł Nomada, Consula, Vaulta i Terraforma z MPL na BSL. Przy użyciu we własnej infrastrukturze zwykle nic to nie zmienia — ograniczenia dotyczą tych, którzy chcą sprzedawać konkurencyjny produkt. Warto jednak o tym wiedzieć. W nowych projektach rozważamy OpenTofu zamiast Terraforma i OpenBao zamiast Vaulta.

Kiedy jednak Kubernetes. Jeśli zespół zna już k8s, planujecie dziesiątki serwerów i setki usług albo potrzebujecie operatorów do baz danych czy gotowych chartów od dostawcy — bierzcie Kubernetesa. Dla małego klastra jest k3s: pełny Kubernetes, tylko lżejszy w instalacji. Powiemy wprost, jeśli Nomad to zły wybór.

Bazy danych zwykle trzymamy poza orkiestratorem — na osobnych maszynach lub kontenerach LXC, z replikacją i backupami. Nomad świetnie radzi sobie z usługami bezstanowymi. Z danymi lepiej nie eksperymentować.

Co dostajecie

  • Klaster Nomad + Consul z trzema serwerami, który przeżyje utratę węzła.
  • Traefika na wejściu z automatycznymi certyfikatami i routingiem z katalogu Consula.
  • Job-pliki waszych usług w Gicie, z wdrożeniami rolling lub canary i automatycznym rollbackiem.
  • Pipeline w GitLab CI: build, sprawdzenie planu, deploy.
  • Sekrety w Nomad Variables lub Vaulcie, a nie w plikach .env na serwerach.
  • Prometheusa i Grafanę z dashboardami klastra i alertami.
  • Kod Terraform i Ansible do odtworzenia klastra od zera.
  • Dokumentację: jak wdrożyć nową usługę, jak zaktualizować klaster, co robić, gdy padnie węzeł.
  • Dostępy administracyjne — klaster jest wasz, nie nasz.

Jeśli wasze usługi wyrosły z docker compose, a Kubernetes wydaje się przesadą, napiszcie do nas. Przejrzymy, co u was działa, i powiemy, czy Nomad pasuje — albo co lepiej wybrać.