Skip to content
страница целиком, в Markdown — вставьте в чат с моделью

Nomad ​

Nomad — оркестратор рабочих нагрузок Meduza. Он планирует Docker-контейнеры, управляет проверками здоровья, обрабатывает перезапуски и интегрируется с Traefik (для маршрутизации) и Consul (для конфигурации).

Основные концепции ​

Задачи, группы и задачи ​

Nomad использует трёхуровневую иерархию:

Job (например, "hub-prod")
├── Group: "backend"
│   └── Task: backend container
└── Group: "frontend"
    └── Task: frontend container
  • Job — единица работы верхнего уровня. Одна задача на сервис на окружение.
  • Group — набор задач, размещённых на одном узле. Каждая группа масштабируется независимо.
  • Task — один контейнер (драйвер Docker), работающий внутри группы.

Переменные ​

Файлы задач используют HCL-переменные для параметризации деплоев по окружениям:

hcl
variable "env" {
  description = "Environment name: prod, stage, or dev"
  type        = string
}

variable "domain" {
  description = "Public domain for the frontend"
  type        = string
}

variable "api_domain" {
  description = "Public domain for the backend API"
  type        = string
}

variable "image_tag" {
  description = "Docker image tag to deploy"
  type        = string
}

variable "backend_replicas" {
  description = "Number of backend task instances"
  type        = number
  default     = 1
}

Эти переменные передаются при деплое:

bash
nomad job run \
  -var="env=prod" \
  -var="domain=my-tool.amzhub.ai" \
  -var="api_domain=api-my-tool.amzhub.ai" \
  -var="image_tag=v1.2.3" \
  -var="backend_replicas=2" \
  hub.nomad.hcl

Структура задачи: пример Hub ​

Группа backend ​

Группа backend использует bridge-сеть с динамическим портом, маппящимся на внутренний порт контейнера 3010. Nomad автоматически выбирает доступный порт хоста, а Traefik обнаруживает его через каталог сервисов.

hcl
group "backend" {
  count = var.backend_replicas

  network {
    mode = "bridge"
    port "http" {
      to = 3010
    }
  }

  service {
    name     = "hub-${var.env}-backend"
    port     = "http"
    provider = "nomad"

    check {
      type     = "http"
      path     = "/health/live"
      interval = "10s"
      timeout  = "3s"
    }
  }

  task "backend" {
    driver = "docker"

    config {
      image = "registry.example.com/hub-backend:${var.image_tag}"
      ports = ["http"]
    }

    # Consul template block — see Consul docs for details
    template {
      data        = <<-TPL
      {{ with consulKey "hub/${var.env}/config" }}
      {{ range $key, $value := .Data | parseJSON }}
      {{ $key }}={{ $value }}
      {{ end }}
      {{ end }}
      TPL
      destination = "secrets/env.env"
      env         = true
    }

    resources {
      cpu    = 500
      memory = 512
    }
  }
}

Динамические порты

При использовании динамических портов Nomad назначает случайный доступный порт на хосте. Директива to = 3010 указывает Nomad маппить этот порт хоста на порт 3010 внутри контейнера. Это позволяет избежать конфликтов портов при запуске нескольких экземпляров или окружений на одном хосте.

Группа frontend ​

Группа frontend использует статические порты, чтобы каждое окружение имело предсказуемый, фиксированный порт. Traefik маршрутизирует публичный HTTPS-трафик на эти порты на основе заголовка Host.

hcl
group "frontend" {
  count = 1

  network {
    mode = "bridge"
    port "http" {
      static = var.env == "prod" ? 8888 : var.env == "stage" ? 8889 : 8890
      to     = 3000
    }
  }

  service {
    name     = "hub-${var.env}-frontend"
    port     = "http"
    provider = "nomad"

    tags = [
      "traefik.enable=true",
      "traefik.http.routers.hub-${var.env}-frontend.rule=Host(`${var.domain}`)",
      "traefik.http.routers.hub-${var.env}-frontend.entrypoints=websecure",
      "traefik.http.routers.hub-${var.env}-frontend.tls.certresolver=letsencrypt",
    ]

    check {
      type     = "http"
      path     = "/health"
      interval = "10s"
      timeout  = "3s"
    }
  }

  task "frontend" {
    driver = "docker"

    config {
      image = "registry.example.com/hub-frontend:${var.image_tag}"
      ports = ["http"]
    }

    resources {
      cpu    = 200
      memory = 256
    }
  }
}

Режимы сети ​

РежимОписаниеКогда использовать
bridgeКонтейнер получает собственное сетевое пространство имён. Порты маппятся с хоста в контейнер.По умолчанию для всех сервисов Meduza
hostКонтейнер разделяет сетевое пространство имён хоста напрямую.Не используется в Meduza

Все задачи Meduza используют режим bridge. Ключевое различие — между статическим и динамическим выделением портов:

Тип портаПоведениеКогда использовать
ДинамическийNomad выбирает доступный порт хоста при планированииБэкенд-сервисы (обнаруживаются через каталог сервисов)
СтатическийВы указываете точный порт хостаФронтенд-сервисы (Traefik требуется стабильный upstream)

Проверки здоровья ​

Каждый блок сервиса должен содержать проверку здоровья. Nomad использует их для определения готовности задачи принимать трафик и необходимости перезапуска.

hcl
check {
  type     = "http"
  path     = "/health/live"
  interval = "10s"
  timeout  = "3s"
}
  • type — http, tcp или script. HTTP-проверки предпочтительны для веб-сервисов.
  • path — эндпоинт, на который Nomad будет отправлять запросы. Должен возвращать статус 2xx.
  • interval — как часто проверять.
  • timeout — время ожидания, после которого проверка считается неудачной.

WARNING

Если проверка здоровья падает многократно, Nomad перезапустит задачу. Убедитесь, что ваш health-эндпоинт лёгкий и не зависит от внешних сервисов, если вы не хотите каскадных перезапусков.

Выделение ресурсов ​

Каждая задача объявляет свои требования к CPU и памяти. Nomad использует их для плотной упаковки задач на доступных узлах.

СервисCPU (МГц)Память (МБ)
Backend500512
Frontend200256
hcl
resources {
  cpu    = 500   # MHz
  memory = 512   # MB
}

TIP

Это жёсткие лимиты. Если контейнер превысит выделенную память, Nomad завершит его по OOM. Устанавливайте значения с запасом — отслеживайте реальное потребление через nomad alloc status и корректируйте.

Полезные команды ​

bash
# Run or update a job
nomad job run -var-file=prod.vars.hcl hub.nomad.hcl

# Check job status
nomad job status hub-prod

# View allocations for a job
nomad job allocs hub-prod

# Stream logs for an allocation
nomad alloc logs -f <alloc-id>

# View allocation resource usage
nomad alloc status <alloc-id>

# Stop a job
nomad job stop hub-prod

# Force a periodic garbage collection
nomad system gc

Дополнительное чтение ​

  • Traefik — как Traefik читает теги сервисов, показанные выше
  • Consul — как блок template инжектит конфигурацию из Consul KV

Документация по инфраструктуре