Fazendo backup dos meus dados com Restic, Btrfs e MinIO

Fazendo backup dos meus dados com Restic, Btrfs e MinIO


No ano passado, estabeleci uma estratégia de backup que atende às minhas necessidades. Nesta postagem, compartilharei as propriedades que procuro em uma solução de backup e como minha solução atual as aborda. Como sempre, se você tiver alguma sugestão ou melhoria, fique à vontade para entrar em contato.

O primeiro passo antes de falar de tecnologia é identificar exatamente quais dados queremos fazer backup. No meu homelab, conto com o Immich para armazenamento de fotos, o Navidrome para streaming de música, bancos de dados para meu site e outros documentos pessoais. Isso equivale a pouco mais de 250 GB de dados que seriam muito difíceis de substituir se fossem perdidos.

Nem todos os meus dados residem nesse servidor. Também tenho um VPS de armazenamento que executa Nextcloud e Hedgedoc. Ambos os serviços combinados têm menos de 100 GB de dados, mas, assim como o homelab, esses dados são preciosos. O armazenamento VPS tem capacidade total de 1,5 TB.

A estratégia de backup 3-2-1 cunhada por Peter Krogh sugere que devemos ter três cópias de nossos dados, armazenados em duas mídias diferentes, sendo uma delas externa.

Ambos os meus servidores têm capacidade de armazenamento suficiente para armazenar uma cópia de todos os meus dados. Para minha terceira cópia, decidi contar com o Backblaze b2. Este é um serviço de armazenamento de objetos S3 que cobra taxas baixas pelo que armazeno e pelo número de transações que faço.

Meu homelab fica em minha casa, o VPS de armazenamento fica em Montreal e o Backblaze armazena meus dados em Phoenix. Portanto, eu tenho 3 cópias dos meus dados e eles estão armazenados em mais de 1 localização.

Para abordar tendo pelo menos 2 mídia de armazenamento diferente, faço backup dos meus dados usando duas abordagens diferentes: Restic e Btrfs Snapshots. Atualmente, não tenho dados suficientes para que o armazenamento on-line intenso tenha um custo proibitivo.

Restico

Restic é um software de backup moderno e de código aberto que desduplica e criptografa o conteúdo do arquivo no nível do blob. Em combinação com um cache local de metadados, isso torna este Restic rápido e eficiente de usar.

Ele oferece suporte a uma variedade de destinos de backup:

Embora eu pudesse usar a variedade de destinos de backup para aumentar o número de abordagens de backup dos meus dados, para mim isso não parece suficientemente diferente para garantir a complexidade adicional. Portanto, usarei um destino de backup para todos os três locais.

Como o Backblaze b2 suporta apenas o protocolo S3, isso significa que minha escolha foi feita por mim. No entanto, mesmo que não fosse imposto a mim, eu ainda escolheria essa opção. Projetado pela Amazon para seu serviço de armazenamento, o protocolo S3 é construído com escala em mente e oferece suporte a uploads simultâneos de arquivos multipartes. Além disso, diferentemente do SFTP, o S3 separa suas contas das do servidor. Existem maneiras de restringir clientes SSH, porém esse não é o comportamento padrão. No S3, por padrão, um usuário não pode fazer nada.

Assim, após escolher o S3, preciso configurar um servidor S3 tanto no meu VPS de armazenamento quanto no meu homelab. Optei pelo MinIO por sua facilidade de configuração e longevidade; no entanto, qualquer uma das outras soluções também funcionaria.

Como estamos armazenando cópias dos dados em todos os servidores, uma ideia é configurá-los em uma configuração de cluster. Porém, como não estou gerenciando o servidor S3 hospedado pelo Backblaze, não seria possível incluí-lo no cluster. Geralmente, não é recomendado executar um cluster com apenas dois nós. Se o fizermos, isso pode levar ao que é chamado de problema de cérebro dividido onde ambos os nós são incapazes de se comunicar entre si e pensam que são o nó líder.

Para evitar isso, podemos executar ambas as instâncias do MinIO de forma independente e fazer com que o Restic envie os dados separadamente para todos os servidores.

Configuração do MiniIO

Se você já possui um bucket configurado e configurado com as permissões apropriadas, sinta-se à vontade para pular esta seção.

Os exemplos de código a seguir assumem que o MinIO está instalado e o mc o cliente está disponível com as credenciais raiz para cada servidor (alias) definido. Essas etapas gerais também podem ser alcançadas usando a IU de gerenciamento. Para simplificar, mostrarei como fazer isso em relação a um servidor homelab. No entanto, precisaremos fazer isso para cada instância do MinIO.

Primeiro, crie um bucket que armazenará nossos dados de backup.

# alias_of_server/bucket_name
mc mb homelab/backups

Depois, crie um usuário backup. Precisaremos especificar o ACCESS_KEY e SECRET_KEY que corresponde ao nome de usuário e senha respectivamente. Guarde-os, pois precisaremos usá-los mais tarde.

export ACCESS_KEY="my_awesome_homelab_user"
export SECRET_KEY="SUPER_SECURE_SECRET_KEY"
mc admin user add homelab $ACCESSKEY $SECRETKEY

Observação: Para um pouco mais de segurança, gosto de criar uma chave de acesso e uma chave secreta diferentes para os outros servidores.

Por padrão, nosso usuário não pode fazer nada. Vamos fazer com que eles tenham acesso ao nosso backups balde que criamos anteriormente. Para fazer isso, precisaremos criar uma política que permita ao usuário realizar operações nesse bucket.

Teremos que criar um arquivo JSON e seguir o formato AWS IAM.

{
 "Version": "2012-10-17",
 "Statement": (
  {
   "Effect": "Allow",
   "Action": (
    "s3:ListBucket",
    "s3:PutObject",
    "s3:DeleteObject",
    "s3:GetObject"
   ),
   "Resource": (
    "arn:aws:s3:::backups/*",
    "arn:aws:s3:::backups"
   )
  }
 )
}

Suponha que salvamos o JSON anterior em um local especificado pela variável ambiental $POLICY_PATHentão podemos criar a política através do seguinte:

export POLICY_NAME="backup-policy"
mc admin policy create homelab $POLICY_NAME $POLICY_PATH

Depois de criar a política, precisamos atribuí-la ao nosso usuário backup.

mc admin policy attach homelab $POLICY_NAME --user $ACCESS_KEY

Nginx e inicialização do Restic

Com nosso bucket e usuário configurados, agora vamos discutir como realizaremos nossos backups. Nosso bucket terá a seguinte estrutura de diretórios:

backups/
  homelab/
  vps/

Cada pasta conterá um repositório restic. Nós os separamos em vez de ter um repositório gigante e restrito, para que não precisemos nos preocupar com vários servidores competindo por um bloqueio.

Em vez de nos comunicarmos por HTTP, queremos uma maneira segura de acessar nossos buckets de fora do servidor. Para isso, eu uso o nginx para fazer proxy do tráfego para o MinIO. Eu configuro Certbot com LetsEncrypt para que a conexão possa ser protegida com HTTPS/TLS. Além das instruções listadas na página do MinIO, também restringo os IPs que têm permissão para se conectar. Por exemplo, para permitir apenas o tráfego de dentro da sua rede Wireguard (ex sub-rede: 10.10.10.1/24) então você pode colocar o seguinte dentro do location bloco da configuração do nginx.

allow 10.10.10.1/24;
deny all; // Denies all other traffic

Depois de proteger a entrada do nosso servidor S3, estamos prontos para usar o Restic. Antes de começar, você pode querer criar uma conta dedicada para que não tenhamos que usar o root usuário.

Vamos inicializar o respectivo repositório de cada servidor. Como nossos backups serão criptografados, precisamos criar outra senha e colocá-la no RESTIC_PASSWORD variável ambiental. Salve esta senha em um local seguro, pois sem ela não poderemos descriptografar o backup.

export RESTIC_REPOSITORY=s3:https:///backups/homelab
export AWS_ACCESS_KEY_ID=$ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=$SECRET_ACCESS_KEY
export RESTIC_PASSWORD="RESTIC_SUPER_SECURE_PASSWORD"

restic init

A partir daqui, crie um script de backup em /usr/local/bin/backup.sh. É aqui que especificamos quais pastas fazer backup.

Exemplo:

#!/bin/sh

set -o errexit
set -o nounset

if ( "$EUID" -ne "$(id -u restic)" )
  then echo "Please run as restic"
  exit
fi

# Usage: rbackup (message) (restic-tag) (backup-dir)
rbackup () {
  echo "$1"
  restic backup \
    --tag "$2" \
    "$3"
}


## BACKUP TO CLOUD
export RESTIC_REPOSITORY=s3:https:///backups/homelab
export AWS_ACCESS_KEY_ID="CLOUD_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="CLOUD_SECRET_ACCESS_KEY"
export RESTIC_PASSWORD="RESTIC_SUPER_SECURE_PASSWORD"

rbackup "Backing up documents" \
  Documents \
  /home/user/Documents

# Backup other great directories...

## BACKUP TO BACKBLAZE
export RESTIC_REPOSITORY=s3:https:///backups/homelab
export AWS_ACCESS_KEY_ID="BACKBLAZE_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="BACKBLAZE_SECRET_ACCESS_KEY"
export RESTIC_PASSWORD="RESTIC_SUPER_SECURE_PASSWORD"

rbackup "Backing up documents" \
  Documents \
  /home/user/Documents

# Backup other great directories...

A menos que você tenha armazenamento ilimitado, provavelmente desejará remover backups antigos de acordo com alguma programação. No mesmo script tenho a seguinte função:

prune () {
  echo "Pruning old snapshots"
  restic unlock
  restic forget \
    --group-by "tags" \
    --keep-daily N_DAYS \
    --keep-weekly N_WEEKS \
    --keep-monthly N_MONTHS \
    --prune
}

Substituir N_* ao seu gosto. O Restic garantirá então que manterá instantâneos suficientes para que essas regras baseadas em tempo sejam satisfeitas.

Com o script escrito, podemos configurar um serviço systemd e um cronômetro para que ele seja executado diariamente. Escreva o seguinte para /etc/systemd/system/restic-backup.service.

(Unit)
Description=Executes backup script
Requires=network-online.target
Wants=

(Service)
User=restic
Group=restic
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Environment="HOME=/home/restic"

(Install)
WantedBy=multi-user.target

Escreva o cronômetro para /etc/systemd/system/restic-backup.timer

(Timer)
OnCalendar=daily
Persistent=true
(Install)
WantedBy=timers.target

Instantâneos Btrfs

Ambos os meus servidores executam o Btrfs como sistema de arquivos subjacente. Um recurso interessante é que o Btrfs pode criar instantâneos. Estas são visualizações pontuais imutáveis ​​de um determinado subvolume. Como tal, precisaremos criar um subvolume que conterá os diretórios que desejamos.

Se não estamos começando do zero e, em vez disso, queremos criar um subvolume a partir de uma pasta existente, recomendo executar as seguintes etapas neste tópico do reddit:

mv folder folder_backup
btrfs subvolume create folder
cp --archive --one-file-system --reflink=always folder_backup/. folder

A partir daqui, podemos criar nossos instantâneos. Assim como acontece com nossa configuração Restic, gosto de ter alguns backups diários, semanais e mensais disponíveis. Vou armazenar esses instantâneos em /snapshotsmas você está livre para alterar o local. Aqui está o que parece na minha máquina:

/snapshots/
  daily
    20251201
      /home/user/Documents
      ...
      /home/user/Music
    ...
    20251227
  monthly
    ...
  weekly
    ...

Como estes são instantâneos de backup, queremos que sejam somente leitura. Aqui está como é criar um instantâneo diário para nosso subvolume de documentos:

SNAPSHOT_PATH="/snapshots/daily/$(date +'%Y%m%d')/home/user/Documents"
mkdir -p "$(dirname $SNAPSHOT_PATH)"
btrfs subvolume snapshot -r /home/user/Documents "${SNAPSHOT_PATH}"

Usamos a data no nome da pasta para que possamos detectar facilmente os instantâneos mais antigos para exclusão.

OLDEST_SNAPSHOT=$(ls "${SNAPSHOT_DIR}" | sort | head -n 1)
for SUBVOLUME_PATH in "${SUBVOLUMES(@)}"
do
    SNAPSHOT_PATH="${SNAPSHOT_DIR}/${OLDEST_SNAPSHOT}${SUBVOLUME_PATH}"
    btrfs subvolume delete -c "${SNAPSHOT_PATH}"    
done
rm -rf "${SNAPSHOT_DIR}/${OLDEST_SNAPSHOT}"

Montei um script que recebe como entrada a variável de ambiente SNAPSHOT_DIR e lida com a criação e remoção de instantâneos. Para obter esses instantâneos em intervalos de tempo diferentes, usamos diferentes temporizadores do systemd e alteramos essa variável de entrada. Ao contrário de nossa configuração restic, isso manterá o mesmo número de $N$ de instantâneos para cada um de nossos intervalos de tempo. Copiamos este script para /usr/local/bin/localbtrbak.sh.

#!/bin/bash

set -o nounset

show_usage() {
    echo "Usage: localbtrback"
    exit 1
}

# Check argument count
if ( "$#" -ne 0 ); then
    show_usage
fi

if ( "$EUID" -ne 0 )
    then echo "Please run as root"
    exit
fi

if ( -z "$SNAPSHOT_DIR" )
    then echo "SNAPSHOT_DIR not defined"
    exit
fi

# EDIT TO POINT TO YOUR SUBVOLUMES
SUBVOLUMES=("/home/user/Documents"  "/home/user/Music")

for SUBVOLUME_PATH in "${SUBVOLUMES(@)}"
do
    SNAPSHOT_PATH="${SNAPSHOT_DIR}/$(date +'%Y%m%d')${SUBVOLUME_PATH}"

    # Create folder if not already exists
    mkdir -p "$(dirname $SNAPSHOT_PATH)"

    # Create the readonly snapshot
    btrfs subvolume snapshot -r "${SUBVOLUME_PATH}" "${SNAPSHOT_PATH}"
done

# Calculate the number of snapshots
COUNT=$(ls "${SNAPSHOT_DIR}" | wc -l)

if ( "${COUNT}" -gt 3 ); then
    OLDEST_SNAPSHOT=$(ls "${SNAPSHOT_DIR}" | sort | head -n 1)
    for SUBVOLUME_PATH in "${SUBVOLUMES(@)}"
    do
        SNAPSHOT_PATH="${SNAPSHOT_DIR}/${OLDEST_SNAPSHOT}${SUBVOLUME_PATH}"
        btrfs subvolume delete -c "${SNAPSHOT_PATH}"    
    done
    rm -rf "${SNAPSHOT_DIR}/${OLDEST_SNAPSHOT}"
fi

Para nosso serviço systemd em /etc/systemd/system/btrlocalback@.service

(Unit)
Description=Create a local BTRFS snapshot

(Service)
Type=oneshot
Environment=SNAPSHOT_DIR="/snapshots/%i"
ExecStart=/usr/local/bin/localbtrbak.sh

(Install)
WantedBy=multi-user.target

Um exemplo de cronômetro diário armazenado em /etc/systemd/system/btrlocalbak@daily.timer

(Unit)
Description=Create a daily local BTRFS snapshot
(Timer)
OnCalendar=daily
Persistent=true
(Install)
WantedBy=timers.target

Conclusão

Aqui está uma visualização dos três servidores e onde o backup dos dados é feito:

Fazendo backup dos meus dados com Restic, Btrfs e MinIO

A imagem do bucket no diagrama denota o armazenamento S3, enquanto o ícone do banco de dados cilíndrico denota os snapshots do Btrfs. Pictoricamente, isto também nos mostra como a regra 3-2-1 é satisfeita.

  • Três setas de saída nos dois servidores significam que temos três cópias dos dados
  • Os dois ícones em cada um dos servidores mostram que estamos fazendo backup de duas maneiras diferentes
  • Tenho mais de um backup externo, pois todas as três caixas estão em locais diferentes.

Se eu excluir acidentalmente um arquivo, a configuração do Btrfs será útil, pois posso acessar rapidamente a versão antiga em /snapshots/daily//path. No entanto, se todo o meu servidor falhar, poderei usar um dos backups restic em qualquer um dos servidores para restaurar.



Source link

Postagens Similares

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *