Amazon Web Services (AWS) fournit un service de serveurs virtuels extensibles (Elastic Cloud, aka EC2) qui permet notamment de démarrer des serveurs Ubuntu à partir d’images disque complètes (sans installation). Ces serveurs utilisent, pour la partie stockage disque, des volumes EBS (Elastic Block Store), qui sont en quelque sorte des disques durs virtuels, de taille spécifiée par l’utilisateur, et facturés à l’usage en fonction de l’espace de stockage. S’il est très facile d’augmenter la taille de ces volumes, lorsque vos besoins augmentent, il est en revanche assez complexe et pénible de réduire leur taille. Sauf que, si vous avez des Go inutilisés sur un volume, et que vous gardez en plus des sauvegardes intégrales du disque (snapshots), chaque Go en trop vous est refacturé sur le volume EBS en cours d’utilisation, mais aussi sur toutes vos sauvegardes.
Note
Cette page a été initialement rédigée comme aide-mémoire personnel. Aucune des méthodes mentionnées n’a aboutie à un disque redimensionné fonctionnel et il faudrait débugger les erreurs résiduelles. Le débuggage distant de volume virtuels est une plaie et j’ai fini par quitter AWS EC2 de toute façon pour louer un VPS dédié, pour des raisons de coûts/performance. Par manque de temps, je publie tout de même mes notes pour ce qu’elles valent, car les étapes détaillées ici sont des préalables nécessaires. Gardez à l’esprit qu’il faudra simplement les compléter vous-même pour aboutir à un système utilisable.Introduction
La méthode détaillée ici n’est pas propre à AWS, mais s’applique pour toute tentative de copie intégrale de disque contenant l’OS vers un autre disque de taille différente qui sera utilisé dans la même machine.
L’incohérence des tailles d’origine et de destination nous empêche d’utiliser des méthodes simples et rapides comme la création d’image disque.
À la place, il va nous falloir recréer manuellement la table des partitions et copier tous les fichiers en respectant leurs propriétés système initiales (date, propriétaire et permissions).
Prérequis
On attend un serveur Linux (préférablement Ubuntu 22.04) installé sur une instance EC2 démarrée, et connectée à un volume EBS. Tout autre système qu’Ubuntu 22.04 pourrait demander des adaptations plus ou moins importantes de la méthode détaillée ici. Vous devez avoir un accès SSH vers le serveur.
Préparation
Taille de disque requise
Démarrez une console SSH vers votre serveur, puis exécutez :
On obtient par exemple :
Ici, on utilise un peu plus de 14 Go, c’est donc la taille minimale du nouveau volume.
Structure de la table de partitions
Exécutez :
On obtient par exemple :
On a donc 3 partitions sur le volume nvme1n1
. Les noms des disques et partitions peuvent varier sur votre système.
Exécutez ensuite :
On obtient par exemple :
Si l’on résume, on apprend donc que le volume est de type GPT et a 3 partitions, dans l’ordre du disque :
/dev/nvme1n1p14
, partition BIOS sans point de montage, d’index 14,/dev/nvme1n1p15
, partition EFI montée comme/boot/efi
, d’index 15,/dev/nvme1n1p1
, partition EXT4 montée comme/
, d’index 1.
Créer un nouveau volume
Dans votre console EC2 , créez un nouveau volume EBS de la taille minimale trouvée ci-dessus (ici, 15 Go), puis attachez le sur votre instance en fonctionnement.
Warning
Assurez vous de créer votre nouveau volume dans la même région AWS que votre instance, sinon il sera inaccessible.Dupliquer le volume actuel
Copier le volume contenant le système d’exploitation en fonctionnement, directement vers un nouveau volume, n’est pas conseillé et peut créer des incohérences. On va donc créer un doublon du volume, qui sera copié “froid”, dans la console EC2, en créant un snapshot du volume, puis un nouveau volume à partir de ce snapshot. Lorsque c’est fait, attachez le nouveau volume à votre instance.
Méthode 1 : création d’un nouveau système de fichiers miroir
Dans cette variante, on créée une table de partitions sur le volume cible qui reproduit en tout point la table de partition d’origine (sauf pour les tailles), et on copie les données.
Créer la nouvelle table de partitions
Une fois le nouveau volume EBS attaché à l’instance, exécutez depuis la console SSH de celle-ci :
On obtiendra par exemple :
Notre nouveau disque est donc identifié comme nvme0n1
.
Exécutez ensuite blkid
:
Ceci nous donne le label de chacune des partitions d’origine (cloudimg-rootfs
et UEFI
).
Pour créer une nouvelle table GPT
, exécutez donc :
puis tapez o
pour créer une nouvelle table vierge. L’idée est ensuite de reproduire la table de partitions du disque actuel :
Note
Ubuntu (et AWS) permettent d’avoir un volume entièrement chiffré. Dans cette configuration, l’amorçage (partition/boot/efi
) doit être séparé du disque chiffré, et donc non chiffré lui-même. La fonctionnalité est optionnelle, mais toutes les images disques utilisent donc cette configuration.- Partition BIOS :
- taper
n
(pour “nouvelle partition”), - tapez
14
(index de la partition) - choisissez le premier secteur par défaut,
- tapez
+4M
pour la taille, - tapez le code hexadécimal
ef02
pour créer une partition de type BIOS,
- taper
- Partition
/boot/efi
:- tapez
n
, - puis
15
, - choisissez le premier secteur par défaut
- tapez
+106M
pour la taille, - tapez le code hexadécimal
ef00
pour créer une partition de type EFI, - tapez
c
(pour “changer le nom de la partition), - tapez
15
, - saisissez
UEFI
(ou adaptez au label retourné par la commandeblkid
précédemment),
- tapez
- Partition racine
/
:- tapez
n
, - puis
1
, - laissez l’emplacement du premier secteur par défaut,
- laissez l’emplacement du dernier secteur par défaut (tout l’espace disque restant),
- laissez le code hexadécimal par défaut (système de fichier Linux),
- tapez
c
, - tapez
1
, - saisissez
cloudimg-rootfs
(adaptez encore le label si besoin).
- tapez
- Allez dans le mode “expert command” en tapant
x
:- tapez
c
pour changer lePARTUUID
, - tapez
15
pour la partition EFI, - saissisez le
PARTUUID
retourné parblkid
pour la partition EFI d’origine - recommencez pour la partition root (
1
).
- tapez
Finissez avec la commande w
(pour “write”), qui va écrire le nouveau partitionnement.
Vérifions que tout s’est bien passé. Exécutez lsblk
:
Exécutez sudo fdisk -l
:
Note
Lorsqu’on redimensionne un volume EBS dans la console AWS, c’est seulement la première partition (racine) qui est redimensionnée. On s’efforce donc de respecter l’ordre des partitions ici.Il faut ensuite créer le système de fichier pour nos deux nouvelles partitions :
Dupliquer les données
Monter les partitions
À ce stade, vous devriez avoir 3 volumes attachés à votre instance :
nvme1m1
, le système hôte, qui contient le volume trop grand, et qui fournit l’OS avec lequel nous interagissons depuis le shell SSH. Il est identifiable par le fait que ses partitions sont montées en tant que/
et/boot/efi
.nvme2n1
, le doublon du volume hôte, chargé à froid (l’OS n’est pas actif),nvme0n1
, le nouveau volume cible, plus petit, et vide à ce stade.
Les numéros peuvent changer dans votre cas. On va donc créer les nouveaux points de montage :
Puis on monte les partitions racines :
On recommence avec les partitions EFI :
Et on monte tout ça :
À ce stade, lsblk
retourne :
Copier le contenu des partitions
Exécutez :
Il est capital de respecter les slash ici car on effectue une copie récursive du contenu de /mnt/oldroot/
, oublier le dernier slash reviendrait donc à copier seulement le répertoire de plus haut niveau.
On traite ensuite le contenu de la partition BIOS, qui n’est pas un système de fichier :
Vérifier les nouvelles partitions
Démontez les partitions du nouveau volume :
Puis exécutez e2fsck
sur la nouvelle partition racine (EXT4) et dosfsck
sur la partition EFI (FAT32) :
Ces deux commandes vérifient l’intégrité des volumes et sont des préalables requis par la commande tune2fs
qu’on exécutera plus bas.
Réparer l’amorçage du volume
Les identifiants des tables et partitions (UUID) de notre nouveau volume ont changé. Le fichier /etc/fstab
copié sur le nouveau volume n’est donc plus valide, et GRUB doit être réinstallé.
fstab
Affichez le contenu du fichier /etc/fstab
. Par exemple :
On voit ici que les volumes sont références par label. On va donc s’assurer que les labels du nouveau volume sont corrects :
On va ensuite ré-appliquer l’UUID de l’ancien volume racine sur le nouveau (voir l’UUID de l’ancien dans la sortie de blkid
ci-dessus) :
On peut alors vérifier que tout s’est bien passé avec la commande lsblk -o name,mountpoint,label,size,uuid
:
On a donc adéquation entre les labels et les UUID, sur tous les clones.
Réinstaller GRUB
Vous remarquerez qu’on n’a rien fait sur la partition BOOT de 4 Mo. C’est normal : c’est GRUB qui s’en charge. La complexité est ici qu’on ne peut réinstaller GRUB que depuis l’intérieur du système, c’est à dire depuis l’intérieur de notre volume redimensionné. Sauf qu’en l’état, il ne bootera pas. Il nous faut donc chrooter depuis l’instance hôte avant de relancer l’installation de Grub.
On remonte tout dans l’ordre :
Puis on monte le système invité à la place du système hôte :
Puis on réinstalle GRUB :
Puis on un-chroot :
Relancer l’instance avec le nouveau volume
Éteignez votre instance, détachez tous les volumes, puis ré-attachez votre nouveau volume réduit à l’emplacement /dev/sda1
.
Méthode 2 : redimensionnement des partitions à chaud
Dans cette variante, on redimensionne directement le système de fichier puis les partitions de notre disque. L’avantage est de ne pas avoir à réinstaller GRUB ni le chargeur d’amorçage, l’inconvénient est de devoir calculer les nombres de secteurs à la main. Cette méthode se rapproche, en ligne de commande, de ce qu’on fait avec Gparted en interface graphique (et avec assistance). Travaillez dans tous les cas sur un volume dupliqué à partir d’un snapshot du volume initial.
Les commandes sont données directement, voir leurs explications dans la méthode précédente.
Lister les disques
Lister les partitions
Vérifier la partition à redimensionner
Vérifier la taille de partition minimale
Note : la taille est donnée en blocs.
Redimensionner le système de fichiers
Recréer la partition
Un peu de calcul… On a redimensionné le système de fichier (à l’intérieur de la partition) à 3854448 blocks de 4096 bits, donc on a un système de fichiers de 15787819008 bits, soit 14.7 GiB (on divise le nombre de bits par $2^{30}$). Avec les 100 Mo de partitions de boot, on est sur une taille de volume minimale pour le nouveau système de 14.8 GiB. AWS EC2 ne permet que des tailles arrondies au GiB entier, on va donc se donner un peu de marge de sécurité et monter à 16 GiB.
On vérifiée que gdisk
utilise une taille de secteur de 512 octets (4096 bits), donc un secteur gdisk
équivaut à un bloc de ext4
.
Méthode 3 : repartir d’une image disque
Notre principal problème, dans les méthodes précédentes, est de conserver les UID des partitions et le chargeur d’amorçage intact pour éviter d’endommager GRUB et de rendre le volume non bootable, tout en évitant d’endommager les systèmes de fichiers. Je n’ai pas réussi, pour des raisons difficiles à identifier sans accès physique au serveur.
La version la plus simple est de repartir d’une image Linux AWS vierge, dimensionnée à la taille souhaitée. Ensuite, il suffit de copier l’intégralité de la partition root /
d’origine vers le nouveau volume, à l’exception du fichier /etc/fstab
et du répertoire /boot
, qui contiennent des références vers les UID du disque cible. (Non testé).
Conclusion
C’est l’enfer. N’hésitez pas à dimensionner au plus juste vos volumes EBS car il suffit de quelques clics dans la console AWS pour les agrandir, alors que l’inverse est une sainte ostie de purge. Dans tous les cas, AWS EC2 a le mérite d’être flexible et adaptable, mais est plus cher qu’un serveur VPS à performances égales. À mon avis, il n’est pertinent que pour des besoins très réduits (en remplacement d’un serveur basé sur Raspberry Pie à domicile, par exemple), ou pour des instances en fonctionnement intermittent (lancées à la demande par des scripts, par exemple pour effectuer des tâches planifiées qui demandent un OS complet, pour lesquelles AWS Lambda ne suffirait pas).