cloud-init, cloud image e Cloud Hypervisor

Três nomes que aparecem juntos e fazem coisas diferentes. Confundi-los é a causa mais comum de uma VM que arranca e não faz nada — ou que não arranca de todo.

Os três em uma frase

PeçaO que éQuando aparece
cloud image (cloud-img) Um disco .qcow2 publicado por uma distro, já instalado e pronto a arrancar. Não tem utilizador, nem password, nem chave SSH. O FROM de um VMfile, e o disco base de vm create.
cloud-init O programa que corre DENTRO dessa imagem no primeiro arranque e a personaliza: hostname, utilizadores, chaves, rede, comandos. É o que torna a cloud image utilizável. Sem ele, ficas com um disco genérico onde não consegues entrar.
Cloud Hypervisor Um VMM — o programa do HOST que executa a VM. Alternativa ao QEMU/libvirt, feito para microVMs. --backend cloud-hypervisor, e obrigatório para type: microvm.

Analogia com containers, que ajuda mais do que qualquer definição: a cloud image é a imagem, o cloud-init é o ENTRYPOINT da primeira execução, e o Cloud Hypervisor é o runtime — o equivalente ao runc.

1 · Cloud image — o disco

Cada distro publica um qcow2 pré-instalado, pequeno (algumas centenas de MB) e com o cloud-init já lá dentro. O motor sabe descarregar três famílias e verifica sempre o checksum — nunca aceita um download sem o confrontar.

# Num VMfile
FROM ubuntu:24.04        # cloud-images.ubuntu.com
FROM debian:bookworm     # cloud.debian.org
FROM rocky:9             # dl.rockylinux.org

# Ou directamente, sem VMfile nenhum
delonix vm create dev --url-img https://.../imagem.qcow2

Os três publicam checksums de maneiras diferentes, e isso está tratado: Ubuntu usa SHA256SUMS no formato GNU, Debian publica SHA512SUMS (não há SHA256 nenhum), e Rocky usa um .CHECKSUM por ficheiro no formato BSD SHA256 (ficheiro) = hash. Com --url-img, o motor procura um <url>.sha256 ao lado; se não existir, diz que está a confiar só no TLS em vez de calar.

O disco vem pequeno de propósito — tipicamente 2 GB. Cresce-o antes de instalares seja o que for, com SIZE 20G no VMfile: crescer depois de um RUN ter enchido o disco é tarde.

2 · cloud-init — a personalização do primeiro arranque

Uma cloud image acabada de descarregar não tem conta nenhuma. O cloud-init procura um datasource no arranque, lê de lá o user-data, e aplica-o. O Delonix usa o datasource NoCloud: gera um ISO por instância e liga-o à VM.

# O motor gera o seed sozinho quando lhe dás qualquer um destes
delonix vm create dev --hostname dev-01 --ssh-key ~/.ssh/id_ed25519.pub
delonix vm create dev --user-data ./user-data.yaml
delonix vm create dev --seed ./o-meu-seed.iso   # ISO já feito por ti

Um user-data mínimo e completo:

#cloud-config
hostname: dev-01
users:
  - name: delonix
    groups: [sudo]
    shell: /bin/bash
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
    ssh_authorized_keys:
      - ssh-ed25519 AAAA... o-teu-email@exemplo

package_update: true
packages: [nginx]

runcmd:
  - [systemctl, enable, --now, nginx]

final_message: "pronto em $UPTIME segundos"

Duas camadas, e a distinção importa. O CLOUDINIT de um VMfile é assado NA IMAGEM (fica em /etc/cloud/cloud.cfg.d) — é o comportamento por omissão de todas as VMs feitas a partir dela. O --user-data do vm create é POR INSTÂNCIA e assenta por cima. Uma é a receita da imagem, a outra é a configuração daquela VM.

Armadilha real, já paga: um kind: Vm sem seed nenhum fazia o cloud-init saltar a fase de rede, e a VM ficava sem IP e sem rota (Network is unreachable lá dentro). Por isso o motor gera sempre um seed mínimo, mesmo quando não pedes nada — não é opcional.

E o cloud-init só corre uma vez: guarda um marcador em /var/lib/cloud. Um vm restart não o volta a executar — para reaplicar, ou limpas esse estado dentro da VM ou crias outra.

3 · Cloud Hypervisor — o VMM

Quem executa a VM. O Delonix tem dois backends por trás do mesmo trait, e a escolha não é cosmética:

Cloud Hypervisorlibvirt/QEMU
ArranqueMuito rápido (dezenas de ms) — feito para microVMs Segundos; máquina completa emulada
DispositivosSó virtio, mínimoTudo (TPM, vídeo, USB, …)
Redetap na SDN do holder — alcança os containers por IP directo virbr0, no netns do HOST — outra L2
Isolamento por namespaceSim Não--namespace é recusado com erro, não aceite-e-ignorado
SnapshotsNão implementado (fail-closed, com erro que aponta para o libvirt) vm snapshot/restore: memória + disco
Arranque de cloud imagePrecisa de firmware (hypervisor-fw/EDK2) ou de kernel+initrd directos Arranca a cloud image tal como está
delonix vm create micro --backend cloud-hypervisor --firmware /usr/share/hypervisor-fw
delonix vm create pesada --backend libvirt          # default quando CH não está instalado

Qual usar, e quando

Se queres…Usa
Uma VM de trabalho, com snapshots e consola --backend libvirt (é o que a golden do Kubernetes exige — não arranca em CH)
Arranque em milissegundos, isolamento por namespace, ou alcançar containers por IP --backend cloud-hypervisor + firmware
Personalizar UMA VMcloud-init por instância: --hostname/--ssh-key/--user-data
Personalizar TODAS as VMs de um modeloUm VMfile com CLOUDINIT, e vm build
Um disco à tua medida, publicávelvm init --vmfilevm buildvm push

Onde isto falha, e o que ver

SintomaQuase sempre é
A VM arranca e não entras por SSH Sem seed de cloud-init — não há utilizador nenhum. Passa --ssh-key.
IP <none> para sempre libvirt caiu em modo user (SLIRP), cujo IP é invisível. Junta-te ao grupo libvirt — o motor avisa-o no create.
A VM não arranca em Cloud Hypervisor Falta o firmware. CH não faz boot BIOS: precisa de --firmware ou de --kernel+--initrd.
O disco enche a meio do vm build SIZE em falta, ou depois de um RUN. É propriedade da stage, e corre antes de tudo.
Mudaste o user-data e nada muda O cloud-init já correu naquela VM. Cria outra, ou limpa /var/lib/cloud lá dentro.

Referências