Deploy do primeiro app
Suba uma aplicação Node.js com banco Postgres em 50 linhas de YAML. Inclui health check, rolling deploy e rollback.
Um deploy no HeroCtl é um arquivo YAML enviado ao cluster. O cluster decide onde rodar, quando atualizar e como reagir se algo quebra. Você só descreve o desejo.
Anatomia do job spec
Um job define um serviço completo: imagem, réplicas, recursos, ingresso, segredos. Tudo em um arquivo só. Cinco blocos importam:
| Bloco | Função |
|---|---|
meta | nome, versão, tags |
task | imagem, comando, env, recursos |
count | quantas réplicas |
health | como saber se está vivo |
ingress | domínio público e TLS |
50 linhas cobrem 90% dos casos.
Exemplo completo: web Node.js + Postgres
Vamos subir uma API Node.js com 2 réplicas e um Postgres adjacente. Crie o arquivo app.yaml:
job: api-vendas
version: 1
tasks:
- name: postgres
image: postgres:16-alpine
count: 1
resources:
cpu: 500
memory: 512
env:
POSTGRES_DB: vendas
POSTGRES_USER: app
secrets:
POSTGRES_PASSWORD: db-password
volumes:
- name: pgdata
path: /var/lib/postgresql/data
size: 10Gi
health:
tcp: 5432
interval: 10s
timeout: 3s
- name: web
image: minhaempresa/api-vendas:1.4.2
count: 2
resources:
cpu: 250
memory: 256
env:
DATABASE_URL: postgres://app@postgres.local:5432/vendas
NODE_ENV: production
secrets:
DATABASE_PASSWORD: db-password
JWT_SECRET: jwt-secret
health:
http: /healthz
port: 3000
interval: 5s
healthy_after: 2
unhealthy_after: 3
ingress:
host: api.minhaempresa.com
port: 3000
tls: true
Cinquenta linhas, um app inteiro com banco persistente, segredos injetados, health check e domínio com certificado.
Nota: segredos referenciados (
db-password,jwt-secret) precisam existir antes. Crie comheroctl secret create db-password --value '...'. Veja Referência do CLI para todos os comandos.
Submeter o job
Com o arquivo pronto, um comando envia o desejo ao cluster:
heroctl job submit app.yaml
Saída:
job: api-vendas
version: 1 (new)
tasks: 2 (postgres, web)
plan:
+ create alloc postgres-a1b2 on node-2
+ create alloc web-c3d4 on node-1
+ create alloc web-e5f6 on node-3
deploy: rolling
status: accepted (id: dep-2026-04-26-001)
O cluster planejou onde cada contêiner vai rodar e iniciou a execução em segundo plano. O comando volta em 1–2 segundos. Não espera o app subir.
Acompanhar o progresso
Para ver o que está acontecendo de fato:
heroctl alloc list --job api-vendas
ALLOC TASK NODE STATUS HEALTH AGE
postgres-a1b2 postgres node-2 running healthy 12s
web-c3d4 web node-1 running starting 8s
web-e5f6 web node-3 running healthy 8s
Os estados que importam:
| Status | Significa |
|---|---|
pending | aguardando recursos no nó |
running + starting | contêiner subiu, health check ainda não passou |
running + healthy | recebendo tráfego |
failed | crashou. Veja logs. |
Logs em tempo real
Para ver a saída do app enquanto sobe:
heroctl logs -f --job api-vendas --task web
A flag -f segue o stream. Saia com Ctrl+C. Para um alloc específico:
heroctl logs -f --alloc web-c3d4
Logs ficam armazenados por 7 dias por padrão. Para histórico longo, integre com um destino externo (veja Observabilidade).
Health check é obrigatório
O HeroCtl não rola deploy sem health check. Não é restrição cosmética: sem ele, não há como distinguir contêiner subindo de contêiner quebrado.
Sua aplicação precisa expor um endpoint que:
- Retorna
200 OKapenas quando o app está pronto para receber tráfego. - Valida dependências reais (banco, cache, fila).
- Responde em menos de 1 segundo.
Exemplo mínimo em Node.js:
app.get('/healthz', async (req, res) => {
try {
await db.query('SELECT 1')
res.status(200).json({ ok: true })
} catch (err) {
res.status(503).json({ ok: false, error: err.message })
}
})
Atenção: um
/healthzque sempre retorna 200 é pior do que não ter. Ele esconde quebras e o deploy passa achando que está tudo bem.
Rolling deploy padrão
Sem configuração extra, atualizações são rolling. O cluster troca uma réplica por vez, espera ela ficar saudável, e só então mexe na próxima.
Defaults do rolling:
| Parâmetro | Valor | O que faz |
|---|---|---|
max_parallel | 1 | quantas réplicas atualizar ao mesmo tempo |
min_healthy_time | 10s | quanto tempo a nova precisa ficar saudável |
healthy_deadline | 300s | quanto esperar antes de considerar falha |
auto_revert | true | volta sozinho se falhar |
Para customizar, adicione um bloco update no task:
update:
max_parallel: 2
min_healthy_time: 30s
healthy_deadline: 600s
auto_revert: true
Mais paralelismo = deploy rápido + janela maior de risco. Mais tempo saudável = deploy lento + confiança maior.
Atualizar o app
Mudou código, fez build, push da imagem com tag nova. Para promover:
- Edite
app.yamlmudando a tag da imagem (1.4.2→1.4.3). - Submeta de novo:
heroctl job submit app.yaml
O cluster compara as duas versões, percebe que só a imagem do web mudou e roda rolling apenas naquele task. O Postgres continua intocado.
Acompanhe com:
heroctl deploy status dep-2026-04-26-002
# task: web
# strategy: rolling
# progress: 1/2 (50%)
# state: rolling
# next: web-e5f6 (em 8s)
Rollback
Se algo dá errado e você precisa voltar:
heroctl job revert api-vendas --version 1
O comando reaplica o spec da versão anterior, com o mesmo rolling. Em 30–60 segundos você está de volta ao estado bom conhecido. Não há "rollback de banco" — schema migrations são responsabilidade da aplicação.
Nota: versões antigas ficam guardadas indefinidamente. Liste com
heroctl job history api-vendaspara ver todas as versões e quem submeteu cada uma.
Próximos passos
- Quer entender quando rolling não basta? Veja Rolling, canary, blue-green e rainbow.
- Para todos os comandos disponíveis: Referência do CLI.