HashiCorp Nomad: Orquestração Simples de Contentores e VMs
O HashiCorp Nomad é um orquestrador de cargas de trabalho que corre contentores Docker, máquinas virtuais e processos isolados usando um único binário. Ao contrário do Kubernetes, não precisa de etcd, kubelet, API server nem de dezenas de componentes. Instala-se num minuto, consome poucos recursos e é ideal para infraestruturas de pequena e média dimensão.
Neste artigo
1. Introdução ao Nomad
O Nomad é um scheduler de cargas de trabalho desenvolvido pela HashiCorp. Em vez de orquestrar apenas containers Docker como o Kubernetes, o Nomad trata contentores, VMs (QEMU/KVM), processos Java (JVM), e aplicações nativas (exec) com a mesma API. Um ficheiro de job descreve o que correr, e o Nomad encontra o nó adequado.
A arquitectura é simples: um cluster tem nós servidor (consenso via Raft) e nós cliente (executam as tarefas). Um único binário nomad faz as duas funções — basta mudar a configuração. Não há componentes separados como kubelet, etcd, scheduler ou API server.
ℹ Informação
O Nomad usa um único binário para cliente e servidor — sem componentes separados como Kubernetes (kubelet, etcd, etc.).
Comparado ao Kubernetes, o Nomad oferece menos funcionalidades nativas mas compensa com simplicidade operacional. Não tem Ingress controller nativo, nem descoberta de serviços automática sem Consul, nem escalonamento automático de pods. Para equipas pequenas que precisam de orquestrar cargas mistas (contentores + VMs + processos), o Nomad é uma alternativa pragmática.
| Característica | Nomad | Kubernetes |
|---|---|---|
| Binário único | Sim | Não (vários componentes) |
| Containers Docker | Sim | Sim |
| VMs e processos isolados | Sim (nativo) | Não (addons) |
| Service discovery | Via Consul | Nativo (kube-dns) |
| Service mesh | Via Consul Connect | Via Istio/Linkerd |
| Gestão de segredos | Via Vault | Sealed secrets/External |
| Complexidade operacional | Baixa | Alta |
2. Instalação
A instalação do Nomad resume-se a descarregar um binário e criar um ficheiro de configuração. Não há pré-requisitos pesados — apenas um sistema Linux com permissões de root.
# Instalar Nomad
wget https://releases.hashicorp.com/nomad/1.7.0/nomad_1.7.0_linux_amd64.zip
unzip nomad_1.7.0_linux_amd64.zip
sudo mv nomad /usr/local/bin/
nomad version
Para um nó servidor, criar o ficheiro de configuração em /etc/nomad.d/nomad.hcl:
# /etc/nomad.d/nomad.hcl
data_dir = "/opt/nomad/data"
server {
enabled = true
bootstrap_expect = 3
}
Para um nó cliente, a configuração inclui a interface de rede e o directório de dados:
# /etc/nomad.d/client.hcl
data_dir = "/opt/nomad/data"
client {
enabled = true
}
plugin "docker" {
config {
allow_privileged = true
}
}
Iniciar o serviço com systemd:
# Criar serviço systemd
sudo tee /etc/systemd/system/nomad.service > /dev/null << 'EOF'
[Unit]
Description=Nomad
After=network-online.target
[Service]
ExecStart=/usr/local/bin/nomad agent -config /etc/nomad.d
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable nomad
sudo systemctl start nomad
# Verificar estado
nomad node status
nomad server members
3. Jobs e Task Groups
No Nomad, tudo começa com um job. Um job contém task groups, e cada task group contém tasks. O grupo de tarefas é a unidade de agendamento — todas as tarefas no mesmo grupo correm no mesmo nó cliente. Isto permite agrupar aplicações que precisam de co-localização (ex: web + sidecar de cache).
# example.nomad
job "web-app" {
datacenters = ["dc1"]
group "web" {
count = 2
task "nginx" {
driver = "docker"
config {
image = "nginx:latest"
ports = ["http"]
}
resources {
cpu = 500
memory = 256
network {
port "http" { to = 80 }
}
}
}
}
}
Submeter e gerir jobs:
# Submeter job
nomad job run example.nomad
# Verificar jobs
nomad job status
# Verificar allocations
nomad alloc status
# Ver logs de uma allocation
nomad alloc logs ALLOC_ID
# Parar job
nomad job stop web-app
O campo count = 2 define quantas réplicas do grupo de tarefas devem correr. O scheduler do Nomad distribui as réplicas pelos nós disponíveis. Os recursos (CPU em MHz, memória em MB) são reservados por task, e o scheduler só coloca a task num nó com capacidade livre.
4. Docker com Nomad
O controlador Docker é o mais usado no Nomad. Permite correr containers com a mesma flexibilidade do docker run, mas com agendamento automático. O Nomad gere o ciclo de vida do contentor — se o nó cair, o Nomad reagenda o container noutro nó.
job "api-server" {
datacenters = ["dc1"]
group "api" {
count = 3
network {
port "http" { to = 8080 }
}
task "api" {
driver = "docker"
config {
image = "registry.example.com/api:v2.1"
ports = ["http"]
auth {
username = "ci-user"
password = "${NOMAD_DOCKER_AUTH}"
}
}
env {
DB_HOST = "db.service.consul"
ENV = "production"
}
resources {
cpu = 1000
memory = 512
}
}
}
}
O Nomad suporta variáveis de ambiente, volumes, mapeamentos de portas e repositórios privados. Para volumes persistentes, usar o bloco volume com CSI (Container Storage Interface):
group "api" {
volume "data" {
type = "csi"
source = "csi-volume-id"
read_only = false
}
task "api" {
driver = "docker"
volume_mount {
volume = "data"
destination = "/data"
}
}
}
5. Integração com Consul e Vault
O Nomad integra nativamente com Consul para service discovery e com Vault para gestão de segredos. Esta é uma das grandes vantagens — em Kubernetes precisarias de componentes separados, no ecossistema HashiCorp tudo funciona junto.
Consul — Descoberta de Serviços
O Consul regista automaticamente os serviços que correm no Nomad. Cada allocation publica os seus serviços no Consul, que mantém um catálogo actualizado e resolúvel via DNS (service.service.consul).
# Configurar Consul no nó cliente
# /etc/nomad.d/client.hcl
client {
enabled = true
}
consul {
address = "127.0.0.1:8500"
}
# No job, registar serviço
service {
name = "api-server"
port = "http"
check {
type = "http"
path = "/health"
interval = "10s"
timeout = "2s"
}
}
⚠ Atenção
O Nomad não tem malha de serviços nativa — usar Consul Connect ou Cilium para comunicação entre serviços.
Vault — Segredos
O Vault fornece segredos dinâmicos ao Nomad. Em vez de incorporados em ficheiros, os tokens e palavras-passe são obtidos em tempo de execução e rodados automaticamente.
# Configurar Vault no nó
vault {
enabled = true
address = "https://vault.service.consul:8200"
}
# No job, usar template com segredos
template {
data = <<EOF
{{ with secret "secret/data/api" }}
DB_PASSWORD = "{{ .Data.data.password }}"
API_KEY = "{{ .Data.data.key }}"
{{ end }}
EOF
destination = "secrets/env"
env = true
}
O Nomad escreve os segredos em ficheiros temporários no sistema de ficheiros do allocation, nunca em texto na especificação do job. Quando o allocation termina, os ficheiros são removidos.
6. Alta Disponibilidade
O Nomad usa o protocolo Raft para consenso entre servidores. Um cluster de 3 ou 5 servidores garante tolerância a falhas. Com 3 servidores, o cluster suporta a perda de 1; com 5, suporta a perda de 2.
# Configuração de servidor HA
# /etc/nomad.d/nomad.hcl
server {
enabled = true
bootstrap_expect = 3
raft_protocol = 3
}
# Adicionar nós ao cluster
nomad server join IP_DO_SERVIDOR_EXISTENTE
# Verificar quorum
nomad server members
# Saída esperada:
# Name Address Port Status Leader Protocol
# nomad1 10.0.1.10 4648 alive true 2
# nomad2 10.0.1.11 4648 alive false 2
# nomad3 10.0.1.12 4648 alive false 2
Para alta disponibilidade dos clientes, o Nomad reagenda automaticamente as allocations quando um nó cai. O processo de reconciliation detecta nós offline em segundos e move as tarefas para nós saudáveis.
| Configuração | Servidores | Falhas toleradas | Recomendado para |
|---|---|---|---|
| Desenvolvimento | 1 | 0 | Testes locais |
| Produção pequena | 3 | 1 | PME |
| Produção crítica | 5 | 2 | Alta carga |
7. Erros Comuns e Lista de Verificação
Durante a implementação de clusters Nomad, alguns erros aparecem repetidamente. Segue os mais comuns e como os resolver.
| Cenário | Causa | Solução |
|---|---|---|
| Job fica pendente | Nenhum nó com recursos | Verificar nomad node status |
| Allocation falhou | Controlador Docker em falta | Instalar Docker no nó cliente |
| Sem descoberta de serviços | Consul não configurado | Adicionar bloco consul na config |
| Segredos vazam em registos | env sem template Vault | Usar template com env=true |
| Quorum perdido | 2+ servidores em baixo | Restaurar servidores ou usar cópia de segurança Raft |
Lista de Verificação Pré-Implementação
✓ Binário nomad instalado em todos os nós
✓ Docker instalado nos nós que correm contentores
✓ Consul a correr e acessível (consul members)
✓ Vault configurado com políticas para os jobs
✓ Pelo menos 3 servidores para HA em produção
✓ Firewall abre portas 4646 (HTTP API) e 4648 (Raft/DN)
✓ Volume /opt/nomad/data com espaço suficiente
✓ Serviço systemd nomad.service activo e enabled
✓ Especificação do job testada com nomad job validate antes de submeter
O Nomad é uma alternativa pragmática ao Kubernetes para equipas que valorizam simplicidade. Com um único binário, integração nativa com Consul e Vault, e suporte para containers, VMs e processos isolados, reduz drasticamente a complexidade operacional sem sacrificar robustez.
Artigos Relacionados
- Kubernetes Auto-Hospedado: Hetzner vs AKS vs K3s para PME
- Dia 29: Kubernetes Básico no Linux — Pods, Deployments e kubectl
- OpenBao: Gestão de Segredos Código Aberto após o Vault