O Releaser copia os arquivos de backup das builds para um bucket S3 (comando io cloud, veja Cópia em nuvem (S3)). O destino pode ser um serviço comercial (AWS S3, Cloudflare R2, Backblaze B2) ou um S3 no seu próprio data center, o que mantém os dados dentro da Embrapa e não tem custo por gigabyte.

Esta página descreve como montar esse S3 próprio com os boilerplates da plataforma, do mesmo jeito que foi montado o Embrapa I/O S3, usado pelos servidores com Releaser da plataforma. São três peças:

  • Silo: servidor S3 de código aberto (um fork mantido do MinIO, com o console de administração completo), pelo boilerplate silo;
  • Caddy: proxy reverso com HTTPS automático (Let’s Encrypt), pelo boilerplate caddy;
  • Releaser: faz o deploy dos dois e os mantém atualizados.
[Releaser de outro servidor] --HTTPS, chave própria--> [Caddy :443] --> [Silo :PORT] --> /data/silo (disco de dados)
[administrador] --navegador, chave raiz--> [Caddy :443] --> [console do Silo :PORT_CONSOLE]

Atenção! O S3 de backup tem de ficar numa máquina diferente das que geram os backups (regra 3-2-1). Se possível, num datastore separado também: um backup no mesmo disco das aplicações se perde junto com elas.

Máquina

O que foi usado no Embrapa I/O S3, como referência:

Recurso Valor
CPU e memória 4 vCPU e 16 GB de RAM (o Silo usa pouco; 2 vCPU e 4 GB bastam para poucos servidores)
Sistema Ubuntu Server LTS, com Docker do repositório oficial
Disco do sistema 100 GB (sistema, imagens e os backups de configuração)
Disco de dados disco virtual separado, sem formatação, do tamanho do acervo (2 TiB no Embrapa I/O S3)
Rede IP público, se houver Releasers fora da rede da Embrapa; portas 80 e 443 abertas para fora
DNS dois nomes: um para a API (ex.: s3.unidade.embrapa.br) e outro para o console (ex.: console.s3.unidade.embrapa.br)

Ao pedir a VM à equipe de infraestrutura, peça o disco de dados sem formatação e, se possível, em datastore separado do disco do sistema.

Preparo do disco de dados

O disco de dados vira um volume LVM com sistema de arquivos XFS, montado em /data. O LVM permite crescer o volume depois sem parar nada, e o XFS lida bem com objetos grandes e com muitos arquivos. No exemplo, o disco novo é o /dev/sdb: confira com lsblk antes, e confirme que ele está vazio com wipefs -n /dev/sdb (sem saída = sem assinatura).

sudo pvcreate /dev/sdb
sudo vgcreate data-vg /dev/sdb
sudo lvcreate -l 100%FREE -n silo data-vg
sudo mkfs.xfs -L silo /dev/data-vg/silo

sudo mkdir -p /data
sudo cp -a /etc/fstab /etc/fstab.bak
echo "UUID=$(sudo blkid -s UUID -o value /dev/data-vg/silo) /data xfs defaults,noatime,nofail 0 2" | sudo tee -a /etc/fstab
sudo systemctl daemon-reload
sudo mount -a
df -h /data
  • A montagem é pelo UUID, que não muda se a ordem dos discos mudar.
  • O nofail evita que a VM pare no boot se o disco faltar. Nesse caso o Silo também não sobe (o volume dele aponta para /data/silo, que não existe no disco do sistema), e nada é gravado no lugar errado.
  • Faça um reboot de teste antes de colocar dados: /data tem de voltar montado e o Silo, de pé.

Para crescer o disco depois, peça a expansão do disco virtual e rode:

sudo pvresize /dev/sdb
sudo lvextend -r -l +100%FREE data-vg/silo   # o -r estende também o XFS

Atenção! O XFS cresce, mas não diminui.

Silo e Caddy pelo Releaser

  1. Crie um projeto na plataforma (ex.: storage) com duas apps: uma do boilerplate silo e outra do caddy.
  2. Instale o Releaser na VM (veja Releaser) e configure as duas builds com io install.
  3. Antes do primeiro deploy, crie o volume de dados do Silo apontando para o disco de dados. O nome segue a regra {projeto}_{app}_{estágio}_data:
sudo mkdir -p /data/silo
sudo docker volume create --driver local --opt type=none --opt o=bind --opt device=/data/silo storage_silo_release_data
  1. Faça o deploy (io deploy --all).

Se o Silo já tinha subido com um volume comum, no disco do sistema, a troca é:

  1. io stop <build> --down;
  2. rsync -aHAX do diretório do volume antigo para /data/silo;
  3. docker volume rm do volume antigo e docker volume create com o bind, como acima;
  4. io restart <build>, que recria os contêineres desde a versão 1.26.10-15 (antes dela, use io deploy <build> --force).

Configuração do Silo

As variáveis da build do Silo usadas no Embrapa I/O S3:

Variável Valor Por quê
BUCKET backup um bucket para todos os servidores; cada um grava em <projeto>/<app>/<estágio>/
OBJECT_LOCK_DAYS 14 cada arquivo enviado fica imutável por 14 dias (modo GOVERNANCE): nem um servidor invadido, nem um engano, consegue apagá-lo nesse prazo
NONCURRENT_DAYS 30 versões antigas (arquivos apagados ou substituídos) somem sozinhas em 30 dias, depois da retenção
APP_ACCESS_KEY backup usuário de aplicação criado pelo init, com acesso ao bucket inteiro; para os servidores, use chaves próprias (abaixo)
ROOT_USER e ROOT_PASSWORD gerados administração; só para o console

Com o Object Lock, o espaço ocupado é maior que o acervo: um arquivo apagado pela rotação do Releaser continua no disco até completar a retenção e a expiração. Dimensione o disco com folga.

Senhas e chaves só com letras e números ([A-Za-z0-9]), de 32 caracteres ou mais: alguns clientes S3 e shells tratam mal os símbolos.

Configuração do Caddy

Na build do Caddy:

Variável Exemplo
APP_DOMAIN s3.unidade.embrapa.br
APP_PORT a PORT do Silo (API)
CONSOLE_DOMAIN console.s3.unidade.embrapa.br
CONSOLE_PORT a PORT_CONSOLE do Silo
ACME_EMAIL e-mail para os avisos do Let’s Encrypt

O certificado é emitido sozinho no primeiro acesso, desde que os dois nomes apontem para a VM e as portas 80 e 443 estejam abertas. As portas do Silo não precisam ficar abertas para fora: só o Caddy as acessa.

Atenção! O console dá acesso total com a chave raiz. Se não precisar dele fora da rede da Embrapa, deixe o nome do console só no DNS interno, ou acesse-o por túnel SSH.

Uma chave por servidor

Não distribua a chave backup (nem a raiz) aos servidores. Crie uma chave por servidor, restrita aos projetos que ele hospeda: se um servidor for comprometido, ele não lê nem apaga os backups dos outros (e o Object Lock protege os dele próprio por 14 dias).

O Releaser grava em <bucket>/<projeto>/<app>/<estágio>/<arquivo>. A política abaixo deixa o servidor listar o bucket (o teste de acesso do Releaser lista a raiz) e ler, gravar e apagar só dentro dos seus projetos. Troque meu-projeto pelos projetos do servidor (um Resource por projeto); o io deploy sem parâmetros, no próprio servidor, mostra as builds dele.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetBucketLocation", "s3:ListBucket", "s3:ListBucketVersions", "s3:ListBucketMultipartUploads"],
      "Resource": ["arn:aws:s3:::backup"]
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:GetObjectVersion", "s3:PutObject", "s3:DeleteObject", "s3:DeleteObjectVersion", "s3:AbortMultipartUpload", "s3:ListMultipartUploadParts"],
      "Resource": ["arn:aws:s3:::backup/meu-projeto/*"]
    }
  ]
}

A política não inclui s3:BypassGovernanceRetention, s3:PutObjectRetention nem nada de administração: a chave não consegue encurtar a retenção nem mexer no bucket. Listar o bucket inteiro mostra os nomes dos arquivos dos outros servidores, mas não o conteúdo.

Pelo console

  1. Entre no console (https://console.s3.unidade.embrapa.br) com o usuário raiz.
  2. Policies → Create Policy: nome releaser-<servidor>, e cole a política acima.
  3. Gere a senha, só com letras e números:
    openssl rand -base64 48 | tr -dc A-Za-z0-9 | head -c 40
    
  4. Identity → Users → Create User: Access Key <servidor>, Secret Key a senha gerada, e marque somente a política releaser-<servidor>.

Pela linha de comando

O boilerplate traz o mc no serviço mc (perfil cli). No diretório da build do Silo, com a política salva em policy.json:

env $(cat .env.io) docker compose run --rm -T mc admin policy create silo releaser-meu-servidor /dev/stdin < policy.json
env $(cat .env.io) docker compose run --rm mc admin user add silo meu-servidor <SENHA>
env $(cat .env.io) docker compose run --rm mc admin policy attach silo releaser-meu-servidor --user meu-servidor

Os usuários e políticas entram no backup de configuração do Silo (abaixo).

Configuração em cada servidor

No servidor que vai enviar os backups, com o Releaser 1.26.10-15 ou mais novo (io upgrade):

io cloud --setup
Pergunta Resposta
Endpoint https://s3.unidade.embrapa.br
Bucket backup
Access key e secret key a chave do servidor
Região auto (o padrão; o Silo aceita)

O assistente testa a listagem e a gravação antes de salvar. O teste de gravação abre e cancela um upload multipart no diretório de uma build do servidor, sem deixar nada no bucket: um arquivo de teste comum ficaria retido pelo Object Lock por 14 dias. Depois:

io cloud <projeto>/<app>@<estágio>             # primeira cópia, manual
io cloud <projeto>/<app>@<estágio> --verify    # compara os arquivos dos dois lados pelo hash
io cloud <projeto>/<app>@<estágio> --list      # o que está no bucket e o que a rotação faria

Por fim, ligue "auto": { "cloud": true } no arquivo da build para a cópia diária. O io check, e o check diário por e-mail, voltam a testar listagem e gravação todo dia.

Atenção! A primeira cópia envia todo o acervo de backups da build e pode levar horas. Acompanhe o espaço livre em /data do S3 enquanto ela roda.

Monitoramento

  • Saúde: https://s3.unidade.embrapa.br/minio/health/live responde 200 com o Silo de pé. É o que o Embrapa I/O monitora no Gatus.
  • Disco: alerte o uso de /data acima de 80% (aviso) e de 90% (crítico), e também a falta da métrica, que indica /data desmontado ou coletor parado. No Embrapa I/O, as métricas vão pelo Alloy para o Prometheus da plataforma, e os alertas são regras do Grafana.
  • Conteúdo do bucket: mc du --depth 3 silo/backup/ mostra o espaço por projeto; mc ls --recursive --incomplete silo/backup/ lista uploads inacabados.

Backup e recuperação do próprio S3

O serviço backup do boilerplate silo, que o Releaser roda todo dia, guarda só a configuração: usuários, políticas e buckets com versionamento, Object Lock e expiração. Não copia os objetos: os backups das aplicações são, eles mesmos, a cópia; a original continua em cada servidor. Se o S3 for perdido, suba um Silo novo, restaure a configuração (serviço restore) e os servidores voltam a enviar tudo na próxima execução do io cloud.

O arquivo de backup da configuração contém as chaves dos usuários: trate-o como segredo.