Nomad — это лёгкий планировщик и оркестратор рабочих нагрузок (контейнеры, бинарники, системные службы), который отлично чувствует себя на небольших и средних кластерах облачных VDS. В паре с Consul он обеспечивает надёжный service discovery, проверки здоровья и сегментацию сервисов. В статье разберём архитектуру Nomad+Consul, развёртывание на VDS, напишем первый job, посмотрим на allocations, включим обновления без простоя и обсудим, когда Nomad практичнее Kubernetes.
Зачем Nomad на VDS и когда он выигрывает у Kubernetes
Если вашей команде нужен управляемый планировщик без высокой цены за сложность, Nomad — отличный выбор. Он проще в установке, требует меньше системных компонентов, работает с контейнерами и просто с исполняемыми файлами, а в связке с Consul закрывает discovery и health‑checks. На типичном VDS Nomad стартует быстрее и потребляет меньше памяти, чем большинство Kubernetes‑дистрибутивов, при этом оставляя контроль над топологией, обновлениями и отказоустойчивостью.
Идеальный сценарий: 3 VDS под Nomad server, 2–5 VDS под Nomad client, Consul агент на каждом узле. Этого достаточно для продовых нагрузок с высокой доступностью планировщика.
Архитектура Nomad + Consul в минимуме
Роли Nomad
- Nomad server — хранение состояния кластера (Raft), планирование, координация. Рекомендуется нечётное число узлов (3 или 5) с параметром
bootstrap_expect. - Nomad client — исполнитель задач; именно на клиентах создаются
allocations. Клиенты подключаются к серверам и тянут план задания.
Consul: service discovery и здоровье
Consul запускается агентом на каждом узле. Он публикует сервисы, поддерживает проверки здоровья, даёт DNS/API‑интерфейсы для поиска. Nomad интегрируется с Consul через секцию service в job‑описании, автоматически создавая записи и health‑checks.
Сети и порты
- Nomad:
4646/tcp(HTTP API/UI),4647/tcp(RPC),4648/tcp+udp(gossip/serf). - Consul:
8500/tcp(HTTP API/UI),8300/tcp(server RPC),8301/tcp+udp(LAN serf),8302/tcp+udp(WAN serf).
В проде ограничьте публичный доступ к HTTP/UI только через административный доступ (VPN, bastion), а RPC/serf держите в приватной сети между VDS.

Подготовка VDS
Предположим Ubuntu 22.04/24.04, root‑доступ и внутренние IP между узлами.
sudo apt update
sudo apt install -y curl gnupg2 lsb-release apt-transport-https ca-certificates
Откройте только необходимые порты. Пример с UFW:
sudo ufw default deny incoming
sudo ufw default allow outgoing
# SSH
sudo ufw allow 22/tcp
# Nomad
sudo ufw allow 4646/tcp
sudo ufw allow 4647/tcp
sudo ufw allow 4648
# Consul
sudo ufw allow 8500/tcp
sudo ufw allow 8300/tcp
sudo ufw allow 8301
sudo ufw allow 8302
sudo ufw enable
Проверьте, что внутренние адреса узлов доступны друг другу по указанным портам, а UI/HTTP не торчат в публичный интернет без необходимости. Если вы только начинаете с сетевой сегментацией для контейнеров, пригодится материал про настройку Docker и iptables/nftables.
Установка Consul и Nomad
Поставим из официального репозитория пакетов:
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update
sudo apt install -y consul nomad docker.io
Добавьте пользователя Nomad в группу Docker для драйвера docker:
sudo usermod -aG docker nomad
sudo systemctl enable --now docker
Consul: конфигурация сервера и клиента
На трёх серверных узлах создайте каталог и базовый конфиг:
sudo mkdir -p /etc/consul.d
sudo mkdir -p /var/lib/consul
sudo chown -R consul:consul /var/lib/consul
Пример /etc/consul.d/server.hcl (на каждом server‑узле поменяйте IP в retry_join и advertise_addr):
server = true
node_name = "consul-server-1"
datacenter = "dc1"
data_dir = "/var/lib/consul"
bind_addr = "0.0.0.0"
advertise_addr = "10.0.0.11"
client_addr = "127.0.0.1"
bootstrap_expect = 3
grpc_port = 8502
retry_join = ["10.0.0.11", "10.0.0.12", "10.0.0.13"]
ui_config { enabled = true }
На клиентских узлах Consul‑агент без роли сервера:
server = false
node_name = "consul-client-1"
datacenter = "dc1"
data_dir = "/var/lib/consul"
bind_addr = "0.0.0.0"
advertise_addr = "10.0.0.21"
client_addr = "127.0.0.1"
retry_join = ["10.0.0.11", "10.0.0.12", "10.0.0.13"]
Запуск и проверка:
sudo systemctl enable --now consul
consul members
Ожидаем в выводе все серверы и клиенты в статусе alive.
Nomad: конфигурация серверов
Создайте каталоги и простую конфигурацию:
sudo mkdir -p /etc/nomad.d
sudo mkdir -p /var/lib/nomad
sudo chown -R nomad:nomad /var/lib/nomad
Пример /etc/nomad.d/server.hcl (на каждом server‑узле корректируйте advertise):
datacenter = "dc1"
region = "global"
data_dir = "/var/lib/nomad"
bind_addr = "0.0.0.0"
server {
enabled = true
bootstrap_expect = 3
}
advertise {
http = "10.0.0.11:4646"
rpc = "10.0.0.11:4647"
serf = "10.0.0.11:4648"
}
consul {
address = "127.0.0.1:8500"
auto_advertise = true
server_service_name = "nomad-server"
client_service_name = "nomad-client"
}
Запустите Nomad‑серверы:
sudo systemctl enable --now nomad
nomad server members
Статус должен показать лидера и последователей. Если лидера нет — проверьте bootstrap_expect и сетевую связность.
Nomad: конфигурация клиентов
На клиентских узлах используем Docker‑драйвер. Пример /etc/nomad.d/client.hcl:
datacenter = "dc1"
region = "global"
data_dir = "/var/lib/nomad"
bind_addr = "0.0.0.0"
client {
enabled = true
network_interface = "eth0"
node_class = "general"
options = {
"docker.auth.config" = "/root/.docker/config.json"
}
}
plugin "docker" {
config {
volumes {
enabled = true
}
allow_privileged = false
}
}
consul {
address = "127.0.0.1:8500"
}
Запустите клиентов и убедитесь, что они подключились:
sudo systemctl restart nomad
nomad node status
Вы увидите список узлов с их node_class, ресурсами и состоянием.
Первый job: сервис на Nginx
Создадим простой сервис с двумя репликами и health‑check в Consul. Файл web.nomad.hcl:
job "web" {
datacenters = ["dc1"]
type = "service"
group "web" {
count = 2
network {
port "http" { to = 80 }
}
task "nginx" {
driver = "docker"
config {
image = "nginx:1.27-alpine"
ports = ["http"]
}
service {
name = "web"
port = "http"
check {
type = "http"
path = "/"
interval = "5s"
timeout = "2s"
}
}
resources {
cpu = 200
memory = 128
}
}
}
update {
max_parallel = 1
min_healthy_time = "10s"
healthy_deadline = "2m"
stagger = "30s"
}
}
Запуск и базовая проверка:
nomad job run web.nomad.hcl
nomad status web
nomad alloc status <alloc-id>
Секция service автоматически зарегистрирует сервис в Consul, а allocations покажут, где и как выполняются задачи: ID, узел, ресурсы и состояние health‑checks.
Allocations: как читать и отлаживать
Allocation — это конкретный запуск задачи на клиентском узле. При сбое Nomad создаёт новую allocation согласно политике reschedule или пересоздаёт её на другом узле по стратегии update. Основные команды:
nomad status <job>
nomad alloc status <alloc-id>
nomad alloc logs -stderr <alloc-id>
nomad alloc exec -task nginx <alloc-id> sh -c "nginx -t"
При системных ошибках смотрите journalctl -u nomad и journalctl -u consul, а также наличие ресурсов (CPU, RAM, диски) на проблемном узле.
Service discovery с Consul
В нашем примере регистрацией занимается Nomad. Для доступа приложений используйте DNS‑имя вида web.service.consul (или через локальный DNS‑форвардер). Health‑checks отражаются в Consul и влияют на балансировку, если вы используете прокси‑уровень (например, L7‑шлюз). Типовые приёмы:
- Несколько портов? Объявляйте их в секции
networkи сопоставляйте вservice. - Горизонтальное масштабирование? Меняйте
count, Nomad выполнит постепенное обновление по правиламupdate. - Разные классы узлов? Используйте
node_classиconstraint, чтобы направлять конкретные сервисы на подходящие VDS.

Канареечные и безопасные обновления
Nomad поддерживает канареечные релизы без сторонних операторов. Достаточно добавить canary и флаги авто‑промоции/отката:
update {
canary = 1
max_parallel = 1
auto_promote = true
auto_revert = true
min_healthy_time = "15s"
healthy_deadline = "3m"
}
Проверяйте метрики и логи канареек через alloc logs и health‑checks в Consul. Если канарейка не проходит, Nomad сам откатит релиз.
Размещение и ограничения: meta/constraints/affinity
Чтобы направлять задачи на нужные узлы, используйте constraint по атрибутам узла и метаданным клиента. Например, ограничим деплой на класс узлов general:
constraint {
attribute = "${node.class}"
operator = "="
value = "general"
}
Атрибуты узла (CPU архитектура, ядра, ОС) доступны через attr.*. Для мягких предпочтений пригодится affinity с весами, без жёсткой блокировки планировщика.
Хранилище и тома
Nomad предлагает host volumes и интеграции с внешними системами через CSI. Для локальных данных используйте host_volume с явным монтированием:
volume "media" {
type = "host"
read_only = false
source = "/srv/media"
}
group "app" {
volume "media" { read_only = false }
task "svc" {
driver = "docker"
config { image = "busybox:1.36" }
volume_mount {
volume = "media"
destination = "/data"
read_only = false
}
}
}
Помните о жизненном цикле: allocations эфемерны. Для состояния — внешний сторедж или отказоустойчивая СУБД, а локальные тома — только для кешей и временных данных.
Безопасность: TLS, ACL и изоляция
Минимальные практики для прод‑кластера:
- Включите TLS для Nomad и Consul: подпишите серверные/клиентские сертификаты и укажите директории в
tls‑секциях конфигов. Если нужна проверенная цепочка, оформите SSL-сертификаты GlobalSign. - Настройте ACL: в Consul — политики и токены для сервисов; в Nomad — политики для операторов/CI. Храните токены в секретах, включайте ротацию.
- Сегментируйте сеть: RPC/serf только по приватным IP VDS, UI доступен через VPN или промежуточный bastion.
- Ограничьте драйвер Docker:
allow_privileged = false, секкомп‑профили, cgroup‑лимиты CPU/RAM,no-new-privilegesв образах. Для усиления песочницы рассмотрите изоляцию контейнеров gVisor/Firecracker.
Наблюдаемость и алерты
Nomad и Consul отдают метрики и события. Начните с базового:
- Системные логи:
journalctl -u nomad -f,journalctl -u consul -f. - События задания:
nomad status <job>,nomad alloc status. - Здоровье сервисов:
consul catalog services,consul health state critical.
Далее подключайте скраппер метрик и дешборды, чтобы видеть лаги планировщика, неуспешные размещения и деградации health‑checks.
Три типичные ошибки и как их избежать
- Открытый UI в интернет. Держите
client_addrдля HTTP интерфейсов на127.0.0.1и проксируйте доступ по VPN. - Недостаточно прав Docker. Добавьте пользователя
nomadв группуdocker, проверьте сокет и права. - Сеть контейнеров. Ясно задавайте
networkи порты. Если нужен host‑network, учитывайте конфликты портов на узле.
Nomad против Kubernetes: прагматичный взгляд
Nomad выигрывает, когда важны простота, малый накладной расход и единый планировщик для разных типов задач (контейнеры, бинарники, systemd). Kubernetes даёт огромную экосистему и гибкость, но требует больше компетенций и ресурсов. На VDS с умеренными нагрузками Nomad разворачивается за часы, обновляется предсказуемо и прозрачно масштабируется. Если вы не используете сложные паттерны вроде обширных CRD, сложных CNI и сложной сетевой политики — Nomad будет эффективнее по TCO.
Практический мини‑план кластера на VDS
- 3 VDS x 2 vCPU, 4 GB RAM, SSD — роли
serverNomad/Consul. - 2–5 VDS x 2–4 vCPU, 4–8 GB RAM — роли
clientс Docker. - Приватная подсеть для RPC/serf, ограничение публичных портов фаерволом.
- Резервные копии
/var/lib/nomadи/var/lib/consul(осторожно с снапшотами Raft — делайте консистентные).
Отладка планирования
При неожиданных отказах размещения используйте объяснение планировщика:
nomad job run -check-index web.nomad.hcl
nomad plan web.nomad.hcl
nomad eval status <eval-id>
Смотрите причины отказов: несоответствие constraint, нехватка CPU/RAM/диска, конфликт портов, невалидный образ.
Чеклист перед продом
- Включён TLS и ACL в Nomad/Consul, с ротацией ключей.
- UI закрыты во внешнюю сеть, доступ только через VPN/бастион.
- Описаны
update/rescheduleстратегии в jobs, протестирован откат. - Настроены бэкапы и мониторинг критичных метрик планировщика и количества критичных health‑checks.
- Есть staging‑кластер или namespace для предварительного прогона.
Итоги
Nomad на VDS даёт производительный и прозрачный оркестратор с минимальной операционной сложностью. В связке с Consul вы получаете полноценный service discovery, health‑checks и гибкое планирование. Начните с малого: три сервера, пара клиентов, один сервис с канарейкой. Когда нагрузка и команда вырастут, масштабируйтесь горизонтально, не меняя базовый стек и привычки эксплуатации.


