Operador de backup e restauração para Kubernetes · Postgres 15–17 · PostGIS · MySQL 8.4
Segure firme cada segundo.
O Tenax faz backup dos bancos Postgres e MySQL que você roda no Kubernetes no seu próprio bucket S3 e transmite cada mudança assim que ela acontece. Escolha um segundo dentro da janela e receba exatamente aquele banco de volta em um sandbox que você pode consultar. Criptografado antes de sair do cluster e projetado para sobreviver a qualquer queda, por isso nunca trava.
Um binário, um chart. Seu bucket, suas chaves.
- Restaurar para
- 2026-10-10 14:02:37 UTC
- Backup base
- 20261010T020712Z-4c1e
- Depois reaplicar
- 114
$ tenax restore team/app --at 2026-10-10T14:02:37Z --wait
Veja a volta no tempo ou arraste você mesmo pela janela. As marcas laranja são os backups completos de cada noite; a faixa ciano é o fluxo de mudanças entre eles. Ilustração de uma política prod: completo toda noite, janela de 7 dias.
- 9spara restaurar um banco Postgres de 644 MiB em um sandbox: baixar, descriptografar, recuperar e verificar
- 4.2×menor no bucket: um backup físico de 683 MiB armazenado como 161 MiB
- 72MiB/sde vazão em um backup lógico completo com 4 vCPU, em streaming e sem arquivos temporários
- 20msp99 da visão geral do console com 1.000 bancos e 100.000 backups
Medido com make test-perf e make test-ui no ambiente de testes k3d (4 vCPU, MinIO no cluster). Os números estão em docs/PERF.md no repositório.
01Como funcionacinco passos
De uma mudança ao vivo a um sandbox que você pode consultar.
Nenhum agente dentro do seu banco, nenhum snapshot de volume. O Tenax lê as mudanças pela rede, lacra os dados antes que saiam do pod e traz qualquer segundo de volta quando você pede.
- 01
Transmitir
Backups completos agendados e, além disso, cada mudança assim que acontece: o receptor de WAL do próprio Tenax para o Postgres e o mysqlbinlog para o MySQL.
WAL · binlog - 02
Criptografar
Cada byte é comprimido com zstd e criptografado com age para as suas chaves públicas, dentro do pod, em uma única passagem em streaming e sem arquivos temporários.
zstd → age - 03
Guardar
Uploads multipart em paralelo para qualquer bucket compatível com S3, um SHA-256 para cada objeto e o manifesto escrito por último.
*.zst.age · manifest.json - 04
Restaurar no segundo
Peça um horário ou um ID de backup. O Tenax escolhe o backup base e reaplica as mudanças até aquele segundo exato.
--at 14:02:37 - 05
Abrir um sandbox
O resultado chega a um banco privado com TTL e um console de consultas somente leitura. Suas verificações rodam antes de a restauração contar como sucesso.
--ttl 6h
02Restaurarquatro destinos
Restaure onde quiser, sem tocar na produção.
Uma restauração é um recurso do Kubernetes como qualquer outro. Peça um horário ou um ID de backup e escolha o destino. O Tenax planeja o backup base e as alterações a reaplicar, e roda suas verificações antes de considerar a restauração bem-sucedida.
Uma cópia descartável
Um banco privado com TTL, credenciais e um console de consultas somente leitura. Ele se limpa sozinho.
--to sandbox --ttl 6hUm banco novo
Restaurado e verificado em um sandbox intermediário, depois copiado com um novo nome. Objetos existentes nunca são sobrescritos.
--to new --database app_copyVoltar atrás de verdade
Faz antes um backup de segurança e pede que você digite o nome do alvo. Exige o papel restorer-admin.
--to in-place --confirm appUm arquivo de dump
Um dump lógico descriptografado e comprimido, atrás de um link que expira em uma hora. Auditado.
--to download03Vejaum minuto
Um minuto, do início à restauração.
Comandos reais e o console real sobre um catálogo de demonstração: liste cada banco, veja o que mudou durante a noite e restaure em um sandbox.
O console
Saiba o que mudou entre duas versões.
Cada backup traz um inventário das tabelas, linhas e tamanhos. Cada segmento de alterações traz um resumo do que fez. Assim, antes de restaurar qualquer coisa, você vê qual versão ainda tinha as linhas perdidas.
- Diffs entre quaisquer dois backups. Mudanças de esquema, contagem de linhas e tamanho por tabela.
- Resumo de alterações por segmento WAL ou binlog. Inserções, atualizações, exclusões e DDL por tabela, para achar fácil um TRUNCATE às 22:48.
- Prévias mascaradas. Linhas de amostra com as colunas que você indicar mascaradas, legíveis com uma chave de catálogo que não descriptografa os dados.
A CLI
$ tenax targets TARGET ENGINE ORG/PROJECT/ENV LAST FULL PITR WINDOW STORED HEALTH analytics/events postgres acme/data/staging 2026-10-07 02:11:47Z - 19.1GiB ok auth/users postgres acme/platform/prod 2026-10-07 02:11:06Z 2026-09-23 02:11:06Z → 2026-10-07 18:50:52Z 1.5GiB ok billing/invoices mysql acme/billing/prod 2026-10-07 02:09:03Z 2026-09-23 02:09:03Z → 2026-10-07 18:50:52Z 6.7GiB ok billing/ledger postgres acme/billing/prod 2026-10-07 02:08:22Z 2026-09-23 02:08:22Z → 2026-10-07 18:50:52Z 14.3GiB ok maps/geo postgres acme/maps/prod 2026-10-07 02:10:25Z 2026-09-23 02:10:25Z → 2026-10-07 18:50:52Z 23.3GiB ok shop-dev/orders-db postgres acme/shop/dev 2026-10-07 02:12:28Z - 17.4MiB ok shop/catalog-db postgres acme/shop/prod 2026-10-07 02:07:41Z 2026-09-23 02:07:41Z → 2026-10-07 18:50:52Z 731.0MiB ok shop/orders-db postgres acme/shop/prod 2026-10-07 02:07:00Z 2026-09-23 02:07:00Z → 2026-10-07 18:50:52Z 9.6GiB ok web/wordpress mysql acme/marketing/prod 2026-10-07 02:09:44Z 2026-09-23 02:09:44Z → 2026-10-07 18:50:52Z 607.4MiB ok
$ tenax diff 20261006T020700Z-bd79 20261007T020700Z-6da5 from 20261006T020700Z-bd79 (2026-10-06 02:07:00Z) to 20261007T020700Z-6da5 (2026-10-07 02:07:00Z) 20261007 applied (was 20261006) column orders.gift_note added table audit_log +158,175 rows (+2%) table order_items +62,923 rows (+1%) table orders +15,655 rows (+1%) table coupons −3,120 rows (−100%) table customers +531 rows (+1%) 14 segments in between: 00000001000000A100000000 18:51:32–19:20:32 · 800 commits · audit_log +3348 / ~1116 / −83 · order_items +1327 / ~442 / −33 · orders +330 / ~110 / −8 · customers +11 / ~3 / −0 00000001000000A100000001 19:21:32–19:50:32 · 813 commits · audit_log +3352 / ~1116 / −83 · order_items +1328 / ~442 / −33 · orders +330 / ~110 / −8 · customers +13 / ~3 / −0 00000001000000A100000002 19:51:32–20:20:32 · 826 commits · audit_log +3356 / ~1116 / −83 · order_items +1329 / ~442 / −33 · orders +330 / ~110 / −8 · customers +15 / ~3 / −0
$ tenax restore shop/orders-db --at 20261006T020700Z-bd79 --ttl 6h --reason "coupons truncated" restore orders-db-sandbox-60414a15fc created (sandbox from 20261006T020700Z-bd79, 0 segments) restore shop/orders-db-sandbox-60414a15fc $ tenax sandbox list NAME ENGINE SOURCE OWNER PHASE EXPIRES IN-CLUSTER sbx-7f3a postgres shop/orders-db maria@acme.example Ready 2026-10-08 00:37:32Z tenax-sbx-sbx-7f3a.tenax-sandboxes.svc:5432 sbx-c210 mysql billing/invoices dev@acme.example Provisioning -
Saída do servidor de demonstração do repositório: go run ./hack/demo e aponte a CLI ou um navegador para ele.
Console, CLI e API
Uma API JSON descrita em OpenAPI, com papéis do Cloudflare Access. Toda escrita e toda consulta são auditadas.
Nativo de GitOps
Stores, políticas, alvos e restaurações são CRDs. Níveis de retenção, alertas e um dashboard do Grafana vêm com o chart.
Verificado, não presumido
Restaurações de verificação agendadas rodam suas consultas SQL em uma restauração real e marcam o backup como verificado. O tempo de restauração vira métrica.
04Confiabilidadeà prova de quedas
Nunca trava. Nem um kill -9 o abala.
Backups falham de madrugada de jeitos chatos: um mount travado, um pod morto, um arquivo pela metade. O Tenax foi feito para que nenhum deles o trave ou se passe por um backup.
- data/part-00001.zst.age
- data/part-00002.zst.age
- data/part-00003.zst.age
- manifest.json
- data/part-00001.zst.age
- data/part-00002.zst.age
- data/part-00003.zst.age
- manifest.json
Nunca trava
Sem montagens nem dispositivos de bloco; bancos só pela rede. Cada fluxo tem um watchdog de progresso e cada ferramenta roda em seu próprio grupo de processos.
Crash-only
Mate qualquer pod a qualquer momento. Um backup só existe quando o manifesto é gravado por último, e a suíte de caos derruba o Tenax no meio do backup para provar.
Os dados trafegam em Jobs, nunca no controlador.
O controlador apenas agenda. Movers e streamers levam os bytes por um único pipeline em streaming direto para o seu bucket, e o restorer os traz de volta.
Gentil com a produção
Um único usuário de banco com privilégio mínimo, que nunca escreve. Slots por host, limites de banda e uma proteção de carga que adia o backup quando o servidor está ocupado.
Streaming de alterações
O receptor WAL do próprio Tenax em um slot de replicação para Postgres e mysqlbinlog para MySQL. A janela chega ao presente, mesmo com o banco ocioso.
Rápido por construção
Pipelines em streaming sem arquivos temporários, uploads multipart em paralelo, zstd multithread e um catálogo em memória por trás de um console que responde em milissegundos.
Leve a ponto de você esquecer que está lá.
O Tenax é um único binário Go. O controlador e a API apenas agendam e leem; os dados trafegam em Jobs de vida curta que terminam ao concluir, então entre um backup e outro nada pesado fica no seu cluster.
Working set informado pelo kubelet no cluster de testes k3d (12 bancos) após as suítes end-to-end e de caos; a CPU em repouso fica em poucos milicores. Cada banco com restauração pontual também roda um streamer, cerca de 70 MiB durante o streaming.
05Segurançacriptografado na origem
Seu bucket só vê dados criptografados.
A criptografia acontece no pod, antes do upload, com chaves que o Tenax não guarda. O acesso é dividido por papéis, e cada escrita e cada consulta deixa um registro de auditoria.
$ head -c 200 data/part-00001.zst.age age-encryption.org/v1 -> X25519 Qm9yZWQ/IE5vdGhpbmcgdG8gc2VlIGhlcmUu… --- 7Hc1kS0zR2QeYc… ÌÞ#ø§ñ¹t¤¢Ý}ϰë։ÿ]Wœ3Ð÷…
Cada objeto de dados é um arquivo age criptografado para os seus destinatários (X25519). Só o manifesto é JSON em texto claro, e ele não contém segredos.
Criptografado antes de sair
Cada objeto é criptografado no cliente com age para as suas chaves. O bucket nunca vê texto puro, e a chave de catálogo do console não lê dados.
Uma chave de catálogo que não lê dados
O console lê inventários e prévias mascaradas com uma identidade de catálogo separada. Ela não consegue descriptografar dumps, backups base, WAL nem binlogs.
Verificado de ponta a ponta
O manifesto guarda um SHA-256 para cada objeto armazenado, conferido ao fim de cada leitura, e é escrito por último com um PUT condicional.
Segredos longe dos olhos
As credenciais chegam às ferramentas filhas por arquivos lacrados em memória, nunca por argv nem pelo ambiente. Os logs ocultam tudo o que parece segredo.
Papéis e trilha de auditoria
Login pelo Cloudflare Access e quatro papéis, de viewer a restorer-admin. Restaurar no lugar exige o papel mais alto e uma confirmação digitada.
Pods blindados
Sem root, sistema de arquivos raiz somente leitura, todas as capabilities removidas e seccomp RuntimeDefault. Os pods de dados montam apenas emptyDir.
06Comparadoa um cron
Mais do que um dump noturno em um bucket.
| Quando você precisa… | script cron + pg_dump | Tenax |
|---|---|---|
| Voltar para 09:41:27 | O dump da noite passada, até 24 h perdidas | Qualquer segundo da janela |
| Provar que um backup restaura | Descobrir durante o incidente | Restaurações de verificação agendadas com suas checagens |
| Achar a versão com as linhas perdidas | Restaurar várias e olhar | Diffs e resumos de alterações no console |
| Olhar sem risco | Restaurar sobre um staging compartilhado | Um sandbox privado com TTL |
| Manter o bucket às cegas | Criptografia no servidor, se configurada | Criptografia age no cliente com suas chaves |
| Sobreviver a um nó que cai no meio | Um arquivo pela metade que parece completo | Nada conta até o manifesto ser gravado por último |
| Saber que continua funcionando | Silêncio | Alertas de backups atrasados, cadeias quebradas e atraso |
07Instalarcerca de dez minutos
Do zero ao restaurável.
Instale o chart
CRDs, o controlador, a API e o console, RBAC, alertas e o dashboard.
helm install tenax charts/tenax -n tenax-system --create-namespace \ --set image.repository=registry.example.com/tenax/tenax --set image.tag=v0.1.0 \ --set 'targetNamespaces={team-a}'Aponte para um bucket e suas chaves
Qualquer armazenamento compatível com S3. Gere uma chave age com age-keygen e guarde uma cópia offline.
apiVersion: tenax.republic.global/v1alpha1 kind: BackupStore metadata: { name: main } spec: s3: endpoint: https://s3.example.com region: us-east-1 bucket: db-backups credentialsSecret: { namespace: tenax-system, name: tenax-s3 } encryption: ageRecipients: [age1…] # só a chave pública; a privada fica offline
Declare um alvo ao lado do banco
Crie o usuário tenax com o SQL de docs/sql/ e faça commit do alvo no git.
apiVersion: tenax.republic.global/v1alpha1 kind: BackupTarget metadata: { name: app, namespace: team-a } spec: engine: postgres endpoint: { host: postgres, port: 5432 } databases: [app] policy: prod # completos toda noite, janela de 7 dias credentials: secretRef: { name: tenax-postgres }
Restaure algo, de propósito
O primeiro backup completo começa sozinho. Depois teste aquilo que você espera nunca precisar.
tenax targets tenax restore team-a/app --at 2026-10-07T09:41:27Z --wait tenax query <sandbox> -e "select count(*) from orders"
O guia completo, cada campo dos CRDs e a API REST estão na documentação (em inglês).
08FAQrespostas diretas
O que os engenheiros perguntam primeiro.
Quais bancos de dados o Tenax suporta?
Postgres 15, 16 e 17, incluindo PostGIS, com backups completos físicos ou lógicos e streaming de WAL. MySQL 8.4 com backups completos lógicos e streaming de binlog.
Até quando posso restaurar, e com que precisão?
Qualquer backup completo que seus níveis de retenção mantenham, e qualquer segundo dentro da janela de recuperação definida pela sua política. A política de exemplo prod mantém uma janela de 7 dias e 14 completos diários, 8 semanais, 12 mensais e 5 anuais.
O Tenax ou meu provedor de armazenamento conseguem ler meus dados?
O bucket não: cada objeto é criptografado com age para os seus destinatários antes do upload. O console lê os inventários com uma chave de catálogo que não descriptografa os dados. As restaurações descriptografam com uma identidade age fornecida por você; guarde uma cópia offline.
O que acontece se um pod morrer no meio de um backup?
Nada que conte. Um backup só existe quando o manifesto é escrito, depois que cada objeto foi enviado e verificado. Uma execução pela metade não tem manifesto e nunca aparece para restauração. A suíte de caos mata o Tenax no meio do backup para provar isso.
O Tenax monta volumes ou usa snapshots?
Não. Ele acessa os bancos só pela rede, e os pods não montam nada além de emptyDir: nada de hostPath, FUSE, iSCSI ou dispositivos de bloco, e nenhum PVC por padrão. Um driver de armazenamento travado não consegue travar um backup.
Do que o Tenax precisa no meu banco?
Um usuário tenax de privilégio mínimo por banco, que nunca escreve, criado com o SQL em docs/sql/. Sem permissão de replicação o Tenax ainda faz backups lógicos e diz o que conceder para restaurar em qualquer segundo.
O Tenax é open source?
O código está disponível sob a The Republic Lex Aequa License 1.0. Qualquer pessoa pode usar, modificar e redistribuir sem custo, inclusive em produção e em empresas comerciais, para proteger os próprios dados. Vender ou oferecer como serviço a terceiros é reservado.