Transmita arquivos tar entre servidores sem armazenamento local
Para copiar um diretório entre dois servidores, encadeie um comando tar no servidor de origem, por
meio do SSH, a um comando tar no servidor de destino. O arquivo tar passa pelo seu computador sem
ser salvo localmente. O destino precisa de espaço para os arquivos extraídos, mas nenhum dos
servidores precisa de espaço para um arquivo tar intermediário.
O caminho é servidor de origem → seu computador → servidor de destino. Seu computador transporta todo o fluxo e precisa permanecer conectado; os servidores não precisam de acesso SSH um ao outro. Se os bytes precisarem contornar totalmente o seu computador, execute a transferência em um host com a conectividade e as credenciais necessárias para acessar os servidores.
O SSH criptografa a comunicação com cada servidor. O arquivo tar é descriptografado no pipe local e criptografado novamente para o destino, por isso use um computador confiável. Não é necessário adicionar uma senha do OpenSSL a este pipeline para criptografar o transporte.
Prepare a origem e o destino
Este exemplo copia app-data do diretório home da conta de origem para um novo diretório app-data.incoming
no diretório home da conta de destino. Substitua source-server e
destination-server pelos seus aliases SSH ou endereços user@host. Ajuste os caminhos nos dois
scripts se os seus dados estiverem em outro lugar.
Você precisa do Bash no computador que executa os scripts e de acesso via OpenSSH a duas contas Linux
com GNU tar, GNU find e GNU sha256sum. A conta de origem precisa conseguir ler todos os arquivos; a
conta de destino precisa conseguir criar o diretório de recebimento e o conteúdo dele. Configure a
autenticação baseada em chaves, carregue qualquer chave criptografada no seu agente SSH e verifique
as chaves de host dos dois servidores antes de começar. Os comandos usam
BatchMode=yes, então eles falham em vez de pedir
senhas ou confirmação da chave de host durante uma transferência.
Interrompa as gravações no diretório de origem até que a cópia e a verificação terminem, ou leia a partir de um snapshot consistente. Em uma aplicação web, isso inclui uploads e tarefas em segundo plano. Use o procedimento de backup do banco de dados para os dados dele: copiar arquivos de um banco de dados em execução com tar não gera um backup consistente do banco. Estes comandos copiam arquivos; a configuração da aplicação e a migração do tráfego são etapas separadas.
Os exemplos foram testados com Bash 5.1.16, GNU tar 1.34 e OpenSSH 8.9p1 no Linux. A etapa de checksum usa GNU find e coreutils; ela não é uma receita de comandos para macOS.
Transmita para um novo diretório
Salve isto como transfer.sh no seu computador e execute com bash transfer.sh:
#!/usr/bin/env bash
set -euo pipefail
ssh -T -o BatchMode=yes source-server 'test -d app-data'
ssh -T -o BatchMode=yes destination-server 'mkdir app-data.incoming'
ssh -T -o BatchMode=yes source-server 'tar -cf - -C app-data .' |
ssh -T -o BatchMode=yes destination-server 'tar -xf - -C app-data.incoming'
printf 'Transfer completed; verify app-data.incoming before using it.\n'
O mkdir simples falha propositalmente se o diretório de recebimento já existir. Escolha um novo
caminho para uma nova tentativa, ou inspecione e remova antes o diretório de uma transferência que
falhou. Isso evita que o exemplo extraia o conteúdo por cima de um diretório de aplicação existente.
Entendendo os fundamentos do streaming com tar
Em tar -cf -, c cria um arquivo tar e f - o envia para a saída padrão. Em tar -xf -, x
extrai o arquivo tar lido da entrada padrão. Essas são as mesmas operações comumente escritas como
tar cf - e tar xf -.
-C app-data muda o diretório de trabalho do tar
antes de ele adicionar . ao arquivo tar. Por isso, os membros têm nomes como ./uploads/photo.jpg,
incluindo dotfiles, em vez de um prefixo de diretório que você precisaria remover depois. O -C
da extração coloca esses membros em app-data.incoming. Ele não cria esse diretório.
-T desativa a alocação de pseudoterminal do SSH para que a conexão possa transportar dados
binários. pipefail faz o pipeline falhar se
qualquer um dos comandos SSH falhar; em seguida, set -e interrompe o script antes da mensagem de
conclusão. Sem pipefail, um processo tar na origem pode falhar depois de produzir um arquivo tar
extraível enquanto o destino termina com sucesso.
O SSH retorna o status de saída do comando remoto, o que permite
que o Bash detecte essa falha.
Uma execução bem-sucedida imprime a mensagem de conclusão e deixa a árvore copiada em app-data.incoming. Uma
execução com falha pode deixar arquivos parciais ali. Nem um status de saída zero nem a mensagem de
conclusão provam que uma origem em alteração foi copiada de forma consistente.
Verifique os arquivos copiados
Mantenha a origem inalterada e salve isto como verify.sh. Execute bash verify.sh depois da transferência:
#!/usr/bin/env bash
set -euo pipefail
ssh -T -o BatchMode=yes source-server \
'cd app-data && find . -type f -exec sha256sum -- {} +' |
ssh -T -o BatchMode=yes destination-server \
'cd app-data.incoming && sha256sum --check --strict -'
printf 'Regular-file checksums match.\n'
Isso transmite uma lista de checksums entre os servidores, novamente sem salvá-la localmente. O GNU
sha256sum --check imprime
./filename: OK para cada arquivo correspondente e falha para arquivos ausentes ou divergentes. O GNU
find -exec … {} + também retorna
falha se um comando de checksum falhar, então o lado de origem deste pipeline também é verificado.
Espere a mensagem final somente quando os dois lados tiverem sucesso.
A verificação lê novamente todos os arquivos regulares nos dois servidores. Ela pressupõe pelo menos um arquivo regular e verifica o conteúdo dos arquivos, não os destinos de links simbólicos, diretórios vazios, permissões, propriedade ou arquivos extras no destino. Esta é uma receita de cópia de diretório, não um backup completo do sistema: ela não solicita a preservação de ACLs nem de atributos estendidos. Confirme os metadados de que sua aplicação precisa antes de apontá-la para o diretório copiado.
Ajuste a transferência quando necessário
Para exibir o progresso, instale pv no seu computador e insira-o no pipeline de transferência:
ssh … | pv | ssh …. Mantenha o pipeline dentro do script com pipefail. O
manual do pv descreve a contagem de bytes, o
tempo decorrido e a taxa de transferência que ele exibe. Sem um tamanho total conhecido do fluxo, ele
não consegue fornecer uma porcentagem de conclusão ou um ETA significativos. A saída dele mede os
bytes que passam pelo pipe local, não arquivos verificados.
Se o acesso exigir um bastion host, adicione -J bastion-host a cada comando SSH nos dois scripts. Configure
também a autenticação e a verificação da chave de host para esse host.
ProxyJump se conecta ao host-alvo por meio do
bastion; o pipe entre os dois comandos SSH continua sendo executado no seu computador. As
configurações de identidade e porta do jump host devem ficar na sua configuração do SSH, porque as
opções de linha de comando geralmente se aplicam ao host-alvo final.
Para dados compressíveis em uma conexão limitada, troque tar -cf - por tar -czf - e
tar -xf - por tar -xzf -. Isso usa a
opção --gzip do tar e
exige gzip nos dois servidores. Ela consome tempo de CPU e pode trazer pouco ganho com vídeos,
imagens ou pacotes de arquivos já comprimidos. Faça medições com seus arquivos e sua conexão antes de
presumir que será mais rápido.
Solução de problemas comuns
- Permissão negada ou disco cheio: Leia o stderr dos dois comandos SSH. Verifique a permissão de leitura na origem, as permissões no destino, o espaço livre e os inodes disponíveis. Corrija a causa e comece com um diretório de recebimento novo; não use uma cópia parcial.
- “File changed as we read it”: Interrompa o processo que está gravando ou use um snapshot e, em seguida, repita a transferência e a verificação de checksum. Suprimir o aviso não torna consistente uma cópia feita com os dados em uso.
- Erros inesperados no arquivo tar: Os arquivos de inicialização do shell remoto não devem
imprimir saudações no stdout para comandos não interativos. Essa saída entraria no fluxo do
arquivo tar. Mantenha os diagnósticos no stderr; não misture o stderr ao pipe com
2>&1ou|&. - Conexão interrompida: Este fluxo tar não tem operação de retomada.
tmuxouscreenpodem manter um processo em execução quando você se desconecta do terminal dele, mas não conseguem reparar uma conexão SSH interrompida no pipeline de transferência. Recomece em um diretório novo e verifique-o antes de usá-lo.
