Voltar ao blog
Cloud MigrationInfrastructureMulti-Cloud

Checklist de migração para a cloud: de on-prem para multi-cloud

Checklist de migração para a cloud por fases, com os comandos: descobrir dependências, landing zone, mover os dados, runbook de cutover e trigger de rollback.

P
Davi Nunes
February 15, 2026Atualizado October 30, 202611 min de leitura

Cada item desta checklist termina em algo que podes verificar: uma lista, o resultado de uma consulta, um passo do runbook com um responsável. Os exemplos assumem hosts Linux e PostgreSQL, e um destino com um ou vários fornecedores cloud.

Fase 1: descoberta — o que corre de facto

Ligações: quem fala com quem

As ligações estabelecidas com o processo que as detém e, depois, as portas em escuta:

bash
sudo ss -tnp state established
sudo ss -tlnp

Uma fotografia do momento não apanha o job que se liga às 03:00. Recolhe uma amostra a cada cinco minutos durante uma semana que inclua um fecho de mês:

text
# /etc/cron.d/conn-sample (delete after discovery)
PATH=/usr/sbin:/usr/bin:/sbin:/bin
*/5 * * * * root ss -tnp state established >> /var/tmp/conn-$(hostname).log

Depois conta os pares de processo e peer:

bash
grep -h 'users:' /var/tmp/conn-*.log |
  awk -F'"' '{n = split($1, a, " "); sub(/:[0-9]+$/, "", a[n-1]); print $2, "<->", a[n-1]}' |
  sort | uniq -c | sort -rn | head -50

Cada peer que não consigas identificar é uma dependência por documentar. A amostragem não apanha as ligações curtas, por isso ativa também log_connections no PostgreSQL durante essa semana.

Trabalho agendado

bash
# as root
for u in $(cut -d: -f1 /etc/passwd); do crontab -u "$u" -l 2>/dev/null | sed "s/^/$u: /"; done
cat /etc/crontab; ls /etc/cron.d /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly
systemctl list-timers --all

Cada job precisa de um responsável e de um destino; os que escrevem numa base de dados continuam a escrever na cópia antiga depois do cutover se ninguém os parar.

Endereços hard-coded, montagens, entradas de hosts

bash
sudo grep -rIEno '([0-9]{1,3}[.]){3}[0-9]{1,3}' /etc /opt /srv 2>/dev/null |
  grep -vE ':(127[.]0[.]0[.]1|0[.]0[.]0[.]0)$' | sort -u
findmnt -t nfs,nfs4,cifs
grep -v '^#' /etc/hosts

Acrescenta os diretórios das tuas aplicações e repete a pesquisa com o teu nome de domínio interno. Cada resultado é algo que muda com a migração.

Registos DNS e respetivos TTL

bash
dig +short NS example.com
dig +noall +answer app.example.com @ns1.example.com
dig +short TXT example.com

Consulta o servidor autoritativo: um resolver recursivo mostra o tempo que lhe resta em cache, não o TTL configurado. O TTL de cada registo que vai mudar define com quanta antecedência tens de o baixar. Na resposta TXT, procura entradas SPF ip4: dos relays de email do centro de dados.

Licenças ligadas ao hardware

bash
lscpu | grep -E '^ *(Socket|Core|Thread)'
sudo dmidecode -s system-uuid
ip -br link

O software licenciado por socket ou por core, ou associado a um endereço MAC ou a um host ID, não passa tal e qual para uma VM nova. Lê essas condições antes de escolher a estratégia.

Volume de dados e crescimento

bash
df -hT -x tmpfs -x devtmpfs
sql
SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database ORDER BY pg_database_size(datname) DESC;

Compara com há três meses para ver o crescimento e faz as contas à transferência. Imagina 2 TB por uma ligação de 1 Gbit/s da qual podes usar metade: 16 000 gigabits a 0,5 Gbit/s são 32 000 segundos, quase nove horas antes de qualquer restauro começar. Esse número escolhe a opção de migração de dados da fase 4.

Resultado: uma linha por carga de trabalho: responsável, hosts, peers, jobs, nomes DNS, volume de dados, licenças.

Fase 2: decide por carga de trabalho

Atribui a cada carga de trabalho um único destino:

  • Retire: sem responsável e sem utilizadores reais numa semana de registos de ligações. Desliga-a antes de migrar.
  • Retain: latência para equipamento nas instalações, uma licença que proíbe a cloud ou um fim de vida pouco depois da migração.
  • Rehost: a opção por omissão com uma data de saída fixa. Mesmo sistema operativo e configuração, VM nova.
  • Replatform: troca o componente que mais tempo de operação te custa por um gerido, como PostgreSQL gerido, e não mexas em mais nada.
  • Refactor: só quando a carga de trabalho vai mudar de qualquer forma, nunca como pré-condição para sair.
  • Repurchase: funções commodity como o email, o ticketing ou uma wiki. Verifica primeiro a exportação de dados e onde ficam guardados.
  • Relocate: move a camada de virtualização inteira para uma versão alojada do mesmo hipervisor quando há demasiadas VMs perante uma data de saída fixa. Compra tempo, não poupança.

Num destino multi-cloud, acrescenta a cada linha o fornecedor, a região e o motivo: um fornecedor por carga de trabalho, com uma razão explícita. O nosso guia de estratégia multi-cloud analisa se um segundo fornecedor compensa. As cargas que mais falam entre si no registo da fase 1 partilham vaga e fornecedor.

Uma avaliação gratuita de migração para a cloud começa exatamente aqui: fazemos o inventário de ligações e de cron nos teus hosts, atribuímos a cada carga de trabalho um destino e uma vaga, e dimensionamos a migração de dados face à tua ligação. O nosso serviço de migração para a cloud trata do resto.

Fase 3: a landing zone, antes da primeira carga de trabalho

Nada é migrado enquanto isto não existir em código. Num destino multi-cloud, constrói-a por fornecedor, com um único fornecedor de identidade e um único conjunto de chaves de etiquetas.

  • Contas ou projetos: uma por ambiente, mais uma para os registos de auditoria e outra para a rede partilhada. Nada corre na conta de gestão.
  • Rede: intervalos de endereços que não se sobreponham aos do centro de dados, uma VPN site-to-site de volta a ele, uma ligação privada dedicada só se o tráfego da fase 1 a justificar, e reencaminhamento DNS nos dois sentidos.
  • Identidade: federação a partir do teu fornecedor de identidade por SAML ou OIDC, MFA, nenhuma chave de longa duração para pessoas, roles para os serviços e uma conta break-glass que gera um alerta sempre que é usada.
  • Infraestrutura como código: tudo em Terraform desde o primeiro dia, estado remoto com bloqueio, estado separado por ambiente e por fornecedor, alterações por merge requests revistos. Quando esta camada falta, a consultoria de Terraform é por onde começamos.
  • Guardrails: políticas ao nível da organização que limitam as regiões à UE (residência de dados do RGPD, imposta e não apenas prometida), negam buckets públicos, exigem cifragem em repouso e protegem o registo de auditoria.
  • Logging: registos de auditoria de todas as contas na conta de registos, com retenção explícita; métricas e logs (Prometheus, OpenTelemetry) a funcionar antes da primeira carga de trabalho, como baseline.
  • Etiquetas de custo: owner, cost-center, environment, app, migration-wave, impostas por política. Em minúsculas e com hífenes: pelo menos um grande fornecedor só aceita chaves de etiqueta em minúsculas.

A verificação de sobreposições, incluindo os pools de clientes VPN e as redes de parceiros:

python
import ipaddress
on_prem = ["10.0.0.0/16", "172.16.8.0/22", "192.168.50.0/24"]
cloud = ["10.0.128.0/17", "10.40.0.0/16"]
for a in on_prem:
    for b in cloud:
        if ipaddress.ip_network(a).overlaps(ipaddress.ip_network(b)):
            print("overlap:", a, b)

A landing zone está concluída quando um merge request cria uma conta com rede, identidade, guardrails e logging, e ninguém abre uma consola.

Fase 4: move os dados

Dump e restore

A indisponibilidade é dump, transferência, restore e verificação. Ensaia numa cópia e cronometra; se couber na janela com margem, não precisas de mais.

bash
pg_dump -Fd -j 4 -f /backup/appdb appdb
rsync -a /backup/appdb/ migrate@TARGET_HOST:/restore/appdb/
pg_restore -h NEW_DB_HOST -U app -d appdb -j 4 --no-owner --no-privileges /restore/appdb

As bases de dados geridas normalmente não te dão superutilizador; daí as flags de propriedade.

Replicação e um cutover curto

Quando a cópia demora mais do que a janela, replica com antecedência e faz o cutover em minutos. A replicação lógica do PostgreSQL funciona entre versões major:

sql
-- Source: needs wal_level = logical (changing it requires a restart)
CREATE PUBLICATION migration FOR ALL TABLES;

-- Target: load the schema first with pg_dump --schema-only, then
CREATE SUBSCRIPTION migration
  CONNECTION 'host=10.0.2.7 dbname=appdb user=replicator password=REPLACE_ME'
  PUBLICATION migration;

As alterações de esquema não são replicadas, por isso o congelamento tem de cobrir o DDL. Os valores das sequências são acertados no cutover (passo 5 do runbook). E, assim que uma tabela sem chave primária nem replica identity é publicada, os UPDATE e DELETE sobre ela falham na origem, e isso parte a produção. Encontra primeiro essas tabelas:

sql
SELECT n.nspname, c.relname FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r' AND n.nspname NOT IN ('pg_catalog', 'information_schema')
  AND NOT EXISTS (SELECT 1 FROM pg_constraint p WHERE p.conrelid = c.oid AND p.contype = 'p');

Os ficheiros levam duas passagens: uma cópia em massa dias antes e um delta final durante o congelamento.

bash
rsync -aHAX --numeric-ids /srv/data/ migrate@TARGET_HOST:/srv/data/
rsync -aHAX --numeric-ids --delete /srv/data/ migrate@TARGET_HOST:/srv/data/

Verifica a cópia

Conta as linhas de todas as tabelas dos dois lados. Nas tabelas que guardam dinheiro ou identidades, compara um hash:

sql
SET TimeZone = 'UTC';
SELECT count(*), md5(string_agg(o::text, '|' ORDER BY o.id)) FROM orders o;

Se as duas sessões não tiverem o mesmo fuso horário, os timestamps são impressos de forma diferente e os hashes nunca coincidem. Nas tabelas grandes, faz por intervalos de id. Para os ficheiros, um dry run com checksums lista todas as diferenças:

bash
rsync -aHAXnci --delete /srv/data/ migrate@TARGET_HOST:/srv/data/

Quanto tempo fica aberto o caminho de rollback

Enquanto as escritas não reabrirem do lado novo, o rollback é uma alteração de DNS sem perda de dados. A partir daí, o lado antigo fica para trás. Ou configuras replicação inversa no cutover (removes a subscrição de ida, publicas a partir da base de dados nova e subscreves a antiga com copy_data = false), ou acordas por escrito que um rollback tardio implica voltar a introduzir dados à mão. Fecha a janela com um evento de negócio, como a primeira faturação de fim de mês a correr bem do lado novo.

Fase 5: o runbook de cutover

Antes do dia

  • T-14 dias: ensaio completo num clone, rollback incluído, com cada passo cronometrado.
  • Um TTL antigo mais margem antes: baixa para 300 segundos todos os registos que mudam e confirma com dig contra o servidor autoritativo. Um registo a 86400 precisa de pelo menos um dia; uma semana é mais seguro.
  • T-3 dias: congelamento de alterações dos dois lados: nem deploys, nem alterações de esquema ou de configuração.
  • T-1 dia: reunião de go/no-go. Ensaio aprovado, lag quase a zero, último backup testado com um restauro, rollback escrito e uma pessoa identificada que decide o rollback.

No dia, por ordem

  1. 1Ativa a página de manutenção e interrompe as escritas da aplicação.
  2. 2Interrompe o cron e os timers nos hosts antigos: systemctl stop cron (ou crond, conforme a distribuição) e systemctl stop para cada unidade .timer do teu inventário da fase 1.
  3. 3Na origem, espera que o lag chegue a zero: SELECT application_name, pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) FROM pg_stat_replication;
  4. 4Corre o delta final do rsync.
  5. 5Acerta cada sequência, por exemplo SELECT setval(pg_get_serial_sequence('orders', 'id'), (SELECT max(id) FROM orders));, e depois corre as consultas de verificação.
  6. 6Faz os smoke tests do lado novo com o hostname real antes de mexer no DNS (comando abaixo).
  7. 7Muda o DNS ou o load balancer e repete os smoke tests a partir do exterior.
  8. 8Decide go ou no-go à hora fixada de antemão: o go reabre as escritas, o no-go executa o rollback.
bash
curl -sS -o /dev/null -w '%{http_code} %{time_total}' --resolve app.example.com:443:203.0.113.10 https://app.example.com/healthz

Critérios de go/no-go

  • As contagens e os hashes coincidem, e todos os smoke tests passam.
  • A taxa de erros e a latência p95 estão dentro do intervalo medido no lado antigo na semana anterior.
  • Nenhum erro de replicação ou de aplicação desde a mudança.

Smoke tests

  • Inicia sessão, lê um registo conhecido, cria e apaga um registo de teste.
  • Corre um job em segundo plano; envia um email e confirma que passa no SPF.
  • Uma chamada por integração externa: sandbox de pagamentos, SFTP de parceiros, webhooks.

O trigger de rollback

Uma frase, acordada antes do dia. Por exemplo: "Se algum critério de go/no-go falhar e não estiver resolvido às 02:00, ou se a taxa de 5xx ficar acima da baseline antiga durante 15 minutos nas primeiras 24 horas, fazemos rollback. Quem decide é o responsável pela migração; não se discute na chamada."

Mantém o lado antigo a responder ou a redirecionar durante alguns dias; alguns resolvers e clientes guardam em cache para lá do TTL.

Fase 6: depois da migração

  • Desativa com método. Em cada host antigo, sudo ss -tn state established '( sport = :5432 )' lista os clientes que ainda chegam à base de dados antiga; cada um é uma dependência que escapou. Mantém o host desligado duas semanas antes de o apagar, revoga as credenciais, túneis, regras de firewall e registos DNS, e cancela as licenças. Um host esquecido deixa de receber patches mas continua acessível, e os cron jobs dele continuam a correr.
  • Redimensiona com dados reais. Depois de algumas semanas que incluam um fecho de mês, dimensiona para o p95 observado mais margem, não para a alocação on-prem. Os descontos por compromisso vêm depois do rightsizing.
  • Orçamentos e etiquetas. Alertas de orçamento por conta e uma lista semanal de recursos sem etiqueta.
  • Testa o backup e a recuperação de desastres no novo ambiente. Um job de backup a verde não é um teste. Restaura uma base de dados numa instância nova e cronometra, guarda cópias noutra conta e noutra região, e compara o tempo de recuperação e a perda de dados medidos com o que o negócio aprovou. O nosso trabalho de backup e recuperação de desastres começa por esse restauro.

Erros comuns e como os apanhar cedo

  • Intervalos de endereços sobrepostos: corre a verificação de sobreposições antes de existir a primeira rede.
  • O consumidor esquecido: uma semana de amostragem com ss, os registos de ligações da base de dados e a verificação com ss depois do cutover.
  • Allowlists presas aos IP antigos: firewalls de parceiros, fornecedores de pagamentos, peers SFTP, o teu próprio registo SPF. Faz a lista dos teus IP de saída na fase 1 e pergunta logo aí a cada responsável de integração.
  • Um par muito conversador dividido pela VPN: a aplicação na cloud e a base de dados ainda on-prem. Multiplica o round trip pelas consultas de cada página: imagina 200 consultas com um round trip de 15 ms, o que soma 3 segundos.
  • MTU do túnel: ping -M do -s 1472 CLOUD_HOST a partir do centro de dados envia um pacote de 1500 bytes que não pode ser fragmentado. Se falhar, baixa o tamanho até passar e ajusta o MTU ou o MSS clamping em conformidade; caso contrário, as respostas grandes ficam penduradas enquanto os pedidos pequenos funcionam.
  • Um rollback por ensaiar: se o ensaio o deixou de fora, não tens rollback.

Antes da primeira vaga, a avaliação gratuita de migração para a cloud cobre o que falha em silêncio: o mapa de dependências tirado dos teus próprios hosts, as verificações de intervalos de endereços e de TTL, as contas da migração de dados para a tua maior base de dados, e um rascunho do runbook da primeira vaga com critérios de go/no-go e um trigger de rollback.