# ADR-045 — Docker é o runtime padrão; podman é opt-in de desenvolvimento

| Campo | Valor |
|---|---|
| **Status** | Aceito (2026-10-22) |
| **Data** | 2026-10-22 |
| **Plano de origem** | `wiki/implementation/07-runtime-docker.md` (F0/T3) |
| **Relacionadas** | ADR-001, ADR-005, ADR-031, ADR-032, ADR-044 |

## Contexto

O ADR-044 tornou o **podman rootless** um runtime de desenvolvimento suportado e
`make podman-prepare` passou a gravar `CONTAINER_RUNTIME=podman` no `.env`. Com o ciclo
completo medido (6 serviços healthy, `make check` 30 OK, e2e verde) a pergunta seguinte é
objetiva: **podman também em produção?**

A resposta é não — e a consequência disso é que **dev não pode divergir de produção**. Se
produção é Docker (ADR-005: Apache do WHM como borda, `up_prod.sh`, CI com Docker), então
o padrão de dev precisa ser Docker. Manter podman como padrão criaria *drift* exatamente no
que o projeto trata como invariante (ADR-001: determinístico, previsível; regra "dev = prod"):

- o caminho de dev passaria a exercitar `userns_mode: keep-id`, `label=disable` e a exceção
  do `postgres` — configuração que produção **nunca** usa;
- bugs de permissão, SELinux e PGDATA apareceriam só no deploy (ou só em dev), nunca nos
  dois;
- o CI continuaria Docker: o artefato que o dev valida não é o ambiente que o CI valida.

## Decisão

1. **Docker é o runtime padrão e o único de produção.**
   - `tools/runtime.sh` resolve `docker` na ausência de `CONTAINER_RUNTIME`;
   - `.env.example` nasce com `CONTAINER_RUNTIME=docker`;
   - `make up`, `make check`, `make check E2E=1` e o CI rodam no Docker por padrão;
   - o deploy (`up_prod.sh`) **recusa** podman, com mensagem e falha imediata — antes de
     backup, build ou migrate.
2. **Podman é um ato explícito, opt-in, exclusivo de desenvolvimento.**
   - `make podman-prepare` (ou `make runtime RUNTIME=podman`) grava a escolha no `.env`;
   - o override `docker-compose.podman.yml` só é incluído nessa escolha; o arquivo base e o
     deploy nunca o leem;
   - quando escolhido, o caminho continua validado: `podman-check` no `make check`,
     `make check E2E=1` no mesmo runtime, e o contrato do ADR-044 (keep-id, postgres sem
     userns, `MOUNT_LABEL`) permanece o mesmo;
   - volta ao padrão com `make runtime RUNTIME=docker`.
3. **O opt-in não vaza para produção.**
   - nenhum flag de podman (`--userns=keep-id`, `label=disable`, `MOUNT_LABEL=`) existe no
     `docker-compose.yml` base;
   - `up_prod.sh` falha com `CONTAINER_RUNTIME=podman` mesmo que o `.env` do servidor tenha
     sido copiado de uma máquina de dev;
   - o gate `podman-check` é **estático**: valida o contrato dos dois arquivos sem exigir
     podman instalado, então o CI (Docker) continua cobrindo o caminho opcional.

## Justificativa (alternativas descartadas)

- **Podman rootful em produção**: mesma superfície de privilégio do Docker (daemon root),
  sem ganho funcional; só troca de ferramenta e de operação.
- **Podman rootless em produção**: exigiria Quadlet/systemd para os 6 serviços, `linger`,
  storage sob o usuário do deploy (quota, ADR-006), política de relabel SELinux, backup e
  restore do PGDATA via `podman unshare`, e o provider de Compose + socket no servidor —
  para entregar **a mesma imagem OCI** atrás do mesmo Apache. O ganho (sem daemon root) não
  paga a operação e cria um segundo modo de falha.
- **Podman como padrão de dev**: é a definição de drift. O dev validaria um ambiente que
  produção não executa; o CI e o deploy não cobririam keep-id/label.
- **Remover podman de vez**: descartaria um caminho já validado e a necessidade real de
  desenvolvedores Fedora/RHEL rodarem rootless. O custo de mantê-lo é um override e um gate
  estático — já pagos.
- **Shim `docker` → `podman` no PATH**: esconderia a decisão e quebraria `docker compose
  config` em máquinas com Docker real (já descartado no ADR-044).

## Consequências

- Um clone novo roda em Docker sem nenhum passo extra; podman exige `make podman-prepare`
  (ato único e visível).
- `make check` mede o runtime de referência; quem opta por podman aceita que seu ciclo é
  um teste de compatibilidade, não o caminho de produção.
- O ADR-044 permanece válido como **especificação do caminho opcional**; este ADR define
  quando ele é usado e onde não é.
- Produção com `CONTAINER_RUNTIME=podman` falha cedo e alto (`up_prod.sh`), em vez de
  produzir um deploy que ninguém mais reproduz.
- O parque de dev pode ter os dois motores instalados sem ambiguidade: a escolha é dado
  (`.env`), não heurística de PATH.

## Verificação

```bash
# padrão (Docker)
make runtime RUNTIME=docker      # grava CONTAINER_RUNTIME=docker
make ports                       # runtime: docker
make up                          # sobe/provisiona o runtime
make check                       # referência = Docker
make check E2E=1                 # e2e no mesmo motor

# opt-in de dev (podman rootless)
make podman-prepare              # ato explícito; grava CONTAINER_RUNTIME=podman
make up && make check E2E=1
make runtime RUNTIME=docker      # volta ao padrão

# produção nunca aceita podman
CONTAINER_RUNTIME=podman ./up_prod.sh --dry-run   # aborta com mensagem do ADR-045
```

Medido no host de referência: Docker e podman sobem os 6 serviços e passam `make check`
(30 OK); o guard de produção aborta antes de qualquer efeito.
