Сервісів у вас уже з десяток, серверів — три-п’ять. Контейнери запускаються через docker compose на кожній машині окремо, деплой — це ssh і скрипт, який знає лише одна людина. Сервер падає — сервіси на ньому лежать, доки хтось не перекине їх руками.

Логічний наступний крок — оркестратор. І тут усі радять Kubernetes. Але для команди з двох-трьох розробників без окремого платформного інженера він часто стає новим джерелом болю: десяток компонентів, власні абстракції на кожен чих, оновлення кластера як окремий проєкт. Частина ресурсів скромних серверів іде на сам control plane, а не на ваші застосунки.

Для такого масштабу ми ставимо Nomad. Він закриває ту саму задачу — «запусти мені ці сервіси, стеж за ними, перезапускай і оновлюй без простою» — і при цьому влазить у голову за кілька днів.

Що ми робимо

Типова схема на 3–10 серверах (виділені OVH чи Hetzner або віртуалки на Proxmox):

  • Nomad-сервери — три вузли з консенсусом Raft. Вони планують, де що запускати. Один сервер теж працює, але тоді він — єдина точка відмови.
  • Nomad-клієнти — решта машин, на яких крутяться ваші задачі. На маленьких кластерах серверна й клієнтська роль часто живуть на одних вузлах.
  • Consul — каталог сервісів і перевірки здоров’я. Кожен сервіс реєструється сам, і інші знаходять його за ім’ям, а не за IP.
  • Traefik — вхідний проксі. Читає каталог Consul і сам будує маршрути: новий сервіс з’явився — Traefik уже знає, куди слати трафік. Сертифікати Let’s Encrypt випускає теж він.
  • Секрети — Nomad Variables для простих випадків або Vault, якщо потрібні динамічні паролі до бази, ротація й аудит.
  • Prometheus і Grafana — метрики Nomad, Consul, Traefik і самих застосунків, алерти.

Сервери створюємо через Terraform, налаштовуємо Ansible, а job-файли Nomad лежать у тому ж репозиторії інфраструктури. Так увесь кластер описаний кодом, і його можна відтворити з нуля.

Чому Nomad і як він працює

Nomad — це один бінарник. Сервер і клієнт — той самий файл, різниця лише в конфігу. Його можна оновити, просто замінивши файл і перезапустивши службу по черзі на кожному вузлі.

Задачі описуються в HCL — читається простіше, ніж стос YAML-маніфестів. Ось шматок job-файлу з 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"
    }
  }
}

Що тут відбувається: під час оновлення Nomad спершу піднімає одну нову копію поруч зі старими. Якщо перевірка /health проходить, копії замінюються по одній. Якщо нова версія не стартує — Nomad сам повертає попередню. Ніхто не прокидається вночі, щоб робити відкат.

Окрім Docker, Nomad вміє запускати звичайні бінарники через драйвери exec (з ізоляцією) і raw_exec (без неї). Це рятує, коли частина системи — старий Java-сервіс чи Go-бінарник, який нема сенсу пакувати в контейнер.

Traefik ми зазвичай ставимо окремою службою systemd на вхідних вузлах, а не задачею всередині Nomad. Так вхід у систему не залежить від планувальника: навіть якщо кластер поводиться дивно, проксі живий і віддає те, що може.

Деплой із GitLab CI — це збірка образу і nomad job run з тегом нового образу. Перед цим nomad job plan показує, що саме зміниться. Токен CI має права лише на свій namespace, а не на весь кластер.

Компроміси, про які варто знати

Екосистема менша. Для Kubernetes є Helm-чарт майже на все — від Redis до повного стека моніторингу. Для Nomad такі речі часто пишемо самі. Job-файл на 40 рядків — не трагедія, але це робота.

Ліцензія. У 2023 році HashiCorp перевела Nomad, Consul, Vault і Terraform з MPL на BSL. Для запуску у власній інфраструктурі це зазвичай нічого не змінює. Обмеження стосуються тих, хто хоче продавати конкурентний продукт на їхній основі. Але знати про це треба, і в нових проєктах ми розглядаємо OpenTofu замість Terraform та OpenBao замість Vault.

Коли таки потрібен Kubernetes. Якщо команда вже знає k8s, якщо ви плануєте десятки серверів і сотні сервісів, якщо потрібні оператори для баз даних чи готові чарти від постачальника — беріть Kubernetes. Для невеликого кластера є k3s: це повноцінний Kubernetes, тільки легший у встановленні. Ми чесно скажемо, коли Nomad — неправильний вибір.

І ще одне: бази даних ми зазвичай тримаємо поза оркестратором — на окремих машинах чи LXC з реплікацією й бекапами. Nomad чудово керує stateless-сервісами. Із даними краще не гратися.

Що ви отримуєте

  • Кластер Nomad + Consul із трьома серверами, що переживає втрату вузла.
  • Traefik на вході з автоматичними сертифікатами й маршрутами з каталогу Consul.
  • Job-файли для ваших сервісів у Git, з rolling або canary-деплоєм і автовідкатом.
  • Пайплайн у GitLab CI: збірка, перевірка плану, деплой.
  • Секрети в Nomad Variables або Vault, а не в .env на серверах.
  • Prometheus і Grafana з дашбордами по кластеру та алертами.
  • Код Terraform і Ansible, щоб відтворити кластер з нуля.
  • Документацію: як задеплоїти новий сервіс, як оновити кластер, що робити, коли падає вузол.
  • Доступи адміністратора — кластер ваш, а не наш.

Якщо ваші сервіси переросли docker compose, а Kubernetes здається забагато, напишіть нам. Розберемо, що у вас крутиться, і скажемо, чи підійде Nomad — або що краще взяти натомість.