Explorando O Libvirt
- Home /
- Linux /
- KVM e QEMU /
- Explorando o Libvirt
LockD e Sanlock
Eu pretendia abordar o lockd no capítulo anterior, onde tratamos sobre Migrando Máquinas Virtais, mas isso tornaria o conteúdo muito longo. Também achei melhor reservar esse capítulo para falar sobre outros recursos do Libvirt.
Em um ambiente de cluster, com vários servidores envolvidos no processo de virtualização, é comum existir uma storage centralizada. Isso facilita o acesso dos servidores aos discos das VMs e também traz mais flexibilidade para realizar migrações entre os hosts. No entanto, nesse cenário pode surgir um problema: iniciar a mesma máquina virtual simultaneamente em dois hypervisors diferentes.
Se dois hosts tentarem gravar dados no mesmo disco virtual ao mesmo tempo, e o sistema de arquivos da VM não estiver preparado para acesso concorrente, o resultado provavelmente será a corrupção do sistema de arquivos da máquina virtual. Para evitar esse tipo de situação, mecanismos de locking são utilizados. Tanto o sanlock quanto o lockd impedem que isso aconteça, bloqueando a inicialização da VM em um segundo host caso ela já esteja ativa em outro.
LockD
Como mencionado acima, o lockd é um mecanismos de travamento usado no Libvirt para garantir a integridade dos dados das máquinas virtuais. Quando usamos ele, estamos impedindo que uma máquina virtual seja iniciada simultaneamente em dois hypervisors diferentes usando o mesmo disco da VM.
O lockd utiliza um mecanismo do próprio sistema operacional para travar arquivos, garantindo que apenas um processo possa usar ele por vez. No Libvirt, esse controle é feito por meio de um serviço chamado virtlockd. Em ambientes com vários servidores de virtualização, esse mecanismo depende de um sistema de arquivos compartilhado entre os hosts, como NFS ou GlusterFS. Em storages distribuídos como Ceph, o próprio sistema de armazenamento já possui mecanismos internos de controle de acesso.
Quando um servidor inicia uma máquina virtual cujo disco está armazenado em um storage compartilhado, o libvirt cria um lock no arquivo do disco para indicar que aquele recurso já está em uso. Esse lock é criado utilizando o mecanismo de POSIX file locking (fcntl()), normalmente através do serviço virtlockd. A partir desse momento, qualquer outro servidor que tente acessar o mesmo disco irá verificar esse lock antes de permitir o uso do recurso.
Em ambientes que utilizam NFS, esse lock não fica apenas no host que iniciou a VM. Ele é enviado ao servidor NFS por meio do NLM (Network Lock Manager), que faz parte do protocolo de file locking do NFS. O servidor NFS passa então a registrar e gerenciar esse lock, garantindo que outros hosts que acessem o mesmo arquivo consigam verificar que o disco já está em uso. Por esse motivo, é fundamental que o NFS esteja configurado com suporte a locking, seja por meio do NLM (utilizado no NFSv3) ou do mecanismo de locking integrado do NFSv4.
Já em ambientes que utilizam GlusterFS, o controle de locks não depende de um servidor central. Como o GlusterFS é um sistema de arquivos distribuído, o próprio cluster gerencia essas informações. Quando um lock é criado, ele é registrado pelos bricks do cluster responsáveis pelo armazenamento daquele arquivo. Assim, qualquer outro host que tente acessar o mesmo disco irá consultar o cluster GlusterFS e identificar que o recurso já está bloqueado.
Dessa forma, independentemente da tecnologia de armazenamento utilizada, todos os servidores participantes do ambiente de virtualização conseguem verificar se o disco de uma VM já está sendo utilizado, impedindo que a mesma máquina virtual seja iniciada simultaneamente em dois hypervisors.
:::tip POSIX file locking
O virtlockd usa POSIX file locking nos arquivos do storage compartilhado, ou seja, ele é uma capacidade de travamento consultivo baseada na chamada de sistema fcntl(). Isso significa que o sistema operacional não impede fisicamente o acesso ao arquivo. Os programas precisam respeitar o lock voluntariamente. No contexto de virtualização com KVM/libvirt, esse mecanismo é a base do lockd.
Podemos ver os locks em tempo real usando o comando lslocks.
:::
Vamos ver como ativar o lock manager no libvirt. Lembrando que esse processo deve ser realizado em todos os servidores que executam VMs.
# Edite o arquivo abaixo:
sudo vim /etc/libvirt/qemu.conf
## Localize ou adicione a linha lock_manager = "lockd" caso ela não exista.
Depois inicie o serviço virtlockd e reinicie o serviço do libvirt:
# Configurando o virtlockd para iniciar no boot e já iniciando o serviço junto:
sudo systemctl enable --now virtlockd
# Reiniciando o serviço do libvirt:
sudo systemctl restart libvirtd
Pronto, com isso já temos o lockd em operação.
E quando não temos um filesystem compartilhado?
Em alguns ambientes de virtualização, os discos das máquinas virtuais não estão armazenados em um filesystem compartilhado. Em vez disso, eles podem estar em dispositivos de bloco, como volumes LVM, LUNs de iSCSI ou outros tipos de armazenamento em SAN. Nesses casos, o arquivo ou dispositivo que representa o disco da VM não está visível da mesma forma para todos os hosts, o que impede que o mecanismo padrão de file locking funcione corretamente. Isso acontece porque esses dispositivos existem apenas localmente em cada host, mesmo que representem o mesmo volume no storage.
Para resolver esse problema, o libvirt permite configurar um diretório compartilhado dedicado apenas para armazenar arquivos de lock. Essa configuração é feita no arquivo /etc/libvirt/qemu-lockd.conf. Para isso, é necessário usar o parâmetro file_lockspace_dir, como valor dele, devemos fornecer um diretório existente, como abaixo:
file_lockspace_dir = "/var/lib/libvirt/lockd"
Esse diretório precisa estar em um filesystem compartilhado acessível por todos os hosts do cluster, normalmente montado via NFS. Quando uma VM é iniciada, o virtlockd cria um arquivo de lock dentro desse diretório e aplica o locking nesse arquivo. Como todos os servidores conseguem acessar esse diretório, eles também conseguem verificar se o disco da VM já está sendo utilizado.
Esse processo acima deve ser realizado por todos os servidores de virtualização!
Agora, apenas no servidor que irá fornecer o compartilhamento NFS, crie o diretório que armazenará os arquivos de lock:
sudo mkdir /var/lib/libvirt/lockd
Exporte esse diretório no arquivo /etc/exports:
/var/lib/libvirt/lockd *(rw,no_root_squash)
Agora aplique o export do NFS:
sudo exportfs -a
Agora adicione a montagem ao arquivo /etc/fstab apenas nos servidores de virtualização para que o diretório seja montado automaticamente:
IP_server_NFS:/var/lib/libvirt/lockd /var/lib/libvirt/lockd nfs rsize=8192,wsize=8192,timeo=14,intr,sync 0 0
Agora é só montar:
# Crie o diretório antes para não dar erro:
sudo mkdir /var/lib/libvirt/lockd
# Agora monte:
sudo mount -a
Dessa forma, mesmo quando os discos não estão em um filesystem compartilhado, o libvirt ainda consegue impedir que a mesma máquina virtual seja iniciada simultaneamente em dois hypervisors diferentes.
Sanlock
O sanlock é um mecanismo de locking distribuído parecido com o lockd, ele é usado em ambientes de virtualização com múltiplos hypervisors e storage compartilhado. Diferente do virtlockd, que utiliza POSIX file locking (fcntl) em arquivos do sistema, o sanlock funciona diretamente no storage compartilhado, utilizando um sistema de leases gravados em blocos do disco.
Quando um host inicia uma VM, ele registra um lease (uma espécie de reserva) no storage compartilhado. O sanlock utiliza dois tipos de armazenamento:
Diretório local de runtime
Normalmente localizado em
/var/lib/libvirt/sanlock.Área de lease no storage compartilhado
Os leases reais ficam armazenados no próprio storage compartilhado, geralmente em um arquivo especial ou um volume reservado para esse fim.
O sanlock é mais comum em ambientes como o oVirt ou clusters KVM com LVM ou iSCSI. Vamos ver como usar sanlock no libvirt. Primeiro vamos instalar alguns pacotes necessários para usar ele:
# Em todos os hypervisors que são RedHat:
sudo dnf install sanlock libvirt-lock-sanlock
# Em todos os hypervisors que são Debian/Ubuntu:
sudo apt install sanlock libvirt-daemon-driver-qemu
# Ative primeiro o watchdog:
sudo systemctl enable --now wdmd
# Depois inicie o sanlock:
sudo systemctl enable --now sanlock
Isso deve rodar em todos os hosts do cluster.
:::tip O que é o Watchdog? O watchdog é um mecanismo de segurança presente em muitos sistemas que serve para detectar quando um computador ou serviço parou de responder. Ele funciona como um temporizador de proteção: o sistema precisa “alimentar” esse temporizador periodicamente. Caso isso não aconteça dentro do tempo esperado, o watchdog assume que algo está errado e reinicia o servidor automaticamente.
Esse mecanismo pode ser implementado em hardware (por meio de um dispositivo dedicado na placa-mãe) ou em software no kernel do sistema operacional.
O wdmd (Watchdog Multiplexer Daemon) é um serviço que permite que diferentes aplicações utilizem o watchdog do sistema de forma segura. Em vez de cada aplicação acessar diretamente o dispositivo /dev/watchdog, o wdmd atua como um intermediário, controlando e distribuindo o uso do watchdog entre vários processos.
No contexto do sanlock, o wdmd é utilizado para garantir que um host que possui um lease ativo continue saudável. Enquanto o sanlock estiver funcionando corretamente, ele mantém comunicação com o wdmd, que por sua vez alimenta o watchdog do sistema.
Se ocorrer uma falha grave, por exemplo, o processo do sanlock travar ou o sistema parar de responder, o watchdog deixa de ser alimentado. Quando o temporizador expirar, o watchdog força a reinicialização automática do servidor. Isso garante que o lease mantido por esse host seja liberado, permitindo que outros servidores do cluster continuem operando normalmente.
O watchdog clássico do Linux se chama watchdog, ele pode ser instalado com o comando abaixo:
sudo apt install watchdog
:::
Agora vamos configurar o libvirt para usar sanlock:
# Edite o arquivo abaixo:
sudo vim /etc/libvirt/qemu.conf
## Procure ou adicione:
lock_manager = "sanlock"
Isso instrui o libvirt a usar o plugin de locking sanlock. Agora precisamos configurar o ID de cada host no sanlock. Cada host precisa de um número diferente e que seja único:
# Edite o arquivo abaixo:
sudo vim /etc/libvirt/qemu-sanlock.conf
Adicione:
host_id = 1
auto_disk_leases = 1
disk_lease_dir = "/var/lib/libvirt/sanlock"
A opção
auto_disk_leasesinstrui o libvirt a criar automaticamente leases para os discos das VMs.
Lembrando que cada host deve ter um ID diferente. Agora, apenas no servidor que irá fornecer o compartilhamento NFS, crie o diretório que armazenará os arquivos de lock:
sudo mkdir /var/lib/libvirt/sanlock
Exporte esse diretório no arquivo /etc/exports:
/var/lib/libvirt/sanlock *(rw,no_root_squash)
Agora aplique o export do NFS:
sudo exportfs -a
Agora adicione a montagem ao arquivo /etc/fstab apenas nos servidores de virtualização para que o diretório seja montado automaticamente:
IP_server_NFS:/var/lib/libvirt/sanlock /var/lib/libvirt/sanlock nfs hard,nointr 0 0
Agora é só montar:
# Crie o diretório antes para não dar erro:
sudo mkdir /var/lib/libvirt/sanlock
# Agora monte:
sudo mount -a
pag 263 - VM templating