Criando E/Ou Acessando Máquinas Virtuais
- Home /
- Linux /
- KVM e QEMU /
- Criando e/ou Acessando Máquinas Virtuais
Virtual Display
Em ambientes de virtualização, a placa de vídeo da VM não é a GPU física real, para que possamos acessar o console da máquina virtual, o hypervisor precisa expor um dispositivo gráfico virtual, que o sistema operacional convidado enxerga como se fosse um hardware real ou paravirtualizado.
Segue abaixo uma tabela exibindo todas as placas gráficas virtuais:
| Placa gráfica | Descrição |
|---|---|
| tcx | Placa gráfica virtual baseada na SUN TCX. Usada exclusivamente para compatibilidade com sistemas antigos da Sun, como Solaris e SunOS em arquiteturas SPARC. Tem uso apenas histórico. |
| cg3 | Outra placa gráfica virtual da Sun Microsystems, voltada para sistemas SPARC legados. Assim como a tcx, existe apenas por compatibilidade com sistemas antigos. |
| cirrus | Emulação do chip Cirrus Logic GD5446. Oferece VGA básico, ampla compatibilidade e baixa performance. Indicada para sistemas antigos, como Windows 95 até versões mais antigas do Windows e Linux legado. |
| std | Implementação de VGA padrão com suporte a resoluções mais altas que a cirrus. Não possui aceleração gráfica, mas funciona de forma estável e sem drivers adicionais. É uma opção segura para gráficos básicos em VMs modernas. |
| vmware | Adaptador gráfico SVGA da VMware. Oferece bom desempenho 2D, mas exige drivers específicos no Linux e VMware Tools no Windows. Deve ser usado apenas dentro do ecossistema VMware. |
| QXL | Placa gráfica paravirtualizada projetada para uso com o protocolo SPICE. Oferece bom desempenho 2D, suporte a múltiplos monitores e integração com recursos como redimensionamento dinâmico. Foi o padrão em ambientes KVM por muitos anos. |
| QXL VGA | Versão mais antiga do QXL, com menos recursos avançados e menor consumo de memória. Indicada para ambientes que priorizam simplicidade e baixo overhead. |
| virtio-vga | Placa gráfica paravirtualizada moderna baseada no projeto virgl. Suporta aceleração 3D via OpenGL, múltiplos monitores e compatibilidade VGA. É a opção recomendada para VMs Linux modernas com interface gráfica. |
| virtio-gpu | Variante do virtio sem modo VGA legado. Mais enxuta e moderna, usada principalmente com Wayland ou ambientes que não precisam de compatibilidade VGA tradicional. |
| bochs | Placa gráfica genérica e simples, com alta compatibilidade e baixa performance. Geralmente usada como fallback ou para depuração quando outras opções falham. |
| ramfb | Framebuffer simples em memória, muito usado em ambientes UEFI. Não oferece aceleração e serve apenas para saída gráfica básica durante boot ou diagnóstico. |
| none | Desativa completamente a placa gráfica da VM. Indicada para servidores, VMs headless e ambientes acessados apenas via SSH ou console serial. |
| GPU Passthrough (VFIO) | Permite que a VM utilize uma GPU física real. Oferece performance quase nativa, suporte completo a 3D e workloads gráficos pesados. Requer IOMMU, hardware dedicado e configuração avançada. |
Video e Graphics
Essas duas opções (--video e --graphics) aparecem automaticamente quando criamos uma VM com ferramentas como virt-install, virt-manager ou virsh.
A opção --video define qual placa de vídeo virtual será apresentada ao sistema operacional convidado. A máquina virtual enxerga essa placa como se fosse um hardware real, permitindo que o kernel do guest carregue o driver gráfico correspondente.
É essa placa de vídeo virtual que fornece a saída gráfica da VM, tornando possível o uso de interfaces gráficas e do console de acesso. De forma prática, ela pode ser comparada à placa de vídeo de um servidor físico, responsável por gerar a imagem que seria exibida em um monitor.
Os tipos de vídeo disponíveis, ou seja, as diferentes placas gráficas virtuais que podem ser utilizadas pela máquina virtual, foram descritos e comparados na tabela apresentada acima.
Já a opção --graphics é usada para exibir o que a placa definida em --video renderiza. Basicamente, essa opção tem como objetivo definir o protocolo e o método de acesso remoto ao console gráfico da VM. Alguns métodos de acesso são: vnc, spice e none.
Como curiosidade, quando abrimos o console gráfico de uma VM pelo virt-manager, estamos usando o protocolo VNC, definido no XML da VM. Se configurarmos apenas --video (sem --graphics), a VM tem placa gráfica, mas ninguém consegue ter acesso ao vídeo. Já se configurarmos apenas --graphics (sem --video), não existe placa para gerar imagem.
O vnc é o modelo de acesso gráfico remoto simples e amplamente compatível, sendo o padrão na maioria dos ambientes. O QEMU expõe a imagem gerada pela placa gráfica virtual através de um servidor VNC, permitindo que clientes como o virt-manager se conectem ao console da VM. É usado quando se busca simplicidade e compatibilidade, sem recursos gráficos avançados.
O spice é o modelo de acesso gráfico remoto otimizado para virtualização. Ele usa um protocolo mais eficiente que o VNC, oferecendo melhor desempenho gráfico e integração com recursos como redimensionamento dinâmico, clipboard e múltiplos monitores. É normalmente usado junto com placas gráficas paravirtualizadas, como QXL ou virtio-gpu.
Já a opção none é o modelo sem acesso gráfico. Ele desativa completamente o console gráfico da máquina virtual, eliminando qualquer saída de vídeo. É indicado para VMs headless, como servidores, onde o acesso ocorre apenas via SSH ou console serial.
Configurando a placa de vídeo virtual
A configuração abaixo define qual placa de vídeo virtual será apresentada ao sistema operacional convidado. É esse dispositivo que o guest enxerga como hardware gráfico e que permite a existência de saída de vídeo, como o console gráfico da máquina virtual.
<video>
<model type="cirrus" vram="256" heads="1" primary="yes"/>
<alias name="video0"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x0"/>
</video>
Nesse exemplo, a VM utiliza a placa gráfica virtual cirrus, que prioriza compatibilidade com diferentes sistemas operacionais. Os parâmetros adicionais controlam características como a quantidade de memória de vídeo disponível (vram), o número de saídas de vídeo (heads) e indicam que essa é a placa gráfica principal da máquina virtual (primary="yes").
Configurando o acesso de vídeo
Podemos utilizar a configuração abaixo em uma máquina virtual para habilitar o acesso gráfico via VNC. Essa opção faz com que o QEMU exponha o console gráfico da VM através de um servidor VNC, permitindo que o vídeo gerado pela placa gráfica virtual seja acessado remotamente por ferramentas como o virt-manager ou qualquer cliente VNC compatível.
<graphics type="vnc" port="5900" autoport="yes" websocket="5700" listen="127.0.0.1" keymap="en-us">
<listen type="address" address="127.0.0.1"/>
</graphics>
Nessa configuração, o protocolo VNC é responsável apenas por exportar a saída de vídeo da VM, enquanto a geração da imagem continua sendo feita pela placa gráfica virtual definida na opção --video ou no bloco <video> do XML.
Configurando via CLI
Ao criar uma máquina virtual usando o virt-install, podemos definir o acesso gráfico via VNC diretamente pela linha de comando, sem necessidade de ajustes posteriores no XML da VM. Para isso, vamos usar o comando abaixo:
virt-install \
--virt-type kvm \
--name ubuntu24 \
--vcpus 2 \
--ram 4096 \
--os-variant ubuntu24.04 \
--cdrom /var/lib/libvirt/images/noble-live-server-amd64.iso \
--network network=default \
--graphics vnc,listen=127.0.0.1 \
--disk size=30
A opção --graphics vnc define o VNC como protocolo de acesso ao console gráfico da máquina virtual e o parâmetro listen=127.0.0.1 restringe o acesso ao VNC apenas ao host local, aumentando a segurança.
O console gráfico gerado pela placa de vídeo virtual da VM poderá ser acessado por ferramentas como o virt-manager ou qualquer cliente VNC conectado ao host.
Criando máquinas virtuais
Em servidores que não possuem interface gráfica, podemos criar máquinas virtuais utilizando o libvirt ou diretamente o QEMU, como já foi mostrado. No entanto, esses métodos não se comportam da mesma forma em relação à persistência da VM.
Quando utilizamos comandos como virsh create ou qemu-system-x86_64, a máquina virtual é criada de forma temporária. Nesse modelo, não existe um XML persistente associado à VM, e ela deixa de existir assim que é desligada. A única informação que permanece após o desligamento são as alterações realizadas no disco da máquina virtual.
Para criar uma máquina virtual temporária, podemos usar os comando virsh create ou qemu-system-x86_64.
Para que a máquina virtual continue existindo após ser desligada, é necessário criar ela de forma persistente no libvirt. Isso pode ser feito usando os comandos virt-install ou virsh define.
Nesse caso, a definição da VM é armazenada em um arquivo XML, que fica salvo em disco e permite que a máquina virtual seja iniciada, parada e gerenciada posteriormente por diferentes ferramentas, como o próprio virsh, sem necessidade de interface gráfica.
Criando uma máquina virtual com virsh define
O comando virsh define cria uma máquina virtual persistente a partir de um arquivo XML. A VM não é iniciada automaticamente, apenas sua definição é registrada no libvirt. Crie um arquivo, por exemplo ubuntu2404.xml contendo o seguinte conteúdo:
<domain type='kvm'>
<name>ubuntu2404</name>
<memory unit='MiB'>4096</memory>
<currentMemory unit='MiB'>4096</currentMemory>
<vcpu placement='static'>2</vcpu>
<os>
<type arch='x86_64' machine='q35'>hvm</type>
<boot dev='cdrom'/>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<cpu mode='host-model'/>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<!-- Disco -->
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/ubuntu2404.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
<!-- CDROM de instalação -->
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/var/lib/libvirt/images/noble-live-server-amd64.iso'/>
<target dev='sda' bus='sata'/>
<readonly/>
</disk>
<!-- Rede -->
<interface type='network'>
<source network='default'/>
<model type='virtio'/>
</interface>
<!-- Console serial -->
<console type="pty">
<target type="serial" port="0"/>
</console>
<!-- Vídeo -->
<video>
<model type="cirrus" vram="256" heads="1" primary="yes"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x0"/>
</video>
<!-- Gráficos -->
<graphics type="vnc" port="-1" autoport="yes" websocket="-1" listen="127.0.0.1" keymap="en-us">
<listen type="address" address="127.0.0.1"/>
</graphics>
</devices>
</domain>
Vamos agora criar o disco que será usado pela VM.
qemu-img create -f qcow2 /var/lib/libvirt/images/ubuntu2404.qcow2 30G
Agora vamos criar a definição da VM no libvirt:
virsh define ubuntu2404.xml
Agora a VM existe no libvirt de forma permanente. Podemos iniciar a máquina virtual com o comando:
virsh start ubuntu2404
:::tip curiosidade
Nessa configuração do Libvirt, o que faz com que possamos usar a aceleração de hardware do KVM é a primeira linha: <domain type='kvm'>.
Isso diz ao libvirt para usar o QEMU com aceleração KVM. :::
Criando uma máquina virtual com virt-install
Usar o virt-install é o método mais fácil e prático de iniciar máquinas virtuais, mesmo sem interface gráfica no servidor.
virt-install \
--virt-type kvm \
--name ubuntu2404 \
--ram 4096 \
--vcpus 2 \
--os-variant ubuntu20.04 \
--cdrom /var/lib/libvirt/images/noble-live-server-amd64.iso \
--disk path=/var/lib/libvirt/images/ubuntu2404.qcow2,size=30 \
--network network=default \
--graphics vnc,listen=127.0.0.1 \
--noautoconsole
O parâmetro importante para ambiente sem interface gráfica é o --noautoconsole, ele impede que seja aberto um console após iniciado a VM.
Acessando a console de uma máquina virtual
O comando virsh console VM_NAME funciona exclusivamente quando o sistema operacional convidado está configurado para enviar saída para o console serial. Caso o guest não utilize a interface serial, o comando conecta corretamente, mas não exibe nenhuma saída.
Em ambientes de servidor, não é possível acessar o console gráfico da máquina virtual diretamente pelo terminal SSH do host, pois protocolos como VNC exigem um cliente gráfico para renderização da imagem. Nesses casos, o acesso ao console gráfico deve ser feito a partir de outra máquina, utilizando um cliente VNC, ou por meio do virt-manager conectado via SSH ao host KVM.
Configurando a console de uma máquina virtual
Para que o console serial funcione corretamente no Ubuntu, é necessário configurar o kernel e o GRUB para enviar saída tanto para o vídeo quanto para a porta serial (ttyS0).
Dentro da máquina virtual Ubuntu, edite o arquivo:
sudo vim /etc/default/grub
Localize a linha abaixo:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
E adicione o conteúdo:
GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0,115200n8"
O console=tty0 mantém a saída no console de vídeo (VNC/SPICE), caso exista. Já a linha console=ttyS0,115200n8 é usada para enviar a saída do kernel para a porta serial, permitindo o uso do virsh console.
Ainda no mesmo arquivo, adicione a opção abaixo. Isso garante que o GRUB continue funcionando mesmo sem terminal gráfico.
GRUB_TERMINAL=console
Após salvar o arquivo, gere a nova configuração do GRUB:
sudo update-grub
O kernel agora envia saída para o serial, mas ainda é necessário habilitar um getty para permitir login.
sudo systemctl enable serial-getty@ttyS0.service
Por fim, reinicie a máquina virtual:
sudo reboot
Agora podemos acessar usando a opção console:
virsh console ubuntu2404
Para sair do console:
Ctrl + ]
Comandos virsh
Abaixo vou deixar uma tabela com os principais comandos virsh.
| Comando | Descrição |
|---|---|
| virsh list –all | Exibe todas as máquinas virtuais (sem o --all mostra só as queestiverem em funcionamento). |
| virsh domrename nome1 novonome2 | Renomeia uma VM. |
| virsh start VM_NAME | Inicia uma Máquina Virtual. |
| virsh shutdown VM_NAME | Desliga a máquina virtual, é um desligamento soft (gentil). |
| virsh destroy VM_NAME | Desliga a máquina virtual, é como se tirássemos o cabo de energia do computador, é um desligamento hard (bruto). |
| virsh undefine VM_NAME | Se a VM estiver ligada, após desligá-la ela será deletada, se estiver desligada, será deletada de imediato. (O disco será mantido) |
| virsh undefine VM_NAME –remove-all-storage | Remove a VM e apaga os discos. |
| virt-clone –original VM_NAME –name VM_NAME-Clone –auto-clone | Comando para Clonar uma VM. |
| virt-clone –original VM_NAME –name VM_NAME-Clone –file name.qcow2 | Clona uma VM para usar um HD específico. |
| virsh domblklist –domain VM_NAME | Ver os HDs de uma VM. |
| virsh snapshot-list –domain VM_NAME | Ver os snapshots da VM. |
| virsh snapshot-delete –domain VM_NAME –snapshotname SNAPSHOT_NAME | Deleta um snaphost. |
| virsh edit ubuntu20.04 | Edita a configuração da VM. |
| virsh detach-disk ubuntu20.04 vdb –config | Remove o disco VDB da VM no próximo boot da VM. |
| virsh detach-disk ubuntu20.04 vdb –current | Remove o disco VDB da VM com ela desligada. |
Acessando as Máquinas Virtuais
Existem diversas ferramentas que podem ser utilizadas para acessar o console de máquinas virtuais. Embora todas permitam visualizar ou interagir com a VM, muitas delas vão além desse papel básico e oferecem recursos mais completos, como criação, gerenciamento e organização das máquinas virtuais.
A ideia aqui é descrever o que cada ferramenta oferece, mantendo o foco no acesso ao console da máquina virtual. Ainda assim, algumas soluções se destacam por fornecer um ecossistema de gerenciamento mais completo, e por isso merecem ser mencionadas, mesmo indo além do acesso direto ao console.
virt-manager e virt-viewer
O virt-viewer é um cliente gráfico leve usado para acessar o console de máquinas virtuais. Ele faz parte da mesma família de ferramentas do virt-manager, e ambos integram a stack de gerenciamento baseada no framework libvirt.
Enquanto o virt-manager funciona como uma interface gráfica completa para o gerenciamento do ciclo de vida das máquinas virtuais (permitindo criar, remover, ajustar hardware, redes e acompanhar o uso de recursos) o virt-viewer tem um objetivo bem mais específico.
Ele é uma ferramenta focada exclusivamente na exibição do console gráfico da VM, utilizando protocolos como VNC ou SPICE, sem oferecer funcionalidades de gerenciamento adicionais.
O comando abaixo permite acessar o console gráfico de uma máquina virtual que está sendo executada no próprio host local. Na prática, esse uso é menos comum, já que normalmente o acesso local ao console é feito diretamente pelo virt-manager, que oferece a mesma funcionalidade de forma integrada.
virt-viewer --connect qemu:///system ubuntu2404
Já o comando abaixo permite acessar o console gráfico de uma máquina virtual que está sendo executada em outro host. Nesse caso, o virt-viewer se conecta ao libvirt remoto utilizando SSH, abrindo o console da VM localmente sem a necessidade de expor serviços gráficos na rede.
virt-viewer --connect qemu+ssh://root@192.168.20.239/system ubuntu2404
Neste exemplo, o acesso está sendo feito com o usuário root, o que não é uma boa prática. O recomendado é utilizar um usuário comum, com permissões adequadas para gerenciamento via libvirt, garantindo mais segurança e controle sobre o ambiente.
Já o virt-manager permite gerenciar máquinas virtuais que estão em outros servidores, desde que eles estejam rodando libvirt e sejam acessíveis via SSH. Usando esse método poderemos até criar máquinas virtuais, deletar, pausar e gerenciar de forma completa.
O melhor de tudo, a aplicação gráfica fica na nossa máquina e não precisa ser instalado no servidor.
No virt-manager, vá em: File → Add Connection. Na janela que abrir:
Hypervisor
Selecione QEMU/KVM;Marque Connect to remote host over SSH;
Hostname
Informe o IP ou hostname do servidor KVM;Username
Informe o usuário que você tem acesso via SSH e que tenha acesso ao libvirt;Clique em Connect;
Com isso, o virt-manager passa a se conectar ao libvirt remoto via SSH (qemu+ssh) e permite acessar o console gráfico e gerenciar as VMs do host remoto, sem expor VNC ou SPICE na rede.
noVNC
O noVNC é um cliente VNC baseado em navegador, usado para acessar o console gráfico de máquinas virtuais diretamente pela web. Diferente do virt-viewer e do virt-manager que exigem um ambiente gráfico no lado do cliente, o noVNC funciona inteiramente no navegador, o que o torna especialmente útil em ambientes headless, onde o host não possui interface gráfica instalada.
O noVNC não se conecta diretamente ao VNC tradicional via TCP. Como navegadores não suportam conexões TCP brutas, ele utiliza WebSocket, normalmente por meio do websockify ou do suporte nativo a WebSocket do próprio QEMU, quando configurado.
Nesse modelo, o QEMU expõe o console gráfico da VM via VNC (com suporte a WebSocket), e o noVNC atua apenas como a interface web que permite visualizar e interagir com essa tela.
O acesso ao console da máquina virtual ocorre via navegador, sem a necessidade de instalar clientes VNC, virt-manager ou virt-viewer na máquina do administrador. Isso facilita bastante o acesso pontual, principalmente durante a instalação inicial do sistema operacional ou em cenários de troubleshooting.
Para utilizar o noVNC, é necessário que a máquina virtual esteja configurada para expor o console gráfico via VNC com suporte a WebSocket. Um exemplo de configuração no XML da VM é:
<graphics type="vnc" port="5900" autoport="yes" listen="127.0.0.1" keymap="en-us">
<listen type="address" address="127.0.0.1"/>
</graphics>
No host KVM, instale o noVNC e o websockify:
apt install -y novnc websockify
Em seguida, inicie o noVNC apontando para a porta WebSocket configurada na VM:
/usr/share/novnc/utils/launch.sh --vnc 127.0.0.1:5900 --listen 6080
Esse comando disponibiliza a interface web do noVNC na porta 6080, conectando-a ao console gráfico da máquina virtual. O acesso ao console é feito a partir de outra máquina, via navegador: http://host-kvm:6080/vnc.html?host=host-kvm&port=6080.
Em ambientes onde o host KVM não expõe portas diretamente, o acesso pode ser feito de forma segura utilizando um túnel SSH:
ssh -L 6080:127.0.0.1:6080 usuario@host-kvm
E então acessando no navegador: http://localhost:6080/vnc.html.
:::danger Sempre use TLS O noVNC expõe um console interativo da máquina virtual, com acesso a teclado e tela. Sem TLS, todo o tráfego trafega em texto claro.
Isso representa um risco sério de segurança, principalmente quando o acesso não é feito exclusivamente via localhost ou túnel SSH. :::
Cockpit
O Cockpit é uma interface web para administração de servidores Linux. Diferente de ferramentas focadas apenas em virtualização, ele foi projetado para ser um painel geral de gerenciamento do sistema, acessível diretamente pelo navegador.
No contexto de máquinas virtuais, podemos instalar o pacote cockpit-machines para fazer o Cockpit se integrar ao libvirt e permite não apenas acessar o console da VM, mas também criar, iniciar, parar e remover máquinas virtuais, além de acompanhar o estado do host.
Uma das grandes vantagens do Cockpit é que ele funciona muito bem em ambientes headless. O host não precisa de interface gráfica instalada, já que todo o acesso ocorre via navegador, normalmente através de HTTPS.
Para acesso ao console das máquinas virtuais, o Cockpit utiliza internamente o noVNC, abstraindo completamente a complexidade de configuração de VNC, WebSocket e websockify. Para o usuário, o console simplesmente funciona sem necessidade de ajustes manuais.
Todos esses recursos fazem com que o Cockpit não seja apenas uma ferramenta para acessar o console da máquina virtual, mas sim um painel unificado de administração do host, útil tanto para laboratórios quanto para servidores reais.
Podemos instalar e habilitar o Cockpit com o passo a passo abaixo:
# Instale o Cockpit:
sudo apt install cockpit cockpit-machines -y
# Habilite o serviço/socket e habilite no boot:
sudo systemctl enable --now cockpit.service
sudo systemctl enable --now cockpit.socket
Depois basta acessar o IP do servidor na porta 9090: https://192.168.20.239:9090/.
oVirt
O oVirt é uma plataforma completa de virtualização e gerenciamento de infraestrutura, voltada para ambientes onde o controle de máquinas virtuais vai além do uso individual de um host KVM. Diferente do virt-manager, do virt-viewer ou do Cockpit, o oVirt não é apenas uma ferramenta de acesso ao console. Ele fornece um ecossistema completo de gerenciamento centralizado, capaz de administrar múltiplos hosts KVM como um único ambiente.
O oVirt opera com uma arquitetura separada entre Engine (plano de controle) e Hosts (plano de dados). O Engine é responsável por orquestrar recursos, armazenar metadados, aplicar políticas e fornecer a interface web, enquanto os hosts executam efetivamente as máquinas virtuais.
O acesso ao console das máquinas virtuais no oVirt é feito via noVNC ou SPICE, totalmente integrado à interface web. Assim como no OpenStack, o usuário acessa o console diretamente pelo navegador, sem expor portas VNC nem precisar configurar manualmente WebSocket ou proxies.
Além do acesso ao console, o oVirt oferece recursos avançados que vão muito além disso, como: gerenciamento de clusters KVM, balanceamento de carga e afinidade de VMs, migração ao vivo, gerenciamento centralizado de storage, políticas de alta disponibilidade, templates e snapshots de máquinas virtuais.
Esses recursos tornam o oVirt adequado para ambientes corporativos ou laboratoriais mais complexos, onde é necessário padronizar configurações, aplicar políticas consistentes e gerenciar múltiplos servidores como uma única plataforma.
Do ponto de vista de acesso ao console, o oVirt resolve de forma transparente todos os detalhes técnicos envolvidos (VNC, SPICE, TLS, WebSocket), permitindo que o administrador foque no gerenciamento da infraestrutura e não na configuração manual de cada host. Desde o desenvolvimento inicial, o oVirt foi projetado para ambientes distribuídos, onde múltiplos servidores físicos trabalham em conjunto, compartilhando recursos e sendo administrados de forma centralizada. O primeiro é o Engine, que representa o plano de controle da plataforma.
Ele é responsável por manter o estado global do ambiente, aplicar políticas, coordenar clusters, gerenciar redes e storage, fornecer a interface web e expor APIs. É também o Engine que orquestra o acesso ao console das máquinas virtuais, integrando tecnologias como noVNC e SPICE.
O segundo papel é o dos hosts, que compõem o plano de dados. Esses hosts são servidores KVM responsáveis por executar efetivamente as máquinas virtuais, fornecer recursos de CPU, memória e armazenamento, além de participar de operações como migração ao vivo e alta disponibilidade.
Essa separação não é um detalhe de implementação, mas sim um princípio arquitetural. Mesmo em ambientes pequenos ou de laboratório, o oVirt continua sendo pensado como um sistema distribuído, ainda que fisicamente tudo possa estar rodando em menos máquinas.
Outro aspecto central da arquitetura do oVirt é o sistema operacional no qual ele é implantado. Ele é oficialmente suportado apenas em distribuições baseadas no ecossistema Red Hat. Essa escolha está diretamente ligada à forma como o projeto é desenvolvido e empacotado. O oVirt depende de versões específicas de componentes como libvirt, VDSM, sanlock, gluster, além de uma integração esperada com systemd, SELinux e políticas de segurança típicas desse ecossistema.
Distribuições baseadas em Debian, como Ubuntu, seguem decisões diferentes de empacotamento, ciclos de atualização distintos e não oferecem os mesmos conjuntos de pacotes e integrações. Por esse motivo, não existe suporte oficial para execução do oVirt em produção nesses sistemas.
Apesar do suporte oficial estar restrito ao ecossistema Red Hat, o próprio projeto oVirt mantém documentação mostrando que é possível construir o oVirt Engine em sistemas baseados em Debian/Ubuntu para fins de desenvolvimento. Essa documentação, presente no Developer Guide, descreve como compilar o oVirt Engine em ambientes Debian-like, deixando claro que o código é, em certa medida, portável.
Migrando Máquinas Virtuais
Migrar máquinas virtuais entre servidores de virtualização é um recurso bastante utilizado em ambientes profissionais, esse recurso permite que a gente mova uma máquina virtual que está sendo executada em um servidor físico e coloque essa máquina virtual em outro servidor físico. Esse processo pode ocorrer com tempo mínimo de indisponibilidade ou até mesmo sem interrupção, dependendo do tipo de migração utilizado.
A migração pode envolver dois tipos principais de recursos da VM:
Computação
É o estado da máquina virtual, como: CPU, conteúdo da memória RAM, estado dos dispositivos virtuais (placa de rede, controladores, timers, etc.) entre outras informações. O hypervisor que está executando a VM mantém essas informações na memória do host físico.
Armazenamento
Aqui entram os arquivos da VM, como discos virtuais, snapshots e metadados específicos da VM.
Tipo de migração
O ato de migrar uma VM de um host para outro é algo bem complexo se formos olhar tudo o que acontece no backend do hypervisor. Eu vou arranhar essa superfície complexa para tentar explicar como funciona (de forma bem superficial). Quando falamos em migração de VMs, existem dois aspectos importantes que precisam ser considerados, que são: tipo de migração e escopo da migração.
O tipo de migração define o estado da VM durante o processo de migração, ou seja, se a máquina virtual está desligada, pausada ou em execução. Já o escopo da migração, define quais recursos da VM serão transferidos durante o processo.
Dependendo do ambiente de virtualização, a migração pode envolver diferentes componentes da máquina virtual, mas no geral, podemos migrar os seguintes recursos de uma VM: migrar apenas a computação, migrar apenas o armazenamento ou migrar computação e o armazenamento.
Quando eu falo em Migrar apenas a computação, eu quero dizer que é possível mover o estado de execução da VM entre hosts, isso inclue: CPU virtual, memória e dispositivos virtuais. Mas se atente a um detalhe muito importante, isso só é possível se ambos os hosts físicos possuem acesso ao disco da VM. Isso é muito comum em ambientes com storage compartilhado.
Funciona mais ou menos assim, o disco da VM permanece no storage compartilhado (onde ambos os hosts possuem acesso), enquanto a memória RAM mais o estado da CPU são migrados para outro host. Isso possibilita um live migration sem impactar o uso da VM. Pelo fato de não precisar copiar discos durante a migração, esse tipo de migração é muito rápido e em teoria, quase imperceptível.
Agora, quando falo em migrar apenas o armazenamento, eu quero literalmente dizer que podemos mover os discos virtuais da VM entre diferentes storages ou storage pools. Isso significa que podemos mover o disco de pool para outro dentro do mesmo servidor físico onde a VM está em execução ou mover o disco entre servidores físicos.
Um exemplo é um ambiente que está migrando suas máquinas virtuais para um novo sistema de armazenamento. Para que esse processo ocorra sem impacto para a VM, os hosts envolvidos na migração precisam ter acesso simultâneo aos dois storages. Dessa forma, o hypervisor consegue copiar os discos da VM do storage antigo para o novo enquanto a máquina virtual continua em execução.
Agora, o mais lento é a migração de computação e armazenamento, aqui precisamos mover tanto o estado de execução quanto os discos da VM para outro host ou outro storage. Funciona mais ou menos assim:
- O disco começa a ser copiado;
- A memória da VM é migrada;
- A VM é pausada rapidamente;
- As últimas páginas de memória são sincronizadas;
- Por fim, a VM continua no novo host.
Existem três formas principais de migrar máquinas virtuais entre hosts, que são: Cold Migration, Suspended Migration e Live Migration.
O Cold Migration ou Offline Migration como também é conhecido, é quando a VM precisa estar desligada durante o processo de migração. Aqui o processo por ser realizado manualmente pelo administrador ou automaticamente pelo hypervisor.
Já no Suspended Migration, a VM é suspensa antes da migração. Após a transferência, a VM é restaurada e continua sua execução a partir do ponto em que foi suspensa.
O Live Migration é o método perfeito de migração, ele permite mover uma VM enquanto ela continua em execução. Esse processo ocorre transferindo a memória da VM gradualmente para o host de destino enquanto a VM continua rodando.
Tipos de Live Migration
Quando falamos em live migration, diferentes componentes da VM podem ser migrados como já vimos, que são: migrar apenas a computação, migrar apenas o armazenamento ou migrar computação e o armazenamento.
Eu só quero reforçar que, para uma migração rápida e sem interrupções perceptíveis, o ideal é utilizar um sistema de storage compartilhado entre os hosts de virtualização. Eu recomendo utilizar Ceph ou GlusterFS, pois são sistemas de armazenamento distribuído. No entanto, é importante lembrar que essas tecnologias também exigem planejamento e uma configuração adequada para funcionarem de forma eficiente e a curva de aprendizado é um pouco longa.
Também é possível utilizar NFS ou iSCSI como storage compartilhado. Porém, nesses casos existe um ponto único de falha. Se o servidor que fornece o storage ficar indisponível, as VMs que dependem desse armazenamento também podem ser impactadas ou até interromper sua execução.
Por isso, eu recomendo soluções distribuídas como o Ceph ou GlusterFS, já que eles costumam ser mais indicadas em ambientes que exigem maior disponibilidade e tolerância a falhas.
Limitações de live migration
Infelizmente nem todas as VMs podem ser migradas em execução. Se a VM utiliza PCI passthrough, a live migration geralmente não é possível, já que existe um dispositivo PCI real atrelado na VM.
As VMs que utilizam Single Root I/O Virtualization (SR-IOV) também possuem restrições para migração online, isso ocorre porque as virtual functions (VFs) estão diretamente ligadas ao hardware físico do host.
As VMs que utilizam virtual GPUs (vGPU) também podem ter problemas com live migration dependendo da implementação.
As VMs também podem apresentar problemas durante o live migration quando o host de destino não suporta todas as extensões de CPU utilizadas pela máquina virtual. No entanto, isso é relativamente raro atualmente, a menos que a migração esteja sendo feita para um servidor com hardware mais antigo.
Isso ocorre porque, durante o processo de live migration, o host de destino precisa suportar todas as instruções de CPU que a VM está utilizando, então a migração pode falhar porque o Host de destino não suporta as mesmas extensões de CPU.
Permissões necessárias para migração
Essa é uma parte que poucos pensam até surgir um erro durante a tentativa de migração. Normalmente você pode fazer a migração com usuário root, embora eu não recomende esse método. Caso seja um usuário comum, ele precisa pertencer ao grupo libvirt, assim como para executar VMs no host.
No ecossistema do libvirt existem dois modos de sessão, que são: system session e user session. O system session é utilizado pelo root e serviços do sistema. Já o user session é utilizado por usuários comuns. Essa distinção é importante porque as máquinas virtuais criadas em cada sessão são independentes entre si, ou seja, uma VM criada na system session não aparece na user session, e vice-versa.
A maioria das operações administrativas, como criação, gerenciamento e migração de VMs, ocorre na system session, pois é nesse modo que o libvirt tem acesso completo aos recursos do sistema, como interfaces de rede, dispositivos de armazenamento e permissões necessárias para realizar migrações entre hosts.
Você pode explicar assim, de forma direta e técnica:
No libvirt, o comando virsh pode se conectar a diferentes sessões do hypervisor. As duas mais comuns são a system session e a user session como mencionado acima. A sessão utilizada define quais máquinas virtuais serão visíveis e quais recursos estarão disponíveis.
Para visualizar as VMs da system session, podemos usar o comando abaixo:
virsh -c qemu:///system list
Essa sessão é controlada pelo sistema e normalmente utilizada pelo usuário root ou por serviços administrativos. As máquinas virtuais executadas nesse modo têm acesso completo aos recursos do host, como interfaces de rede, dispositivos de armazenamento e bridges de rede.
Já para visualizar as VMs da user session, podemos usar o comando abaixo:
virsh -c qemu:///session list
Nesse modo, as VMs pertencem ao usuário que as iniciou e ficam isoladas das VMs da system session. Esse tipo de sessão é mais comum em ambientes de testes ou uso local, onde o usuário não possui privilégios administrativos.
É importante entender essa diferença porque as VMs criadas em uma sessão não aparecem na outra. Assim, ao executar virsh list sem especificar a sessão, pode parecer que não existem VMs no host, quando na realidade elas estão sendo executadas em outra sessão.
Em ambientes de produção, especialmente quando se trabalha com migração de máquinas virtuais, as VMs geralmente são executadas na system session, pois esse modo possui as permissões e os recursos necessários para operações administrativas entre hosts.
Migrando Máquinas Virtuais
Agora sim chegamos ao ponto em que vamos ver como migrar as máquinas virtuais.
# Migrar apenas a computação (precisa ter storage compartilhado):
virsh migrate --live --persistent ubuntu2004 qemu+ssh://vagrant@kvm01/system
# Migrar apenas o armazenamento (copiando o disco para outro pool - a VM precisar estar em execução):
virsh blockcopy ubuntu2004 vda /var/lib/libvirt/newpool/ubuntu2004.qcow2 --transient-job --wait --pivot --verbose
# Migrar computação mais armazenamento:
virsh migrate --live --persistent --verbose --copy-storage-all ubuntu2004 qemu+ssh://vagrant@kvm01/system
Para ver o nome do disco na VM, podemos usar o comando abaixo:
virsh domblklist ubuntu2004
A opção --persistent é necessária porque ela faz com que a VM seja registrada como persistente no host de destino. Sem essa opção, a VM pode ser criada como transiente no host destino e desaparecer após ser desligada. Ela basicamente cria o XML da VM no host de destino.
A opção --verbose para mostrar informações detalhadas do progresso da migração no terminal. Outra opção interessante é a --unsafe. Ela permite que a migração seja realizada mesmo quando o libvirt detecta riscos de inconsistência. Normalmente o libvirt bloqueia a migração se detectar algo que pode causar corrupção de dados, como: discos locais não compartilhados, configurações incompatíveis, risco de perda de dados e etc.
A opção --transient-job permite executar um block job mesmo quando a VM possui uma definição persistente no libvirt. Sem essa opção, operações como virsh blockcopy ubuntu2004 vda... são recusadas porque o libvirt originalmente exige que o domínio seja transient (não possua um XML com a configuração da VM).
Ao usar --transient-job, o libvirt permite que a cópia do disco seja realizada mesmo em uma VM persistente. Essa opção é muito usada com --pivot, ela permite copiar o disco para o novo local e também atualiza a configuração da VM (XML) para que ela passe a utilizar o novo disco de forma persistente.
:::tip O pivot pode te enganar
Após realizar a cópia do disco em tempo real usando a opção --pivot, é possível observar que o XML da VM ainda faz referência ao disco ou path antigo. Isso ocorre porque o libvirt mantém duas representações da configuração da máquina virtual: a configuração ativa (runtime), usada pela VM em execução, e a configuração persistente, armazenada no XML.
Com o --pivot, o disco ativo da VM é trocado imediatamente no runtime, permitindo que a máquina virtual continue rodando e passando a utilizar o novo disco sem interrupção. No entanto, a configuração persistente pode continuar exibindo o caminho antigo até que a VM seja desligada e iniciada novamente. Nesse momento, o libvirt reconcilia as informações e o XML passa a refletir a nova configuração.
Mesmo antes de reiniciar a VM, é possível verificar que a mudança já ocorreu observando que o novo disco passa a receber as escritas da máquina virtual, enquanto o disco antigo deixa de ser utilizado.
:::
A opção --offline pode ser usada no lugar de --live para fazer uma migração com a VM desligada.
:::danger Cuidado com blockcopy O uso do blockcopy pode ser sentido no lado da VM durante a cópia, algumas travadas podem ocorrer.
Ele também não muda a configuração da VM, apenas copia o disco para outro local. Para alterar a configuração e mudar o disco que a VM deve usar, use a opção --pivot.
:::
:::danger Cuidado Pool durante o live migration com cópia de disco
Durante o virsh migrate --copy-storage-all, o libvirt procura no host de destino um storage pool ativo cujo target path corresponda ao caminho do disco definido no XML da VM. Caso não exista um pool ativo com esse caminho, você verá um erro parecido com error: Storage pool not found: no storage pool with matching target path '...'.
:::
pag 240 Migrating VMs