Points clés à retenir (TL;DR)
Synthèse exécutive- Une OVA VMware n'est pas bootable telle quelle sur Azure : il faut forcer les pilotes Hyper-V dans l'initramfs, activer la console serie et installer l'agent Azure.
- Le disque est converti en VHD taille fixe Gen2, televerse via le mode Upload d'un disque gere, puis transforme en image generalisee.
- La VM est deployee en Bicep, sans IP publique par defaut, dans un sous-reseau d'administration restreint par NSG.
- Chaque phase passe par un
what-ifavant creation : rien n'est provisionne sans validation explicite. - Le succes se mesure sur les boot diagnostics (chargement de
hv_storvsc, montage de la racine LVM) et un login SSH par cle.

Le probleme qu’on resout
Vous disposez d’une appliance Linux livree sous forme d’OVA VMware (par exemple une pile applicative conteneurisee) et vous souhaitez l’exploiter sur Azure plutot que sur un hyperviseur local. La tentation est d’uploader l’OVA directement ou de « bricoler » un import rapide. Cela echoue presque toujours, pour des raisons concretes :
- L’OVA cible le firmware et les pilotes VMware. Sur Azure, l’hyperviseur est Hyper-V : sans les modules
hv_vmbusethv_storvscdans l’initramfs, le disque racine n’est pas detecte et la VM ne boote jamais. - Azure n’offre pas de console graphique : si la console serie n’est pas configuree, vous etes aveugle en cas d’echec de boot.
- Le provisionnement (injection de cle SSH, redimensionnement, reseau) repose sur l’agent Azure (
walinuxagent) et cloud-init, souvent absents ou mal configures dans une image generique. - Le format de disque VMDK streamOptimized n’est pas accepte : Azure exige un VHD taille fixe, aligne, avec une taille declaree exacte.
L’objectif de ce guide est une procedure reproductible et sans surprise, ou l’adaptation de l’image se fait hors ligne et le deploiement est entierement scripte.
Comment ca marche
La demarche se decompose en deux grands temps : adapter l’image, puis deployer l’infrastructure.
L’adaptation consiste a rendre l’OS « Azure-compatible » : on injecte les pilotes Hyper-V, on active la sortie serie du noyau et de GRUB, on installe l’agent Azure, on laisse cloud-init gerer le provisionnement et on generalise l’image (suppression des cles SSH hote, du machine-id et de l’etat cloud-init). Toutes ces operations se font en chroot, hors ligne, sur le disque extrait de l’OVA. Attention a la chaine d’init : les distributions recentes utilisent dracut et non initramfs-tools, donc les reglages passent par /etc/dracut.conf.d/.
Cote plateforme, on televerse le VHD via le mode Upload d’un disque gere : on cree un disque vide en mode upload, on obtient un SAS d’ecriture, on copie avec azcopy (qui saute les blocs vides, donc seuls les ~8 Go reels transitent), puis on revoque l’acces. On transforme ce disque en image Gen2 generalisee, source d’une VM deployee en Bicep.
Prerequis
- Un abonnement Azure et un role Contributor sur le groupe de ressources cible.
- Azure CLI (
az) et l’outilazcopyinstalles sur un poste d’administration. qemu-imgpour la conversion de disque (disponible via conteneur si besoin).- Une paire de cles SSH dediee a la VM (stockee hors du depot, en coffre).
- Le fonctionnalite
UseStandardSecurityTypeenregistree si vous visez unsecurityType=Standard(Secure Boot desactive). - Un quota vCPU suffisant dans la region et la famille de taille visees (verifiez avant de deployer).
- L’OVA source et la place disque pour les artefacts intermediaires (raw + VHD).
Procedure
- Inspecter l’OVA : identifier l’OS, le firmware (UEFI → VM Gen2), le schema de partitionnement (EFI + /boot + LVM) et l’absence eventuelle de l’agent Azure.
- Extraire et convertir le disque VMDK en VHD taille fixe aligne (voir le script).
- Adapter l’image en chroot : pilotes Hyper-V dans dracut, console serie dans GRUB, installation de
walinuxagent, cloud-init en datasource Azure, generalisation. - Creer le reseau : un VNet d’administration et un NSG n’autorisant SSH que depuis votre IP d’administration.
- Televerser le disque via le mode Upload, puis revoquer le SAS.
- Creer l’image Gen2 generalisee a partir du disque.
- Deployer la VM (Bicep), sans IP publique, avec boot diagnostics actives.
- Etendre le disque dans la VM si la taille cible est superieure a celle de l’image.
- Valider via les boot diagnostics et un login SSH par cle.
Le script
Conversion de l’OVA en VHD Azure taille fixe (valeurs generiques). Le passage par un conteneur evite d’installer qemu-img sur l’hote.
# --- Extraction du VMDK depuis l'OVA ---
tar -xf appliance.ova appliance-disk1.vmdk
# --- Conversion VMDK -> raw -> VHD taille fixe, aligne 4k ---
qemu-img convert -f vmdk -O raw -S 4k appliance-disk1.vmdk disk.raw
qemu-img convert -f raw -O vpc -o subformat=fixed,force_size disk.raw appliance-azure.vhd
# Verifier la taille virtuelle (doit etre un multiple de 1 Mio)
qemu-img info appliance-azure.vhd
Reglages a appliquer en chroot sur le systeme de fichiers de l’appliance (distribution utilisant dracut) :
# 1) Forcer les pilotes Hyper-V dans l'initramfs
cat > /etc/dracut.conf.d/90-azure.conf <<'EOF'
force_drivers+=" hv_vmbus hv_storvsc "
add_drivers+=" hv_netvsc hv_utils "
EOF
dracut -f
# 2) Console serie dans GRUB
sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200n8 earlyprintk=ttyS0"/' /etc/default/grub
echo 'GRUB_TERMINAL="serial console"' >> /etc/default/grub
update-grub
# 3) Agent Azure
apt-get update && apt-get install -y walinuxagent
systemctl enable walinuxagent
# 4) cloud-init : datasource Azure
echo 'datasource_list: [ Azure, NoCloud, None ]' > /etc/cloud/cloud.cfg.d/90-azure.cfg
# 5) Generalisation (derniere etape avant capture)
rm -f /etc/ssh/ssh_host_*
truncate -s 0 /etc/machine-id
cloud-init clean --logs
Deploiement de l’infrastructure. Adaptez les variables en entete.
#!/usr/bin/env bash
set -euo pipefail
# --- Variables generiques ---
RG="rg-appliance-dev"
LOC="canadaeast"
DISK="disk-appliance"
IMAGE="img-appliance"
VM="vm-appliance"
VHD="appliance-azure.vhd"
SIZE_BYTES=214748364800 # 200 Gio declares dans l'image
VM_SIZE="Standard_D4as_v4" # verifier le quota de la famille visee
ADMIN_USER="azureadmin"
SSH_PUB="$HOME/.secrets/appliance/id_ed25519.pub"
# --- 0) Groupe de ressources ---
az group create -n "$RG" -l "$LOC"
# --- A) Disque gere en mode Upload (Gen2, Linux, HDD) ---
az disk create -g "$RG" -n "$DISK" --os-type Linux --hyper-v-generation V2 \
--sku Standard_LRS --upload-type Upload --upload-size-bytes "$SIZE_BYTES"
# Octroyer un SAS d'ecriture (attention : champ accessSAS, S majuscule)
SAS=$(az disk grant-access -g "$RG" -n "$DISK" --access-level Write \
--duration-in-seconds 86400 --query accessSAS -o tsv)
# Televersement : azcopy saute les blocs vides
azcopy copy "$VHD" "$SAS" --blob-type PageBlob
# Revoquer l'acces des que la copie est terminee
az disk revoke-access -g "$RG" -n "$DISK"
# --- A2) Image Gen2 generalisee depuis le disque ---
DISK_ID=$(az disk show -g "$RG" -n "$DISK" --query id -o tsv)
az image create -g "$RG" -n "$IMAGE" --hyper-v-generation V2 \
--os-type Linux --source "$DISK_ID"
# --- B) VM sans IP publique, boot diagnostics actives ---
az vm create -g "$RG" -n "$VM" --image "$IMAGE" --size "$VM_SIZE" \
--admin-username "$ADMIN_USER" --ssh-key-values "$SSH_PUB" \
--public-ip-address "" --nsg "" \
--os-disk-size-gb 256 --storage-sku Standard_LRS \
--security-type Standard --boot-diagnostics-storage ""
Apres le premier boot, etendre la partition et le volume logique a la taille du disque OS (ici 256 Go) :
# Sur la VM, via SSH
sudo growpart /dev/sda 3
sudo pvresize /dev/sda3
sudo lvextend -l +100%FREE /dev/mapper/appliance--vg-root
sudo resize2fs /dev/mapper/appliance--vg-root
df -h /
Validation
La validation ne repose pas sur « la VM apparait dans le portail » mais sur des preuves concretes :
- Recuperer le journal de boot serie :
az vm boot-diagnostics get-boot-log -g rg-appliance-dev -n vm-appliance
Dans la sortie, vous devez voir le noyau charger hv_storvsc, monter la racine LVM, puis lancer les services applicatifs (par exemple un moteur de conteneurs). C’est la preuve que les pilotes Hyper-V ont ete correctement injectes.
- Tester le login SSH par cle (le provisionnement cloud-init a reussi si la cle est injectee) :
ssh -i ~/.secrets/appliance/id_ed25519 azureadmin@<IP_PRIVEE>
# Puis dans la VM, verifier la pile applicative, p.ex. :
sudo docker ps --format '{{.Names}} {{.Status}}'
Attendu : tous les conteneurs en etat Up / healthy, et df -h / refletant la taille etendue.
Plan de retour (rollback)
Comme chaque phase est idempotente et additive, le retour en arriere est propre :
- Echec de boot : la VM n’etant pas en production, supprimez-la (
az vm delete) et conservez le disque/l’image pour diagnostic. L’OVA d’origine reste intacte. - Image incorrecte : regenerez l’image apres correction des reglages chroot ; l’ancienne image peut etre supprimee (
az image delete). - Reseau : les regles NSG sont des ressources enfant additives ; supprimez uniquement la regle fautive sans toucher a la regle SSH.
- Retour complet : supprimez le groupe de ressources dedie (
az group delete -n rg-appliance-dev) ; aucun composant partage n’est impacte.
Gardez toujours l’OVA source et le VHD converti : ils permettent de tout reconstruire en quelques minutes.
Depannage
| Symptome | Cause probable | Solution |
|---|---|---|
| Boot bloque, racine introuvable | Pilotes Hyper-V absents de l’initramfs | Ajouter hv_vmbus/hv_storvsc dans dracut.conf.d puis dracut -f, regenerer l’image |
| Aucune sortie dans les boot diagnostics | Console serie non configuree | Ajouter console=ttyS0,115200n8 et GRUB_TERMINAL, puis update-grub |
az disk grant-access renvoie un SAS vide |
Nom de champ sensible a la casse | Interroger --query accessSAS (S majuscule) selon la version d’az |
| Creation VM refusee : securityType non dispo | Fonctionnalite non enregistree | az feature register --namespace Microsoft.Compute --name UseStandardSecurityType puis re-register du provider |
| Erreur de quota a la creation | Quota vCPU de la famille a 0 dans la region | Deployer temporairement une famille disponible ou demander une hausse de quota |
| Cle SSH non injectee | Agent Azure/cloud-init absent ou mal configure | Installer walinuxagent, activer le service, verifier datasource_list |
Securite, changement et bonnes pratiques
- Moindre exposition : deployez sans IP publique. Si un acces externe est requis, ajoutez une IP publique statique et restreignez le NSG a vos seules IP sources (SSH 22, HTTPS 443) ; tout le reste est bloque par defaut.
- Secrets : la cle SSH privee ne doit jamais figurer dans un depot. Stockez-la en coffre (Key Vault ou gestionnaire de secrets) et limitez les droits de lecture.
- Moindre privilege : le role Contributor suffit pour deployer ; l’achat d’une reservation de capacite necessite un role dedie (par exemple Reservation Purchaser) a accorder temporairement.
- Certificat : une appliance expose souvent un certificat auto-signe. Prevoyez le remplacement par un certificat de votre PKI une fois le nom DNS en place.
- Cadrage ITIL : le premier deploiement est un changement normal a soumettre au CAB, avec fenetre de maintenance, plan de test et plan de retour documentes. Les redeploiements ulterieurs a parametres identiques peuvent devenir des changements standards (pre-approuves) une fois la procedure eprouvee.
- Sauvegarde : apres validation, activez Azure Backup ou des snapshots planifies du disque OS avant toute montee en charge.
A retenir
Deployer une appliance OVA sur Azure n’est pas un simple « glisser-deposer » : la cle du succes est l’adaptation hors ligne de l’image (pilotes Hyper-V, console serie, agent Azure) avant toute operation sur la plateforme. En scriptant chaque phase et en placant un what-if avant toute creation, vous obtenez un processus reproductible, auditable et reversible. Validez toujours par les boot diagnostics et un login SSH plutot que par l’etat affiche au portail.
Documentez votre version de la procedure, versionnez vos modeles Bicep et vos scripts, et faites valider le premier deploiement en CAB. Vous disposerez alors d’une base fiable pour industrialiser la mise en service de vos appliances sur Azure.