`runner adopt`
Recupera o registro de uma app que continua rodando mas cujo state o Runner perdeu
(disco corrompido, unregister acidental, migracao de servidor). Em vez de recriar a
app do zero — e arriscar subir com secrets errados — o adopt le o container vivo
como fonte da verdade.
Resolve a issue #36.
O que ele faz
- Captura as variaveis de ambiente do container em execucao
- Faz diff contra os defaults da imagem — so o que foi injetado no deploy sobra
- Classifica cada valor em secret ou plain via
secret_detect - Registra a app (cold) ou reusa o registro existente (warm)
- Grava
.env/.secretse re-encripta o bundle
Sintaxe
runner adopt <app> --from-container <container> -r <owner/repo> -b <branch> --ckey # cold
runner adopt <app> --from-container <container> # warmCold vs warm
| Modo | Quando | Exige |
|---|---|---|
| cold | Nao ha registro nenhum da app | --repo, --branch, --ckey |
| warm | O registro existe, so o .env/.secrets se perdeu |
so --from-container |
Argumentos
| Argumento | Tipo | Obrigatorio | Descricao |
|---|---|---|---|
<app> |
string | Sim | Nome da app |
Flags
| Flag | Obrigatorio | Descricao |
|---|---|---|
--from-container <NOME> |
Sim | Container vivo de onde capturar as envs |
-r, --repo <OWNER/REPO> |
So no cold | Repositorio GitHub |
-b, --branch <BRANCH> |
So no cold | Branch de distribuicao |
--ckey [<CKEY>] |
So no cold | Content key do bundle de secrets. Sem valor (--ckey solto): gera uma aleatoria de 32 chars |
-t, --token <TOKEN> |
Nao | Token GitHub para repo privado (encriptado at rest) |
--token-from <APP> |
Nao | Reusa o token de outra app registrada, sem passar por plaintext |
--github-app <APP_ID> |
Nao | Credencial de GitHub App (2.141.0+; exige --repo). Ver credenciais |
--corte-pendente |
Nao | Adocao com corte (2.141.0+): registra como pendente e pausa a app ate o corte. Ver abaixo |
--manifest-path <PATH> |
Nao | Caminho do .deploy.yml dentro do repo (monorepos) |
--instance <INSTANCE> |
Nao | Instance alvo (production, staging, ...) |
--yes |
Nao | Nao pergunta nada: a faixa ambigua de classificacao vira secret (conservador) |
-o, --output |
Nao | human | json | yaml |
-x, --exact |
Nao | Exige match exato de identidade, sem fallback por prefixo |
--insecure |
Nao | Bypass dos guards. Emite banner e grava em insecure-events.jsonl |
Exemplos
# cold — nenhum registro sobrou
runner adopt myapp --from-container myapp -r user/myapp -b main --ckey
# warm — o registro existe, reusa
runner adopt myapp --from-container myapp
# monorepo, com token emprestado de outra app
runner adopt api --from-container api_production_v1-2-0 \
-r acme/mono -b dist --manifest-path services/api/.deploy.yml --token-from webAdocao com corte (parada e substituicao) — 2.141.0+
Sem --corte-pendente, o primeiro deploy substitui o adotado do jeito de sempre
(parando-o antes so quando compartilha volume ou porta). Com ele, a troca vira
uma operacao explicita, com janela e volta:
# 1. registra; a app fica pausada (o cron nao deploya, deploy comum e recusado)
runner adopt loja --from-container loja -r acme/loja -b dist --corte-pendente
# 2. corte: para o adotado, sobe o novo, health dentro da janela
runner deploy loja --replace-adopted --janela 60 [--antigo-id <id>] [--dados compartilhar|copiar|mover|sem]
# 3a. desfazer (religa o antigo) 3b. concluir (destroi o antigo, despausa)
runner revert-adoption loja runner finalize-adoption loja
runner adoption status loja --json # pendente | cortado | revertido | finalizadoO que o corte faz: confere o adotado (--antigo-id), para-o, trata os dados,
renomeia para <nome>__ccs_antes com restart policy no e sobe o novo. Se o
health nao passa dentro de --janela (contada desde a parada), o novo sai e o
antigo volta com nome e restart policy originais. Sucesso deixa o antigo
parado e preservado e a app ainda pausada ate o finalize/revert.
Depois de um revert-adoption (status revertido, app pausada) da para cortar
de novo direto com deploy --replace-adopted (2.141.2+), sem refazer o adopt.
--dados |
Efeito |
|---|---|
compartilhar (padrao) |
O novo monta os mesmos volumes/binds (o antigo esta parado: um escritor so) |
copiar |
Copia o conteudo dos volumes do adotado para os do manifesto (cp -a) |
mover |
Copia e, no finalize-adoption, remove os volumes de origem |
sem |
Nao toca nos dados; recusa (colisao_de_volume) se o novo montar o mesmo volume |
Codigos de erro (prefixo da mensagem / error no JSON): adocao_em_andamento
(deploy comum numa adocao pendente/cortada/revertida), app_desconhecida, adocao_nao_pendente,
container_mudou, corte_em_andamento (ja existe um __ccs_antes),
colisao_de_volume, revertido, janela_estourada, reversao_falhou
(estado manual: confira docker ps -a), nada_a_reverter, antes_ausente,
nada_a_finalizar.
Sobre a classificacao automatica
O secret_detect divide os valores em tres faixas: claramente secreto, claramente
publico, e ambiguo. Sem --yes o comando pergunta caso a caso. Com --yes, o
ambiguo vira secret — o erro conservador (um valor publico tratado como secreto
nao vaza nada; o contrario sim).
Ver tambem
- `runner add` — registrar uma app nova, do zero
- `runner state` — recuperar o state a partir da cadeia de backup
- `runner unregister`