[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
<!---------------------------->
|
|
|
|
|
<!-- multilingual suffix: en, fr -->
|
|
|
|
|
<!-- no suffix: en -->
|
|
|
|
|
<!---------------------------->
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
# QEMU/KVM — Linux VM deployment (Ubuntu / Debian / Fedora)
|
|
|
|
|
|
|
|
|
|
`deploy_qemu.py` deploys a Linux VM (libvirt/KVM) from an official cloud
|
|
|
|
|
image, using `qemu-img` + `cloud-init` + `virt-install`. Pick the
|
|
|
|
|
distribution with `--distro` (`ubuntu` default, `debian`, `fedora`) and the
|
|
|
|
|
release with `--version`; run `--list-images` to see the full catalogue with
|
|
|
|
|
minimum specs. It:
|
|
|
|
|
|
|
|
|
|
1. **Downloads the cloud image by itself** (cached, no double download).
|
|
|
|
|
2. Converts it to a dedicated qcow2 working disk and resizes it.
|
|
|
|
|
3. Generates `user-data` / `meta-data` and builds the `seed.iso` (cloud-init).
|
|
|
|
|
4. Runs `virt-install` importing the disk + the seed as a CD-ROM.
|
|
|
|
|
5. Waits for the DHCP lease and prints the SSH command.
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
# QEMU/KVM — Déploiement de VM Linux (Ubuntu / Debian / Fedora)
|
|
|
|
|
|
|
|
|
|
`deploy_qemu.py` déploie une VM Linux (libvirt/KVM) à partir d'une image
|
|
|
|
|
cloud officielle, via `qemu-img` + `cloud-init` + `virt-install`. Choisissez
|
|
|
|
|
la distribution avec `--distro` (`ubuntu` par défaut, `debian`, `fedora`) et
|
|
|
|
|
la version avec `--version` ; `--list-images` affiche tout le catalogue avec
|
|
|
|
|
les specs minimales. Il :
|
|
|
|
|
|
|
|
|
|
1. **Télécharge lui-même l'image cloud** (mise en cache, sans double
|
|
|
|
|
téléchargement).
|
|
|
|
|
2. La convertit en un disque de travail qcow2 dédié et le redimensionne.
|
|
|
|
|
3. Génère `user-data` / `meta-data` et construit le `seed.iso` (cloud-init).
|
|
|
|
|
4. Lance `virt-install` en important le disque + le seed en CD-ROM.
|
|
|
|
|
5. Attend le bail DHCP et affiche la commande SSH.
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
## Prerequisites
|
|
|
|
|
|
|
|
|
|
- A host with KVM available (bare-metal or nested virtualization enabled).
|
|
|
|
|
- `sudo` rights (the deployment writes to `/var/lib/libvirt/images` and drives
|
|
|
|
|
libvirt).
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
The script **auto-installs the missing pieces it needs**: on first run it
|
|
|
|
|
detects your package manager (apt / dnf / pacman / zypper / brew), lists the
|
|
|
|
|
missing components (the client tools, **plus the libvirt daemon and the QEMU
|
|
|
|
|
system emulator**), asks for confirmation, installs them with `sudo`, then
|
|
|
|
|
enables and starts `libvirtd`. Use `-y` to accept automatically or
|
|
|
|
|
`--no-install-deps` to disable this behaviour.
|
|
|
|
|
|
|
|
|
|
To install everything manually on Ubuntu/Debian (recommended full KVM stack):
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
## Prérequis
|
|
|
|
|
|
|
|
|
|
- Un hôte disposant de KVM (bare-metal ou virtualisation imbriquée activée).
|
|
|
|
|
- Les droits `sudo` (le déploiement écrit dans `/var/lib/libvirt/images` et
|
|
|
|
|
pilote libvirt).
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
|
|
|
|
Le script **installe automatiquement les composants manquants** : au premier
|
|
|
|
|
lancement, il détecte votre gestionnaire de paquets (apt / dnf / pacman /
|
|
|
|
|
zypper / brew), liste les composants absents (les outils clients, **ainsi que
|
|
|
|
|
le démon libvirt et l'émulateur QEMU système**), demande confirmation, les
|
|
|
|
|
installe avec `sudo`, puis active et démarre `libvirtd`. Utilisez `-y` pour
|
|
|
|
|
accepter automatiquement ou `--no-install-deps` pour désactiver ce
|
|
|
|
|
comportement.
|
|
|
|
|
|
|
|
|
|
Pour tout installer manuellement sur Ubuntu/Debian (pile KVM complète
|
|
|
|
|
recommandée) :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
sudo apt install qemu-utils virtinst libvirt-clients cloud-image-utils \
|
|
|
|
|
libvirt-daemon-system qemu-system-x86
|
|
|
|
|
sudo systemctl enable --now libvirtd
|
|
|
|
|
sudo usermod -aG libvirt,kvm "$USER" # re-login / reconnectez-vous
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
`libvirt-daemon-system` provides the `libvirtd` daemon (and the
|
|
|
|
|
`/var/run/libvirt/libvirt-sock` socket) and `qemu-system-x86` the emulator —
|
|
|
|
|
without them `virt-install` fails with *"Failed to connect socket to
|
|
|
|
|
'/var/run/libvirt/libvirt-sock'"*. The script installs and starts them for
|
|
|
|
|
you; this manual command is only needed if you prefer to prepare the host
|
|
|
|
|
yourself or run with `--no-install-deps`.
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
|
|
Simplest form — the image is downloaded automatically (path derived from
|
|
|
|
|
`--version`, cached in `/var/lib/libvirt/images/iso`):
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
`libvirt-daemon-system` fournit le démon `libvirtd` (et le socket
|
|
|
|
|
`/var/run/libvirt/libvirt-sock`) et `qemu-system-x86` l'émulateur — sans eux
|
|
|
|
|
`virt-install` échoue avec *« Failed to connect socket to
|
|
|
|
|
'/var/run/libvirt/libvirt-sock' »*. Le script les installe et les démarre pour
|
|
|
|
|
vous ; cette commande manuelle n'est utile que si vous préférez préparer
|
|
|
|
|
l'hôte vous-même ou utiliser `--no-install-deps`.
|
|
|
|
|
|
|
|
|
|
## Utilisation
|
|
|
|
|
|
|
|
|
|
Forme la plus simple — l'image est téléchargée automatiquement (chemin déduit
|
|
|
|
|
de `--version`, mis en cache dans `/var/lib/libvirt/images/iso`) :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name test-vm --version 24.04 \
|
|
|
|
|
--ssh-key ~/.ssh/id_ed25519.pub
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
Download (and verify) an image without creating a VM:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Télécharger (et vérifier) une image sans créer de VM :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --download-only --version 24.04 --verify
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
Deploy with an interactive password instead of an SSH key:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Déployer avec un mot de passe interactif au lieu d'une clé SSH :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name test-vm --version 24.04 --ask-password
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
Larger VM (8 GB RAM, 8 vCPU, 120 GB disk), overwriting an existing disk:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
VM plus grande (8 Go RAM, 8 vCPU, disque 120 Go), en écrasant un disque
|
|
|
|
|
existant :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name test-vm --version 24.04 \
|
|
|
|
|
--memory 8192 --vcpus 8 --disk-size 120G --ask-password --force
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
Preview what would happen, without doing anything (no sudo, no download):
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Prévisualiser ce qui serait fait, sans rien exécuter (sans sudo, sans
|
|
|
|
|
téléchargement) :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
./script/qemu/deploy_qemu.py --name test-vm --version 24.04 --dry-run
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
Non-interactive deployment (accept dependency install automatically):
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Déploiement non interactif (accepte automatiquement l'installation des
|
|
|
|
|
dépendances) :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name test-vm --version 24.04 \
|
|
|
|
|
--ssh-key ~/.ssh/id_ed25519.pub -y
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
Supported Ubuntu versions: `20.04`, `22.04`, `24.04` (default), `24.10`,
|
|
|
|
|
`25.04`, `25.10`. Provide an explicit image path as a positional argument to
|
|
|
|
|
override the automatic download location.
|
|
|
|
|
|
[REM] install: drop Ubuntu 20.04 and 22.04
Two blockers on 20.04, neither worth carrying. "TypeError: unsupported
operand type(s) for |" fired before the install even started:
update_env_version.py imports erplibre_state as the very first thing
"make install_os" does, hence before pyenv, on the system Python 3.8,
where a "str | None" annotation is evaluated at import. And cryptography
now demands OpenSSL 3, while focal ships 1.1.1.
Annotations are therefore deferred, a contract the bootstrap file already
stated in a comment and now holds across script/version and
script/install. But the releases themselves go: pikepdf requires
qpdf >= 12.2, compiled in C++20, when focal ships GCC 9.
--- FR ---
Deux blocages sur 20.04, aucun ne méritant d'être porté. « TypeError:
unsupported operand type(s) for | » se déclenchait avant même le début de
l'installation : update_env_version.py importe erplibre_state en tout
premier lieu de « make install_os », donc avant pyenv, sur le Python 3.8
du système, où une annotation « str | None » est évaluée à l'import. Et
cryptography exige désormais OpenSSL 3, quand focal livre 1.1.1.
Les annotations sont donc différées, contrat que le fichier d'amorçage
énonçait déjà en commentaire et qui tient maintenant sur script/version et
script/install. Mais les versions elles-mêmes partent : pikepdf réclame
qpdf >= 12.2, compilé en C++20, quand focal livre GCC 9.
Assisted-by: Claude Opus 5
2026-08-11 08:03:32 -04:00
|
|
|
On **s390x**, `20.04` and `22.04` are **not supported**: no PyPI wheel exists
|
|
|
|
|
for that architecture, so everything is built against the distribution's
|
|
|
|
|
libraries, and pikepdf needs qpdf 12.2, whose build requires C++20. Focal
|
|
|
|
|
ships GCC 9 and publishes no `g++-10` for s390x — there is no way around it.
|
|
|
|
|
Use `24.04` or later. Both are still supported on amd64 and arm64, where pip
|
|
|
|
|
installs prebuilt wheels.
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
## After deployment
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Versions Ubuntu supportées : `20.04`, `22.04`, `24.04` (défaut), `24.10`,
|
|
|
|
|
`25.04`, `25.10`. Fournissez un chemin d'image en argument positionnel pour
|
|
|
|
|
surcharger l'emplacement de téléchargement automatique.
|
|
|
|
|
|
[REM] install: drop Ubuntu 20.04 and 22.04
Two blockers on 20.04, neither worth carrying. "TypeError: unsupported
operand type(s) for |" fired before the install even started:
update_env_version.py imports erplibre_state as the very first thing
"make install_os" does, hence before pyenv, on the system Python 3.8,
where a "str | None" annotation is evaluated at import. And cryptography
now demands OpenSSL 3, while focal ships 1.1.1.
Annotations are therefore deferred, a contract the bootstrap file already
stated in a comment and now holds across script/version and
script/install. But the releases themselves go: pikepdf requires
qpdf >= 12.2, compiled in C++20, when focal ships GCC 9.
--- FR ---
Deux blocages sur 20.04, aucun ne méritant d'être porté. « TypeError:
unsupported operand type(s) for | » se déclenchait avant même le début de
l'installation : update_env_version.py importe erplibre_state en tout
premier lieu de « make install_os », donc avant pyenv, sur le Python 3.8
du système, où une annotation « str | None » est évaluée à l'import. Et
cryptography exige désormais OpenSSL 3, quand focal livre 1.1.1.
Les annotations sont donc différées, contrat que le fichier d'amorçage
énonçait déjà en commentaire et qui tient maintenant sur script/version et
script/install. Mais les versions elles-mêmes partent : pikepdf réclame
qpdf >= 12.2, compilé en C++20, quand focal livre GCC 9.
Assisted-by: Claude Opus 5
2026-08-11 08:03:32 -04:00
|
|
|
Sur **s390x**, les `20.04` et `22.04` ne sont **pas supportées** : aucune roue
|
|
|
|
|
PyPI n'existe pour cette architecture, tout se compile donc contre les
|
|
|
|
|
bibliothèques de la distribution, et pikepdf réclame qpdf 12.2, dont la
|
|
|
|
|
compilation exige C++20. Focal livre GCC 9 et ne publie pas de `g++-10` pour
|
|
|
|
|
s390x — il n'y a pas de contournement. Utilisez la `24.04` ou plus récente.
|
|
|
|
|
Les deux restent supportées sur amd64 et arm64, où pip pose des roues
|
|
|
|
|
précompilées.
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
## Après le déploiement
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
virsh list --all
|
|
|
|
|
virsh console test-vm # Ctrl+] to quit / pour quitter
|
|
|
|
|
virsh domifaddr test-vm --source lease # find the IP / trouver l'IP
|
|
|
|
|
ssh erplibre@<IP>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
The default user is `erplibre` (change it with `--user`).
|
|
|
|
|
|
|
|
|
|
## Via the TODO menu
|
|
|
|
|
|
|
|
|
|
The script is integrated into the interactive assistant. Run `make todo` (or
|
|
|
|
|
`./script/todo/todo.py`), then go to **Execute → Deploy → QEMU/KVM - Deploy an
|
|
|
|
|
Ubuntu VM (libvirt)**. From there you can deploy a VM, preview a dry-run,
|
|
|
|
|
download an image, list VMs and show a VM IP address — the menu asks for the
|
|
|
|
|
parameters and builds the command for you.
|
|
|
|
|
|
|
|
|
|
## Main options
|
|
|
|
|
|
|
|
|
|
- `--distro` — `ubuntu` (default), `debian` or `fedora`.
|
|
|
|
|
- `--version` — release for the distro (default: the distro's default).
|
|
|
|
|
- `--list-images` — print all distros/versions and their specs, then exit.
|
|
|
|
|
- `--image-dir` — image cache directory (default `/var/lib/libvirt/images/iso`).
|
|
|
|
|
- `--download-only` — download the image then exit (no VM).
|
|
|
|
|
- `--name` — VM name (required for deployment).
|
|
|
|
|
- `--memory`, `--vcpus`, `--disk-size` — VM sizing. When omitted, `--memory`
|
|
|
|
|
and `--disk-size` default to the **minimum required by the chosen version**
|
|
|
|
|
(libosinfo values, see `--list-images`: Ubuntu 24.04+ → 3072 MB/20G, Debian
|
|
|
|
|
→ 1024 MB/10G, Fedora → 2048 MB/15G); `--vcpus` defaults to 2.
|
|
|
|
|
- `--ssh-key`, `--ask-password`, `--password-hash` — authentication.
|
|
|
|
|
- `-y` / `--assume-yes` — auto-accept dependency installation.
|
|
|
|
|
- `--no-install-deps` — never auto-install dependencies.
|
|
|
|
|
- `--dry-run` — show the commands without executing anything.
|
|
|
|
|
- `--force` — overwrite the existing working qcow2 disk.
|
|
|
|
|
|
|
|
|
|
Run `./script/qemu/deploy_qemu.py --help` for the full list.
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
L'utilisateur par défaut est `erplibre` (modifiable avec `--user`).
|
|
|
|
|
|
|
|
|
|
## Via le menu TODO
|
|
|
|
|
|
|
|
|
|
Le script est intégré à l'assistant interactif. Lancez `make todo` (ou
|
|
|
|
|
`./script/todo/todo.py`), puis allez dans **Execute → Deploy → QEMU/KVM -
|
|
|
|
|
Deploy an Ubuntu VM (libvirt)**. De là, vous pouvez déployer une VM,
|
|
|
|
|
prévisualiser un dry-run, télécharger une image, lister les VM et afficher
|
|
|
|
|
l'IP d'une VM — le menu demande les paramètres et construit la commande pour
|
|
|
|
|
vous.
|
|
|
|
|
|
|
|
|
|
## Principales options
|
|
|
|
|
|
|
|
|
|
- `--distro` — `ubuntu` (défaut), `debian` ou `fedora`.
|
|
|
|
|
- `--version` — version de la distro (défaut : celle par défaut de la distro).
|
|
|
|
|
- `--list-images` — affiche toutes les distros/versions et leurs specs.
|
|
|
|
|
- `--image-dir` — répertoire de cache des images (défaut
|
|
|
|
|
`/var/lib/libvirt/images/iso`).
|
|
|
|
|
- `--download-only` — télécharge l'image puis quitte (sans VM).
|
|
|
|
|
- `--name` — nom de la VM (requis pour le déploiement).
|
|
|
|
|
- `--memory`, `--vcpus`, `--disk-size` — dimensionnement de la VM. Omis,
|
|
|
|
|
`--memory` et `--disk-size` prennent le **minimum requis par la version**
|
|
|
|
|
choisie (valeurs libosinfo, voir `--list-images` : Ubuntu 24.04+ →
|
|
|
|
|
3072 Mo/20G, Debian → 1024 Mo/10G, Fedora → 2048 Mo/15G) ; `--vcpus`
|
|
|
|
|
vaut 2 par défaut.
|
|
|
|
|
- `--ssh-key`, `--ask-password`, `--password-hash` — authentification.
|
|
|
|
|
- `-y` / `--assume-yes` — accepte automatiquement l'installation des
|
|
|
|
|
dépendances.
|
|
|
|
|
- `--no-install-deps` — n'installe jamais les dépendances automatiquement.
|
|
|
|
|
- `--dry-run` — affiche les commandes sans rien exécuter.
|
|
|
|
|
- `--force` — écrase le disque de travail qcow2 existant.
|
|
|
|
|
|
|
|
|
|
Lancez `./script/qemu/deploy_qemu.py --help` pour la liste complète.
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
## Managing VMs
|
|
|
|
|
|
|
|
|
|
List, stop and remove VMs (the qcow2 disk under `/var/lib/libvirt/images`
|
|
|
|
|
is kept unless you delete it):
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
## Gestion des VM
|
|
|
|
|
|
|
|
|
|
Lister, arrêter et supprimer les VM (le disque qcow2 sous
|
|
|
|
|
`/var/lib/libvirt/images` est conservé tant que vous ne le supprimez pas) :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
sudo virsh list --all # toutes les VM et leur état / all VMs and state
|
|
|
|
|
sudo virsh shutdown <nom-vm> # arrêt propre ACPI / graceful shutdown
|
|
|
|
|
sudo virsh destroy <nom-vm> # arrêt forcé / force off (pull the plug)
|
|
|
|
|
sudo virsh undefine <nom-vm> # supprime la définition / remove definition
|
|
|
|
|
sudo virsh domifaddr <nom-vm> # adresse IP de la VM / VM IP address
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
`destroy` only powers the VM off (disk kept); `undefine` removes its
|
|
|
|
|
definition. To fully recreate a VM with the same name, `destroy` + `undefine`
|
|
|
|
|
it first, or redeploy with `--force`.
|
|
|
|
|
|
|
|
|
|
## SSH access from another machine (ProxyJump)
|
|
|
|
|
|
|
|
|
|
With the default NAT network the VM is reachable **only from the KVM host**.
|
|
|
|
|
To reach it from another machine **without changing the network**, use the
|
|
|
|
|
host as a jump host (it already reaches the VM). Get the VM IP with
|
|
|
|
|
`sudo virsh domifaddr <nom-vm>`, then from the other machine:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
`destroy` ne fait qu'éteindre la VM (disque conservé) ; `undefine` supprime sa
|
|
|
|
|
définition. Pour recréer proprement une VM du même nom, faites `destroy` +
|
|
|
|
|
`undefine` d'abord, ou redéployez avec `--force`.
|
|
|
|
|
|
|
|
|
|
## Accès SSH depuis une autre machine (ProxyJump)
|
|
|
|
|
|
|
|
|
|
Avec le réseau NAT par défaut, la VM n'est joignable que **depuis l'hôte
|
|
|
|
|
KVM**. Pour l'atteindre depuis une autre machine **sans toucher au réseau**,
|
|
|
|
|
utilisez l'hôte comme rebond (il joint déjà la VM). Récupérez l'IP de la VM
|
|
|
|
|
avec `sudo virsh domifaddr <nom-vm>`, puis depuis l'autre machine :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
# Rebond SSH vers la VM / jump through the KVM host
|
|
|
|
|
ssh -J user@<ip-hote> erplibre@<ip-vm>
|
|
|
|
|
|
|
|
|
|
# Tunnel d'un service, ex. Odoo 8069 / tunnel a service, then http://localhost:8069
|
|
|
|
|
ssh -L 8069:<ip-vm>:8069 user@<ip-hote>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
To make it permanent, add this to `~/.ssh/config` on the other machine (then
|
|
|
|
|
just `ssh myvm`):
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Pour le rendre permanent, ajoutez ceci à `~/.ssh/config` sur l'autre machine
|
|
|
|
|
(ensuite `ssh myvm` suffit) :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```text
|
|
|
|
|
Host myvm
|
|
|
|
|
HostName <ip-vm> # ex. 192.168.122.50 (reseau NAT)
|
|
|
|
|
User erplibre
|
|
|
|
|
ProxyJump user@<ip-hote> # IP LAN de l'hote KVM
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
This works over Wi-Fi and needs no VM shutdown — the simplest option for
|
|
|
|
|
personal access. Prefer a bridge (below) if the VM must be a full server
|
|
|
|
|
exposed on the LAN.
|
|
|
|
|
|
|
|
|
|
## QEMU inside QEMU (nested) & exposing the VM via a bridge
|
|
|
|
|
|
|
|
|
|
If the KVM host is **itself a VM** (QEMU-in-QEMU), the deployment works only
|
|
|
|
|
when **nested virtualization** is enabled on the outer/physical host and the
|
|
|
|
|
middle VM uses CPU mode `host-passthrough`. Check from inside the KVM host
|
|
|
|
|
(the first command must be non-empty):
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Ça marche en Wi-Fi et sans arrêter la VM — l'option la plus simple pour un
|
|
|
|
|
accès personnel. Préférez un pont (ci-dessous) si la VM doit être un serveur
|
|
|
|
|
à part entière exposé sur le LAN.
|
|
|
|
|
|
|
|
|
|
## QEMU dans QEMU (imbriqué) & exposer la VM via un pont
|
|
|
|
|
|
|
|
|
|
Si l'hôte KVM est **lui-même une VM** (QEMU dans QEMU), le déploiement ne
|
|
|
|
|
fonctionne que si la **virtualisation imbriquée** est activée sur l'hôte
|
|
|
|
|
physique et que la VM intermédiaire utilise le mode CPU `host-passthrough`.
|
|
|
|
|
Vérifiez depuis l'hôte KVM (la première commande doit être non vide) :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
grep -E -o '(vmx|svm)' /proc/cpuinfo | sort -u # extensions visibles / visible
|
|
|
|
|
# Sur l'hote PHYSIQUE / on the PHYSICAL host:
|
|
|
|
|
cat /sys/module/kvm_intel/parameters/nested # Intel -> Y/1
|
|
|
|
|
cat /sys/module/kvm_amd/parameters/nested # AMD -> Y/1
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
To enable nesting on the physical host (Intel shown; use `kvm_amd` on AMD),
|
|
|
|
|
then recreate the middle VM with `host-passthrough`:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Pour activer l'imbrication sur l'hôte physique (Intel montré ; `kvm_amd` sur
|
|
|
|
|
AMD), puis recréer la VM intermédiaire en `host-passthrough` :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
echo "options kvm_intel nested=1" | sudo tee /etc/modprobe.d/kvm-nested.conf
|
|
|
|
|
sudo modprobe -r kvm_intel && sudo modprobe kvm_intel # ou / or reboot
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
[IMP] qemu: a VM one can reach, and a first boot that does not stall
The monitor froze the address given at launch, so it lost the VM as soon as
cloud-init renamed the host and DHCP handed out another lease. It now
re-resolves at each attempt, in the views too, and reads virsh without sudo
— « sudo -n » fails in a detached session with no tty.
First boot also stopped paying for what it does not need: the guest agent
leaves cloud-init, snapd and locale-gen go, apt takes the fastest mirror.
The timezone follows the host. And when KVM is missing, the deployment says
so before the wait instead of being mysteriously fifteen times slower.
--- FR ---
Le suivi figeait l'adresse connue au lancement : il perdait donc la VM dès
que cloud-init posait le vrai nom d'hôte et que DHCP donnait un autre bail.
Il la ré-résout désormais à chaque tentative, dans les vues aussi, et lit
virsh sans sudo — « sudo -n » échoue dans une session détachée, sans tty.
Le premier démarrage cesse aussi de payer l'inutile : l'agent invité sort
de cloud-init, snapd et locale-gen disparaissent, apt prend le miroir le
plus rapide. Le fuseau suit l'hôte. Et faute de KVM, le déploiement le dit
avant l'attente, au lieu d'être quinze fois plus lent sans raison visible.
Assisted-by: Claude Opus 5
2026-08-10 03:10:50 -04:00
|
|
|
On **s390x and arm64** the parameter lives on the `kvm` module itself, not on
|
|
|
|
|
`kvm_intel` / `kvm_amd` — and `/sys/module/kvm/parameters/nested` does not even
|
|
|
|
|
exist on x86. Reading the wrong file returns a reassuring `0` that commands
|
|
|
|
|
nothing:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Sur **s390x et arm64**, le paramètre vit sur le module `kvm` lui-même, et non
|
|
|
|
|
sur `kvm_intel` / `kvm_amd` — et `/sys/module/kvm/parameters/nested` n'existe
|
|
|
|
|
même pas sur x86. Lire le mauvais fichier renvoie un `0` rassurant qui ne
|
|
|
|
|
commande rien :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
echo "options kvm nested=1" | sudo tee /etc/modprobe.d/kvm-nested.conf
|
|
|
|
|
sudo modprobe -r kvm && sudo modprobe kvm # ou / or reboot
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
`nested` on a machine means « let MY guests run VMs ». To accelerate a VM
|
|
|
|
|
created on host H, the setting belongs to the hypervisor **above** H, not to H
|
|
|
|
|
itself. The one command that settles it, run on H:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
`nested` sur une machine signifie « j'autorise MES invités à faire tourner des
|
|
|
|
|
VM ». Pour accélérer une VM créée sur l'hôte H, le réglage appartient à
|
|
|
|
|
l'hyperviseur **au-dessus** de H, pas à H. La commande qui tranche, sur H :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
ls -l /dev/kvm # absent -> pas d'imbrication, tout sera émulé
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
Measured on an s390x host that was itself a KVM guest without nesting:
|
|
|
|
|
`/dev/kvm` absent, `virsh dumpxml` showing `<domain type='qemu'>`, and a
|
|
|
|
|
7 min 30 boot instead of well under a minute. `systemd-detect-virt` inside the
|
|
|
|
|
VM is **not** proof of acceleration — on s390x, QEMU fabricates the STSI answer
|
|
|
|
|
and reports `kvm` even under TCG. Only `<domain type=…>` on the host is
|
|
|
|
|
conclusive.
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
If nesting is unavailable, QEMU still runs via software emulation (TCG) — it
|
|
|
|
|
works but is slow.
|
|
|
|
|
|
[IMP] qemu: a VM one can reach, and a first boot that does not stall
The monitor froze the address given at launch, so it lost the VM as soon as
cloud-init renamed the host and DHCP handed out another lease. It now
re-resolves at each attempt, in the views too, and reads virsh without sudo
— « sudo -n » fails in a detached session with no tty.
First boot also stopped paying for what it does not need: the guest agent
leaves cloud-init, snapd and locale-gen go, apt takes the fastest mirror.
The timezone follows the host. And when KVM is missing, the deployment says
so before the wait instead of being mysteriously fifteen times slower.
--- FR ---
Le suivi figeait l'adresse connue au lancement : il perdait donc la VM dès
que cloud-init posait le vrai nom d'hôte et que DHCP donnait un autre bail.
Il la ré-résout désormais à chaque tentative, dans les vues aussi, et lit
virsh sans sudo — « sudo -n » échoue dans une session détachée, sans tty.
Le premier démarrage cesse aussi de payer l'inutile : l'agent invité sort
de cloud-init, snapd et locale-gen disparaissent, apt prend le miroir le
plus rapide. Le fuseau suit l'hôte. Et faute de KVM, le déploiement le dit
avant l'attente, au lieu d'être quinze fois plus lent sans raison visible.
Assisted-by: Claude Opus 5
2026-08-10 03:10:50 -04:00
|
|
|
<!-- [fr] -->
|
|
|
|
|
Mesuré sur un hôte s390x lui-même invité KVM sans imbrication : `/dev/kvm`
|
|
|
|
|
absent, `virsh dumpxml` affichant `<domain type='qemu'>`, et un démarrage de
|
|
|
|
|
7 min 30 au lieu de bien moins d'une minute. `systemd-detect-virt` dans la VM
|
|
|
|
|
ne prouve **pas** l'accélération — sur s390x, QEMU fabrique la réponse STSI et
|
|
|
|
|
annonce `kvm` même en TCG. Seul `<domain type=…>` sur l'hôte fait foi.
|
|
|
|
|
|
[ADD] qemu: deploy ERPLibre VMs from cloud images
Deploys Ubuntu, Debian, Fedora and Arch cloud images through libvirt, on
amd64, arm64 and s390x. Handles the image download with mirror fallback,
the cloud-init seed, UEFI without Secure Boot, and the host setup.
--- FR ---
Déploie des images cloud Ubuntu, Debian, Fedora et Arch via libvirt, en
amd64, arm64 et s390x. Gère le téléchargement avec repli sur miroir, le seed
cloud-init, l'UEFI sans Secure Boot et la préparation de l'hôte.
Assisted-by: Claude Opus 4.8
2026-08-07 03:22:26 -04:00
|
|
|
### Bridge for external access
|
|
|
|
|
|
|
|
|
|
A NAT VM is isolated; a **bridged** VM gets an IP directly on the LAN,
|
|
|
|
|
reachable by any machine. On the KVM host, create a bridge `br0` over the
|
|
|
|
|
physical NIC (**wired only** — Wi-Fi cannot be bridged). netplan (Ubuntu
|
|
|
|
|
server) — replace `enp3s0` with your interface:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Si l'imbrication est indisponible, QEMU tourne quand même en émulation
|
|
|
|
|
logicielle (TCG) — ça marche mais c'est lent.
|
|
|
|
|
|
|
|
|
|
### Pont pour l'accès externe
|
|
|
|
|
|
|
|
|
|
Une VM en NAT est isolée ; une VM **pontée** obtient une IP directement sur le
|
|
|
|
|
LAN, joignable par n'importe quelle machine. Sur l'hôte KVM, créez un pont
|
|
|
|
|
`br0` sur la carte physique (**filaire uniquement** — le Wi-Fi ne se ponte
|
|
|
|
|
pas). netplan (Ubuntu serveur) — remplacez `enp3s0` par votre interface :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```yaml
|
|
|
|
|
# /etc/netplan/01-br0.yaml
|
|
|
|
|
network:
|
|
|
|
|
version: 2
|
|
|
|
|
renderer: networkd
|
|
|
|
|
ethernets:
|
|
|
|
|
enp3s0: {dhcp4: no, dhcp6: no}
|
|
|
|
|
bridges:
|
|
|
|
|
br0:
|
|
|
|
|
interfaces: [enp3s0]
|
|
|
|
|
dhcp4: yes
|
|
|
|
|
parameters: {stp: false, forward-delay: 0}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
Apply safely (auto-reverts if you lose the connection) and verify — or use
|
|
|
|
|
NetworkManager (Ubuntu desktop):
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Appliquez avec filet de sécurité (annulation auto en cas de coupure) et
|
|
|
|
|
vérifiez — ou via NetworkManager (Ubuntu bureau) :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
# netplan
|
|
|
|
|
sudo netplan try && sudo netplan apply
|
|
|
|
|
ip addr show br0 # br0 porte l'IP du LAN / br0 holds the LAN IP
|
|
|
|
|
|
|
|
|
|
# NetworkManager (alternative)
|
|
|
|
|
nmcli con add type bridge ifname br0 con-name br0
|
|
|
|
|
nmcli con add type ethernet ifname enp3s0 master br0 con-name br0-port
|
|
|
|
|
nmcli con modify br0 ipv4.method auto
|
|
|
|
|
nmcli con down "Wired connection 1" ; nmcli con up br0
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
Then attach the VM to the bridge — **either at creation**:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
Rattachez ensuite la VM au pont — **soit à la création** :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
sudo ./script/qemu/deploy_qemu.py --name <nom-vm> --version 24.04 \
|
|
|
|
|
--ssh-key ~/.ssh/id_ed25519.pub --network bridge=br0,model=virtio -y --force
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
**or by editing a VM already created**: stop it, replace its `<interface>`
|
|
|
|
|
block (`type='network'` / `<source network='default'/>` → `type='bridge'` /
|
|
|
|
|
`<source bridge='br0'/>`), then start it again:
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
**soit par édition d'une VM déjà créée** : arrêtez-la, remplacez son bloc
|
|
|
|
|
`<interface>` (`type='network'` / `<source network='default'/>` →
|
|
|
|
|
`type='bridge'` / `<source bridge='br0'/>`), puis redémarrez-la :
|
|
|
|
|
|
|
|
|
|
<!-- [common] -->
|
|
|
|
|
```bash
|
|
|
|
|
sudo virsh shutdown <nom-vm>
|
|
|
|
|
sudo virsh edit <nom-vm> # mettre l'interface en bridge=br0
|
|
|
|
|
sudo virsh start <nom-vm>
|
|
|
|
|
sudo virsh domifaddr <nom-vm> # nouvelle IP LAN / new LAN IP
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
<!-- [en] -->
|
|
|
|
|
The VM now gets a LAN IP from your router, reachable by other machines. From
|
|
|
|
|
the Internet you additionally need a port-forward on your router (or a VPN);
|
|
|
|
|
in a nested setup the outer host must also forward/expose the middle VM.
|
|
|
|
|
|
|
|
|
|
<!-- [fr] -->
|
|
|
|
|
La VM obtient maintenant une IP LAN de votre routeur, joignable par les autres
|
|
|
|
|
machines. Depuis Internet, il faut en plus une redirection de port sur votre
|
|
|
|
|
routeur (ou un VPN) ; en configuration imbriquée, l'hôte externe doit aussi
|
|
|
|
|
rediriger/exposer la VM intermédiaire.
|