Copyrigh © 2016 by Antonio Augusto DE CINTRA BATISTA
<antonio.a.c.batista@gmail.com>
10/11/2016: primeira versão
O conteúdo deste documento é diponibilizado pelo autor sob a
licença GNU Free Documentation License
1.3
Revisões:
Motivações:
Esta figura representa o cenário onde se irá se desenrolar a clonagem.
Vamos admitir:
As etapas deste procedimento, numeradas de 1 a 4, e suas sub-etapas, devem ser seguidas segundo o fluxograma abaixo. Se você já adquiriu experiência neste procedimento, provavelmente verá que é recomendado planejar melhor seu caminho de ação antes de começar a agir. Este fluxograma pode auxiliar a se ter uma visão global das etapas e sub-etapas, e por quais delas você deverá passar. No fluxograma, as elipses representam o número de uma (sub)etapa e os losangos representam a decisão que deve ser tomada entre as alternativas disponíveis.
Vamos considerar 2 casos bem distintos com relação à máquina A:
Poder gerar o snapshot "a quente" é talvez a melhor maneira de simplificar o procedimento. Deve ser gerado um snapshot da máquina A, para cada volume necessário. Por exemplo, se os diretórios / e /var estão em partições diferentes (e ambos formatados como BTRFS), os snapshots destes volumes podem ser gerados como se segue:
# Entrar como root na máquina A (IP 1.3.5.7):
ssh -l root 1.3.5.7
# Criar uma pasta para os snapshots, em cada volume:
[ -e /.snapshot.btrfs ] || mkdir /.snapshot.btrfs
[ -e /var/.snapshot.btrfs ] || mkdir /var/.snapshot.btrfs
# Fazer os snapshots:
btrfs subvolume snapshot / /.snapshot.btrfs/maquinaQueSeraClonada-volume_root-$(date +%Y-%m-%d_%H.%M.%S)
btrfs subvolume snapshot /var /var/.snapshot.btrfs/maquinaQueSeraClonada-volume_var-$(date +%Y-%m-%d_%H.%M.%S)
Pular parar o passo 2, adiante.
Digamos que iremos criar o arquivo maquinaQueSeraClonada.tar.gz, que será armazenado, num primeiro momento, na máquina B, para ser posteriormente clonada em outras máquinas físicas ou virtuais. Este arquivo deverá representar uma cópia plenamente funcional e consistente da máquina A e, para isto, devemos eliminar alguns arquivos e pastas inúteis ao processo e, muito importante, devemos derrubar todos os processos que possam modificar, ou tornar inconsistentes, os arquivos importantes.
Para os efeitos do presente procedimento, arquivo importante será definido como um arquivo que deverá pertencer ao archive gerado pelo comando tar, para que o processo de clonagem possa ser bem sucedido. É uma definição pouco determinística, a priori; ou seja, ela não permite a qualquer pessoa olhar para um arquivo e dizer, a priori, se este arquivo específico é ou não é importante. Assim, um arquivo será julgado importante pelo administrador de sistemas, segundo a sua experiência pessoal, ou porque o processo de clonagem não deu certo e, então, aconteceu o aprendizado de que um determinado arquivo era importante.
Para facilitar a escolha de quais são os arquivos importantes, na etapa 1b.2 abaixo é sugerido o conteúdo do arquivo /root/FILES, o qual especifica quais são as pastas inúteis para este procedimento. Ou seja, todas as outras pastas são importantes, a menos que o administrador de sistemas tenha algum motivo para eliminar alguma delas: por exemplo, uma pasta de backup montada via NFS (não faz sentido incluir esta pasta, visto que a mesma poderá ser montada via protocolo de rede NFS em outra máquina).
Antes de se iniciar o comando tar (etapa 3 abaixo), devemos parar todos os processos que possam modificar os arquivos importantes durante o processo de execução do comando tar. No cenário da figura acima, o processo de clonagem está sendo realizado à distância, através de um terminal aberto via ssh, então é claro que não vamos derrubar o daemon do ssh. Segue abaixo um exemplo, o qual deve ser adaptado para o seu caso específico; a título de esclarecimento deste exemplo, ele foi diversas vezes executado para clonar VM de PABX rodando ASTERISK, MySQL, DHCP (para fornecer endereço IP aos telefones), TFTP (para provisionamento automático dos aparelhos de telefone IP), SMTP, HTTP/HTTPS, SNMP, SIP, NTP
# Entre como root na máquina A (IP 1.3.5.7):
ssh -l root 1.3.5.7
# Verifique quais os serviços de rede estão rodando:
lsof -i udp:67-69,123,5060-5062,161 -i tcp:80,443,3306,25
# Verificar quais os processos estão acessando o /var:
lsof /var
# Para saber o nome dos processos para utilizar nos comandos "stop" de serviços,
# pode ser mais fácil ir para a pasta de startup correspondente ao runlevel atual:
cd /etc/rc$(runlevel |cut -f2 -d' ').d
# liste os softlinks para os arquivos de startup:
ls -l
# Pare os serviços (apenas os que forem necessários; o ssh deve continuar), na ordem inversa
# em que eles foram iniciados.
# Vamos supor, pela saída do comando ls acima,
# que os últimos softlinks correspondem aos últimos serviços que foram iniciados.
# Mais claramente, o comando ls acima listou fail2ban por último, então vamos começar derrubando
# este serviço.
# CUIDADO para não derrubar um serviço essencial para que você possa continuar trabalhando à distância.
service fail2ban stop
service apache2 stop
service ntp stop
service postfix stop
service atftpd stop
service asterisk stop
service mysql stop
service rsyslog stop
service cron stop
service atd stop
# Verificar se existe ainda algum processo acessando o /var:
lsof /var
# Avaliar se já se pode considerar que a máquina está num estado bem estável para ser
# copiada (clonada).
No Debian 8, o sistema de startup deixou de ser o puramente SYSV; ele é agora o systemd, que possui diversos recursos bem interessantes. Neste caso, ao invés de parar os serviços com o comando
service <nome-do-serviço> stop
recomenda-se utilizar comandos do próprio systemd:
systemctl stop <nome-do-serviço>
systemctl status <nome-do-serviço> # para ver o status atual do serviço
Em sistemas muito antigos (este documento foi escrito em 2016), nem o comando systemctl e nem mesmo o service talvez não funcionem, sendo necessário executar:
/etc/init.d/<nome-do-serviço> stop
Vamos criar um arquivo texto: /root/FILES. Cada linha deste arquivo representará um arquivo ou uma pasta a ser ignorada pelo futuro comando tar. ATENÇÃO: Certifique-se de que as pastas listadas abaixo podem mesmo serem TODAS ELAS ignoradas (por exemplo, em alguns sistemas a pasta /mnt contém dados ou programas que não podem faltar na clonagem).
/dev
/lost+found
/mnt
/proc
/run
/sys
/tmp
Salve este arquivo. Ele será utilizado pelo comando tar mais para frente.
O comando tar, para a geração do archive, será executado pela CPU da máquina A, a pedido de um comando ssh, que por sua vez será disparado pelo administrador e executado na máquina B (conforme as etapas 3a ou 3b abaixo). Supõe-se que você está fazendo tudo isto à distância, via ssh, o qual irá disparar a execução remota do comando tar e irá armazenar a saída deste comando localmente (ou seja, o archive será armazenado na máquina B do administrador).
Para que a máquina B tenha autorização de entrar como root, via ssh, na máquina A, acrescente a chave pública do seu usuário da máquina B ao arquivo /root/.ssh/authorized_keys da máquina A.
Como na etapa 1 acima, vamos considerar 2 casos bem distintos com relação à máquina A:
Na máquina A, verifique qual é o nome da pasta onde está o snapshot gerado na etapa 1a acima. Vamos supor que seja maquinaQueSeraClonada-volume_root-2016-11-07_18.37.30 e maquinaQueSeraClonada-volume_var-2016-11-07_18.37.30.
Na máquina B do administrador, execute o seguinte comando:
# comando ssh executado na máquina B do administrador, para entrar na máquina A (cujo IP é 1.3.5.7):
ssh -l root 1.3.5.7 'tar -czpf - /.snapshot.btrfs/maquinaQueSeraClonada-volume_root-2016-11-07_18.37.30' \
| dd of=maquinaQueSeraClonada-volume_root.tar.gz
ssh -l root 1.3.5.7 'tar -czpf - /var/.snapshot.btrfs/maquinaQueSeraClonada-volume_var-2016-11-07_18.37.30' \
| dd of=maquinaQueSeraClonada-volume_var.tar.gz
Certifique-se de que os serviços da máquina A continuam em "stop" (consulte etapa 1b.1 acima):
# Entrar como root na máquina A (IP 1.3.5.7):
ssh -l root 1.3.5.7
# certificar-se de que os serviços de rede abaixo, considerados usuais da máquina A
# (e isto varia de máquina para máquina), não aparecem listados por este comando:
lsof -i udp:67-69,123,5060-5062,161 -i tcp:80,443,3306,25
lsof /var
O arquivo /root/FILES é o que foi gerado na etapa 1b.2 acima. Este arquivo deverá estar na máquina A. Antes de executar o comando abaixo, confira o conteúdo deste arquivo e observe se ele parece lhe satisfazer. Na máquina B do administrador, execute o seguinte comando:
# 1.3.5.7 = IP da máquina A
ssh -l root 1.3.5.7 'tar -X /root/FILES -czpf - /' | dd of=maquinaQueSeraClonada.tar.gz
Vamos detalhar abaixo 2 casos distintos para a máquina C: 4.1 e 4.2.
Vamos supor que a máquina C tem 2 discos (sda e sdb), que ela deu boot pelo sda, e que nós vamos instalar o clone no disco sdb. É conveniente que ela possua 2 discos, para que exista um disco totalmente livre para receber a clonagem.
Aqui também vamos ter 2 casos distintos: 4.1.1, ou 4.1.2, abaixo.
Se este não é o caso, pule para a etapa 4.1.2 abaixo.
Vamos supor que a máquina C deu boot pelo sda, e nós vamos instalar o clone no disco sdb. Acontece que, algumas vezes, o disco sdb está em pleno uso (pelo /var, por exemplo); se este não é o seu caso, ignore a etapa 4.1.1.1 abaixo.
Vamos supor que a partição /dev/sdb1 está ocupada com o /var. Faremos basicamente o seguinte: vamos copiar toda a pasta /var dentro de uma pasta /var.1 do disco sda. Antes de fazer isto, certifique-se de que há espaço suficiente no sda para receber todo o conteúdo do /var:
# espaço ocupado pelo /var:
du -sh /var
# espaço ocupado e livre do disco sda e dos diversos volumes montados:
df -h
Mas, como o /var é uma partição que tipicamente se modifica sistematicamente, precisamos torná-la o mais estática possível antes de começar a cópia. Para isto, inspire-se no procedimento da etapa 1b.1 acima. Após isto, execute o seguinte:
# derrube todos os serviços que possam modificar os arquivos importantes (consultar item 1b.1 acima)
# crie a pasta /var.1 no disco sda:
mkdir /var.1
# copie todo o /var para o disco sda (com os discos que tenho usado, isto pode demorar,
# tipicamente, de 20 a 40 segundos por cada GB):
cp -a /var/* /var.1/.
# verifique como ficaram os espaços livre e ocupado, e avalie se está como o esperado:
du -sh /var.1
du -sh /var
df -h
Se tudo está correndo como esperado até aqui, chegou a hora de modificar o /etc/fstab para que o novo reboot use o /var.1 como /var. Para isto, edite o /etc/fstab da máquina C, e faça o seguinte:
# linha a ser acrescentada ao /etc/fstab da máquina C
/var.1 /var none bind 0 0
Certifique-se de que tudo foi digitado corretamente. A experiência mostra que a preguiça é realmente amiga do inventor e do inovador, mas é nossa inimiga aqui, nesta hora; ou seja, execute um
clear ;blkid ;echo ;cat /etc/fstab
e leia com atenção o conteúdo do fstab.
Se tudo foi digitado corretamente, chegou a hora de um reboot.
shutdown -r now
Após este boot, o /var não será mais do sdb (pois foi comentada a linha do fstab que montava o /var no /dev/sdb1); e a pasta /var.1 do sda se tornará invisível e inacessível, pois será vista pelo sistema como sendo /var. Pule para a etapa 4.1.3 abaixo.
Há casos em que a máquina física não tem um Linux pré-instalado onde possamos entrar via ssh e fazer o nosso trabalho de clonagem à distância; há, também, casos em que houve um problema qualquer e não é mais possível contar com o boot pelo disco da máquina C; ou, simplesmente, há uma pessoa disponível no local da máquina C, a qual poderá dar um boot nesta máquina a partir de um pendrive, e esta solução é vista como a mais conveniente porque permite uma intervenção à distância num sistema ISO "novo" e de boa qualidade.
A idéia é gravar, no pendrive, um ISO cujo sistema permita, uma vez terminado o boot, o acesso via ssh; e que contenha um conjunto mínimo de utilitários de administração para poder clonar a máquina A a partir do archive (arquivo .tar) presente na máquina B.
Será utilizado um ISO de Debian Live 7, o qual disponibiliza, após o boot da máquina C, o acesso via ssh e algumas ferramentas úteis de administração de sistema.
# Baixar o ISO do Debian Live 7
# Com o navegador, acessar http://cdimage.debian.org/mirror/cdimage/archive/7.11.0-live/
# e escolher a arquitetura de apropriada para a máquina C. Aqui, vamos supor que a
# arquitetura de 64 bits (amd64) é apropriada, então, baixe o ISO da imagem rescue correspondente:
wget http://cdimage.debian.org/mirror/cdimage/archive/7.11.0-live/amd64/iso-hybrid/debian-live-7.11.0-amd64-rescue.iso
# Os ISOs atuais do Debian ao serem gravados diretamente no pendrive USB, já estão prontos para o boot.
# Assim, procure qual é o dispositivo correspondente ao seu pendrive e grave nele.
fdisk -l
# este último comando é para verificar qual é o dispositivo. Vamos supor que o pendrive seja o /dev/sdc e
# vamos gravar o ISO nele:
dd if=debian-live-7.11.0-amd64-rescue.iso of=/dev/sdc
Terminado o comando dd acima, você já pode testar o boot com o seu pendrive. Em alguns casos, será necessário instalar um pacote adicional para que o Linux possa se comunicar com a placa de rede da máquina C. Lembremos que, por hipótese de nosso cenário de exemplo, você precisará entrar remotamente na máquina C via ssh. Digamos que existe um pacote de Debian com nome firmware-da-placa-de-rede.deb, então você precisa gravar este pacote em algum pendrive para instalá-lo posteriormente após o boot do Debian Live 7.11.
A pessoa que estará disponível localmente, para acesso ao console da máquina C, deverá insirir o pendrive de boot numa porta USB da máquina C. Verifique como deverá ser feito para que esta máquina escolha dar o boot pelo pendrive e, após terminado o boot, a pessoa local deverá preparar a máquina C para que você possa acessá-la remotamente via ssh, seguindo o procedimento abaixo.
# Bootar a máquina C pelo pendrive.
# Se o Debian live pedir usuário e senha, entrar como user: user e password: live
# Assumir o controle como usuário root:
sudo su -
# Verificar se deu mesmo o boot pelo iso.
cat /etc/debian_version
df -h
cat /etc/os-release
# Atribuir uma senha para o root:
passwd
# Caso seja necessário, inserir o pendrive com o firmware da placa de rede e, em seguida, instalar:
dpkg -i firmware-da-placa-de-rede.deb
# Limitar acesso SSH com iptables
# Vamos supor que o endereço IP de sua máquina B é 1.2.3.4
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 1.2.3.4 -j ACCEPT
# Vamos supor que a máquina C tenha 2 interfaces ethernet:
iptables -A INPUT -i eth0 -j DROP
iptables -A INPUT -i eth1 -j DROP
iptables -A INPUT -j ACCEPT
# Colocar o IP da máquina C (vamos supor que seja 5.6.7.8/24) e de seu default gateway (5.6.7.10):
ifdown eth0
ifdown eth1
ip a add 5.6.7.8/24 dev eth0
ip link set dev eth0 up
ip r add default via 5.6.7.10 dev eth0
# Configurar resolução de DNS (vamos supor que o servidor DNS seja o 5.6.7.1):
echo "nameserver 5.6.7.1" > /etc/resolv.conf
# Baixar a sua chave ssh pública:
cd /root
mkdir .ssh
cd .ssh
wget http://seu-site/chaves/sua-chave.pub
mv sua-chave.pub authorized_keys
Pronto. Feito isto, a máquina C deverá estar pronta para que você possa acessá-la via ssh. Continue com a etapa 4.1.3 abaixo.
Entre na máquina C via ssh e prepare o disco sdb. Vamos exemplificar, logo abaixo, com um esquema genérico de particionamento de disco.
# Entre como root na máquina C:
ssh -l root 5.6.7.8
# Entre no utilitário fdisk e particione o disco sdb:
fdisk /dev/sdb
# Vamos supor que sdb1 será partição de swap (tipo 82 do fdisk) e sdb2 conterá todo o sistema
# numa partição tipo Linux (tipo 83 do fdisk).
# Uma vez terminado, salve as alterações no disco sdb (comando w do fdisk) e saia do fdisk (comando q).
Formate as partições e monte a partição sdb2:
mkswap /dev/sdb1
# vamos supor que ambas, a máquina hipervisora e a máquina C (clone), suportam BTRFS (caso contrário,
# formate-a como ext4 ou ext3):
mkfs.btrfs --label 'root partition' /dev/sdb2
# monte o sdb2:
mkdir /mnt/r ;mount /dev/sdb2 /mnt/r
# Na máquina B de administrador, copie o archive para a máquina C:
scp maquinaQueSeraClonada.tar.gz root@5.6.7.8:/mnt/r/.
# Entre como root na máquina C (caso já não esteja dentro dela):
ssh -l root 5.6.7.8
# Expanda o archive copiado:
cd /mnt/r
tar xzf maquinaQueSeraClonada.tar.gz
# Crie as pastas que foram excluídas na geração do archive maquinaQueSeraClonada.tar.gz
# (desnecessário caso a imagem tenha sido gerada a partir de um snapshot do BTRFS, ou seja,
# se executou a etapa 1a acima) :
mkdir /mnt/r/dev
mkdir /mnt/r/mnt
mkdir /mnt/r/proc
mkdir /mnt/r/run
mkdir /mnt/r/sys
mkdir /mnt/r/tmp
# As permissões default destas pastas é 755, com as seguintes exceções que precisam ser colocadas especificamente:
chmod 1777 /mnt/r/tmp
# Se houver problema de espaço no disco da máquina C, a expansão poderá ser feita sem que se faça a cópia antes.
# Ou seja, podemos enviar a expansão do archive para STDOUT da sua máquina B e direcioná-lo para STDIN de um
# comando tar que será executado na máquina C. Em termos mais práticos, execute o seguinte comando na sua máquina B:
cat maquinaQueSeraClonada.tar.gz |ssh -l root 5.6.7.8 'tar -C /mnt/r -xzf -'
# Entre como root na máquina C (caso já não esteja dentro dela):
ssh -l root 5.6.7.8
# verifique se foi expandido como esperado:
cd /mnt/r
ls -la
# Entre como root na máquina C (caso já não esteja dentro dela):
ssh -l root 5.6.7.8
cd /mnt
# certifique-se de que sdb2 está montado em /mnt/r:
df -h
# verifique se foi expandido como esperado:
ls -la /mnt/r
# prepare o ambiente para poder dar um chroot em /mnt/r
mount -o bind /dev /mnt/r/dev
mount -t sysfs none /mnt/r/sys
mount -t proc none /mnt/r/proc
# para ajudar a comparar e diferenciar o ambiente atual da máquina C com
# o ambiente chroot, observe a saída deste comando:
df -h
alias
#
chroot /mnt/r
# execute novamente e compare:
df -h
alias
# ATENÇÃO: a princípio, a única tela de terminal com ambiente chroot é
# esta onde você acaba de executar o comando chroot. Portanto, se
# você possuir outras telas de login na máquina C, CUIDADO para executar
# os comandos abaixo APENAS NESTA TELA DE LOGIN DO CHROOT.
# remova a definição original das interfaces de rede;
# caso contrário, o que era eth0 passará a ser eth2 após o boot
# da máquina clonada (por hipótese, consideramos acima que a máquina C possui
# 2 interfaces ethernet: eth0 e eth1).
rm /etc/udev/rules.d/70-persistent-net.rules
# modifique as configurações de rede, caso a máquina clonada precise disto
# tipicamente, estes são os arquivos que você poderá desejar modificar:
# /etc/network/interfaces
# /etc/hosts
# /etc/hostname
# /etc/mailname
# /etc/resolv.conf
# modifique seu script de firewall iptables, se necessário
# Atualize o /etc/fstab. Se são utilizados UUID para se referir
# às partições (o que é recomendado), verifique quais são os
# UUID de sdb1 (swap) e sdb2 (Linux):
blkid
# e modifique /etc/fstab atualizando os UUID observados pela saída do comando acima.
# crie novas chaves ssh para a nova máquina, caso seja
# conveniente que o seu ssh cliente a perceba como uma máquina diferente
# da máquina A original:
rm -f /etc/ssh/ssh_host*
ssh-keygen -A
# crie novas chaves para os usuários desta máquina, caso isto
# seja conveniente (por exemplo, faça o seguinte para o root):
rm -f /root/.ssh/id*
ssh-keygen
# eventualmente, você pode desejar fazer o mesmo com todos os outros usuários
# que têm chaves ssh na pasta /home:
usuarios=$(ls /home) ;for usuario in $usuarios; do [ -d /home/$usuario/.ssh ] && rm -f /home/$usuario/.ssh/id* ;done
# modifique o /etc/motd, caso lhe convenha
# modifique outras configurações, caso lhe convenham
# atualize o GRUB da máquina C:
update-grub
# caso deseje verificar como ficou, observe o arquivo grub.cfg:
less /boot/grub/grub.cfg
# compile o código de inicialização da máquina
update-initramfs -t -u -k all
# este comando acima pode demorar muito se existem muitas versões de kernel
# instaladas. Para ser mais rápido, use o comando abaixo:
update-initramfs -t -u -k <kernel-default-de-boot>
# onde <kernel-default-de-boot> deve ser igual à saída do seguinte comando,
# que é executado na máquina original A:
uname -r
# ATENÇÃO: certifique-se de que este é também o kernel default de boot do GRUB.
# Para isto, observe novamente o arquivo /boot/grub/grub.cfg que você acabou de atualizar
# acima.
# Instale o GRUB nos discos locais da máquina C:
fdisk -l # para visualizar quais são os discos locais
# vamos supor que existem sda e sdb:
grub-install /dev/sda
grub-install /dev/sdb
# Agora, vamos desmontar o chroot.
exit # para sair do ambiente chroot e voltar ao shell do hipervisor
umount /mnt/r/proc
umount /mnt/r/sys
umount /mnt/r/dev
umount /mnt/r
# Pronto! Pode dar boot na sua nova máquina C:
shutdown -r now
# Bom proveito!
Nota do autor: com os comandos grub-installl acima, o GRUB foi instalado no sda e no sdb; talvez seja suficiente instalar apenas no sdb, que é o disco de boot, por hipótese. Como eu ainda não estou seguro sobre isto, costumo instalar nos dois.
A administração de VMs do KVM é bastante simplificada com o uso do utilitário Virtual Machine Manager (pacote virt-manager do Debian). Uma vez instalado o pacote virt-manager na sua máquina B, você poderá administrar todas as suas máquinas físicas hipervisoras de KVM (inclusive a hipervisora da máquina C).
Vamos supor, a respeito da máquina física hipervisora, a qual NÃO É a máquina C:
Copiar o(s) archive(s) de clone. Por hipótese, ele(s) está na sua máquina B; então, a partir de sua máquina B, copiar para a máquina hipervisora da máquina C (vamos supor que seu endereço IP da hipervisora seja 5.6.7.2):
# entrar na hipervisora da máquina C e montar a partição sdb7 de dados:
ssh -l root 5.6.7.2
# montar o disco de dados, o qual foi escolhido para armazenar a VM da futura máquina C:
mkdir /mnt/dados
mount /dev/sdb7 /mnt/r
cd /mnt/dados
# voltar para a sua máquina B:
exit
# copiar o(s) archive(s) criados nas etapas 3a ou 3b acima (vamos considerar que foi executada a
# etapa 3b acima):
scp maquinaQueSeraClonada.tar.gz root@5.6.7.2:/mnt/dados/.
Entrar na máquina física (hipervisora da futura máquina C) via ssh, criar o arquivo da VM e expandir o archive de clone dentro do arquivo desta VM:
# entre na máquina hipervisora da futura máquina C:
ssh -l root 5.6.7.2
# crie o arquivo correspondente à VM do KVM (vamos supor que 20G bytes é suficiente para a máquina C):
qemu-img create -f raw arquivoDaVM.raw 20G
# observe o 'disk size' desta VM vazia, para comparar posteriormente:
qemu-img info arquivoDaVM.raw
# consulte quais dispositivos de loopback estão em uso (vamos supor nenhum uso atual):
losetup -a
# consulte qual é o próximo dispositivo de loopback está disponível para uso (vamos supor que seja o loop0):
losetup -f
# associe loop0 ao arquivo da VM:
losetup /dev/loop0 arquivoDaVM.raw
# compare agora a saída deste comando (por curiosidade):
losetup -a
# constate que não há partição criada ainda no disco da VM (afinal, o disco acaba de ser criado do zero):
fdisk -lu /dev/loop0
# entre no fdisk e crie 2 partições: uma de swap de 1G e o restante do disco para Linux:
fdisk /dev/loop0
# no final, salve as partições criadas (comando w do fdisk) e saia (comando q)
# verifique que as partições foram criadas:
fdisk -lu /dev/loop0
# saída deste comando deve produzir algo como:
# Device Boot Start End Blocks Id System
#/dev/loop0p1 63 1044224 522081 82 Linux swap / Solaris
#/dev/loop0p2 1044225 16771859 7863817+ 83 Linux
#
# utilize kpartx para criar um mapeamento do dispositivo loop1 com o arquivo da VM (loop0 precisará
# continuar inalterado)
# se necessário, instale o pacote com o comando 'apt-get install kpartx'
kpartx -a arquivoDaVM.raw
# formate as partições mapeadas: /dev/mapper/loop1p1 e /dev/mapper/loop1p2
# observe que o dispositivo aqui é loop1; NÃO É o loop0
# vamos supor que ambas, a máquina hipervisora e a máquina C (clone), suportam BTRFS (caso contrário,
# formate-a como ext4 ou ext3):
mkfs.btrfs --label 'particao root' /dev/mapper/loop1p2
mkswap /dev/mapper/loop1p1
# observar agora o 'disk size', para comparar com o resultado inicial (por curiosidade e para ver a
# evolução do processo):
qemu-img info arquivoDaVM.raw
# montar a partição tipo Linux da VM, pois, é nela que o archive será expandido:
cd /mnt
mkdir r
mount /dev/mapper/loop1p2 r
cd r
# expandir os arquivos originários da máquina A:
tar xzf /mnt/dados/maquinaQueSeraClonada.tar.gz
# verificar se foi expandido como esperado:
ls -l
# Crie as pastas que foram excluídas na geração do archive maquinaQueSeraClonada.tar.gz
# (desnecessário caso a imagem tenha sido gerada a partir de um snapshot do BTRFS, ou seja,
# se executou a etapa 1a acima) :
mkdir /mnt/r/dev
mkdir /mnt/r/mnt
mkdir /mnt/r/proc
mkdir /mnt/r/run
mkdir /mnt/r/sys
mkdir /mnt/r/tmp
# As permissões default destas pastas é 755, com as seguintes exceções que precisam ser colocadas manualmente:
chmod 1777 /mnt/r/tmp
# Pronto, agora vamos desmontar e desfazer os mapeamentos de dispositivo:
cd /mnt
umount r
# elimine o mapeamento de loop1:
kpartx -d arquivoDaVM.raw
# elimine a associação de loop0 com o arquivo da VM:
losetup -d /dev/loop0
# observe o 'disk size' atual, para comparar com o resultado inicial:
qemu-img info arquivoDaVM.raw
# Até este ponto do procedimento, foi prático que o arquivo tivesse esse nome: arquivoDaVM.raw
# Mas, a partir de agora, deve ser mais conveniente dar o nome definitivo para ele, por exemplo:
mv arquivoDaVM.raw minhaVmOpensips.raw
# Este nome minhaVmOpensips.raw foi apresentado aleatoriamente, então escolha o nome melhor para o seu caso.
# E lembre-se que, no item 4.2.2 abaixo, ainda se refere ao nome antigo, então interprete as instruções
# adequadamente.
Quase pronto. Agora, crie a VM (máquina C) do KVM. Esta tarefa pode ser mais fácil de se fazer com o uso do virt-manager. Faça com que o arquivo arquivoDaVM.raw criado seja o disco principal desta VM: se você utiliza o virt-manager, configure nele: 'Disk bus' como sendo VirtIO; e 'Storage format' como raw. Acrescente o ISO do Debian Live como CD-ROM desta VM e faça com que o boot seja dado apenas por ele, por agora. Na etapa 4.1.2.1 acima, foi sugerido um bom ISO para ser utilizado; o procedimento abaixo será baseado neste ISO:
# dar o boot na VM (máquina C) pelo ISO do Debian Live mencionado logo acima
# Terminado o boot, se o Debian live pedir usuário e senha, entrar como user: user e password: live
# Assumir o controle como usuário root:
sudo su -
# Verificar qual é o disco e quais são as partições correspondentes ao disco arquivoDaVM.raw da VM.
# Vamos supor sda1 seja a partição de SWAP e sda2 a partição do tipo Linux.
fdisk -l
# montar sda2:
cd /mnt
mkdir r
mount /dev/sda2 r
# certifique-se de que sda2 está montado em /mnt/r:
df -h
# verifique se há conteúdo em sda2, como esperado (afinal, o archive foi expandido na etapa 4.2.1 acima):
ls -l /mnt/r
# prepare o ambiente para poder dar um chroot em /mnt/r
mount -o bind /dev /mnt/r/dev
mount -t sysfs none /mnt/r/sys
mount -t proc none /mnt/r/proc
# para ajudar a compare e diferencie o ambiente atual da máquina C com
# o ambiente chroot, observando a saída destes comandos:
df -h
alias
#
chroot /mnt/r
# execute novamente e compare:
df -h
alias
# ATENÇÃO: a princípio, a única tela de terminal com ambiente chroot é
# esta onde você acaba de executar o comando chroot. Portanto, se
# você possuir outras telas de login na VM da máquina C, CUIDADO para executar
# os comandos abaixo APENAS NESTA TELA DE LOGIN DO CHROOT.
# remova a definição original das interfaces de rede;
# caso contrário, o que era eth0 passará a ser eth2 após o boot
# da máquina clonada (por hipótese, consideramos acima que a máquina C possui
# 2 interface ethernet: eth0 e eth1).
rm /etc/udev/rules.d/70-persistent-net.rules
# modifique as configurações de rede, caso a máquina clonada precise disto
# tipicamente, você poderá desejar modificar os seguintes arquivos:
#
# /etc/network/interfaces
# /etc/hosts
# /etc/hostname
# /etc/mailname
# /etc/resolv.conf
# modifique o seu script de firewall iptables, se necessário
# Atualize o /etc/fstab. Se são utilizados UUID para se referir
# às partições (o que é recomendado), verifique quais são os
# UUID de sdb1 (swap) e sdb2 (Linux):
blkid
# e modifique /etc/fstab atualizando os UUID com base na saída do comando blkid acima.
# crie novas chaves ssh para a nova máquina, caso seja
# conveniente que o seu ssh cliente a perceba como uma máquina diferente
# da máquina A original:
rm -f /etc/ssh/ssh_host*
ssh-keygen -A
# crie novas chaves para os usuários desta máquina, caso isto
# seja conveniente (por exemplo, faça o seguinte para o root):
rm -f /root/.ssh/id*
ssh-keygen
# eventualmente, você pode desejar fazer o mesmo com todos os outros usuários
# que têm chaves ssh na pasta /home:
usuarios=$(ls /home) ;for usuario in $usuarios; do [ -d /home/$usuario/.ssh ] && rm -f /home/$usuario/.ssh/id* ;done
# modifique o /etc/motd, caso lhe convenha
# modifique outras configurações, caso lhe convenham
# atualize o GRUB da máquina C:
update-grub
# caso deseje verificar como ficou, observe o arquivo grub.cfg:
less /boot/grub/grub.cfg
# compile o código de inicialização da máquina
update-initramfs -t -u -k all
# este comando acima pode demorar muito se existem muitas versões de kernel
# instaladas. Para ser mais rápido, use o comando abaixo:
update-initramfs -t -u -k <kernel-default-de-boot>
# onde <kernel-default-de-boot> deve ser igual à saída do seguinte comando,
# que é executado na máquina original A:
uname -r
# ATENÇÃO: certifique-se de que este é também o kernel default de boot do GRUB.
# Para isto, observe novamente o arquivo /boot/grub/grub.cfg que você acabou de atualizar
# acima.
# Instale o GRUB no disco local da máquina C:
fdisk -l # para visualizar qual é o disco local
# vamos supor que seja o sda:
grub-install /dev/sda
# Agora, vamos desmontar o chroot.
exit # para sair do ambiente chroot e voltar ao shell do hipervisor
cd /mnt
umount r/proc
umount r/sys
umount r/dev
umount r
# Pronto! Pode dar shutdown na sua nova máquina C:
shutdown -h now
# Modifique as configurações da VM (utilizando virt-manager, por exemplo), de tal
# forma que o boot seja dado pelo disco da máquina C (até aqui, o boot era dado
# pelo cdrom representado pelo ISO do Debian Live).
# Dê um boot na sua nova máquina C.
# Bom proveito!
FIM.