Proxmox CLI

Proxmox CLI

Notes

Proxmox VM Alpine

Alpine Linux est une distribution Linux ultra-légère

Générer une paire de clé sur l’ordinateur de bureau PC1

Générer une paire de clé curve25519-sha256 (ECDH avec Curve25519 et SHA2) pour une liaison SSH avec la machine virtuelle

1
2
ssh-keygen -t ed25519 -o -a 100 -f ~/.ssh/vm200-tiny
chmod 600 ~/.ssh/vm200-tiny

La clé publique cat ~/.ssh/vm200-tiny.pub

1
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQzSLhJ6XvGs5O/65xglgHvp0YQpxFZ6VhhKPw85xCQ yann@pc1

Connexion ssh sur proxmox tiny

En mode su

Voici la procédure avec qm, en supposant l’ISO dans le stockage local (/var/lib/vz/template/iso/) et le disque sur local-lvm.

  • Nom utilisateur: alpa
  • Mot de passe: alpa49
  • Ip fixe: 192.168.0.224
  • Gateway: 192.168.0.254
  • Openssh + clé

Vérifier ISO et choisir un VMID

1
2
3
ls /var/lib/vz/template/iso/
pvesm list local --content iso
qm list    # pour repérer un VMID libre

Créer la VM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
qm create 200 \
  --name alpine01 \
  --ostype l26 \
  --memory 1024 \
  --cores 1 \
  --cpu host \
  --net0 virtio,bridge=vmbr0 \
  --scsihw virtio-scsi-single \
  --scsi0 local-lvm:8,discard=on,ssd=1 \
  --ide2 local:iso/alpine-virt-3.24.2-x86_64.iso,media=cdrom \
  --boot order='ide2;scsi0' \
  --agent enabled=1 \
  --serial0 socket \
  --onboot 1

Adapte le nom exact de l’ISO, la RAM et la taille du disque (ici 8 Go).

Démarrer et installer

1
qm start 200

Ouvre la console depuis l’interface web (VM 200 > Console), ou en CLI :

1
qm terminal 200    # nécessite la console série dans la VM, quitter avec Ctrl+O

Sans configuration supplémentaire, la console noVNC est le plus simple. Connecte-toi en root (pas de mot de passe), puis lance :

1
setup-alpine

Pour l’installation sur disque, choisis sda et le mode sys.

Procédure détaillée

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
 ALPINE LINUX INSTALL
----------------------

 Hostname
----------
Enter system hostname (fully qualified form, e.g. 'foo.example.org') [localhost] 

 Interface
-----------
Available interfaces are: eth0.
Enter '?' for help on bridges, bonding and vlans.
Which one do you want to initialize? (or '?' or 'done') [eth0] 
IPv4 address for eth0? (or 'dhcp', 'none', '?') [dhcp] 192.168.0.224
Netmask? [24] 
Gateway? (or 'none') [none] 192.168.0.254
IPv4 configuration for eth0:
  type=static
  address=192.168.0.224/24
  gateway=192.168.0.254
IPv6 address for eth0? (or 'auto', 'dhcp', 'none', '?') [auto] 
Do you want to do any manual network configuration? (y/n) [n] 
DNS domain name? (e.g 'bar.com') 
DNS nameserver(s)? 192.168.0.254

 Root Password
---------------
Changing password for root
New password: 
Bad password: too weak
Retype password: 
passwd: password for root changed by root

 Timezone
----------
Africa/            Egypt              Iran               Poland
America/           Eire               Israel             Portugal
Antarctica/        Etc/               Jamaica            ROC
Arctic/            Europe/            Japan              ROK
Asia/              Factory            Kwajalein          Singapore
Atlantic/          GB                 Libya              Turkey
Australia/         GB-Eire            MET                UCT
Brazil/            GMT                MST                US/
CET                GMT+0              MST7MDT            UTC
CST6CDT            GMT-0              Mexico/            Universal
Canada/            GMT0               NZ                 W-SU
Chile/             Greenwich          NZ-CHAT            WET
Cuba               HST                Navajo             Zulu
EET                Hongkong           PRC                leap-seconds.list
EST                Iceland            PST8PDT            posixrules
EST5EDT            Indian/            Pacific/

Which timezone are you in? (or '?' or 'none') [UTC] Europe
Amsterdam    Busingen     Kiev         Monaco       Sarajevo     Vaduz
Andorra      Chisinau     Kirov        Moscow       Saratov      Vatican
Astrakhan    Copenhagen   Kyiv         Nicosia      Simferopol   Vienna
Athens       Dublin       Lisbon       Oslo         Skopje       Vilnius
Belfast      Gibraltar    Ljubljana    Paris        Sofia        Volgograd
Belgrade     Guernsey     London       Podgorica    Stockholm    Warsaw
Berlin       Helsinki     Luxembourg   Prague       Tallinn      Zagreb
Bratislava   Isle_of_Man  Madrid       Riga         Tirane       Zaporozhye
Brussels     Istanbul     Malta        Rome         Tiraspol     Zurich
Bucharest    Jersey       Mariehamn    Samara       Ulyanovsk
Budapest     Kaliningrad  Minsk        San_Marino   Uzhgorod

What sub-timezone of 'Europe' are you in? (or '?') Paris

 * Seeding random number generator ...
 * Saving 256 bits of creditable seed for next boot
 [ ok ]
 * Starting busybox acpid ...
 [ ok ]
 * Starting busybox crond ...
 [ ok ]


  Proxy
-------
HTTP/FTP proxy URL? (e.g. 'http://proxy:8080', or 'none') [none] 

 APK Mirror
------------
 (f)    Find and use fastest mirror
 (s)    Show mirrorlist
 (r)    Use random mirror
 (e)    Edit /etc/apk/repositories with text editor
 (c)    Community repo enable
 (skip) Skip setting up apk repositories

Enter mirror number or URL: [1] c

Community repository enabled

Community repository enabled
 (f)    Find and use fastest mirror
 (s)    Show mirrorlist
 (r)    Use random mirror
 (e)    Edit /etc/apk/repositories with text editor
 (c)    Community repo disable
 (skip) Skip setting up apk repositories

Enter mirror number or URL: [1] 

Added mirror dl-cdn.alpinelinux.org
Updating repository indexes... done.

 User
------
Setup a user? (enter a lower-case loginname, or 'no') [no] alpa
Full name for user alpa [alpa] 
Changing password for alpa
New password: 
Bad password: similar to username
Retype password: 
passwd: password for alpa changed by root
Enter ssh key or URL for alpa (or 'none') [none] ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGQzSLhJ6XvGs5O/65xglgHvp0YQpxFZ6VhhKPw85xCQ yann@pc1
(1/1) Installing doas (6.8.2-r8)
Executing busybox-1.37.0-r31.trigger
OK: 10.5 MiB in 29 packages
Which ssh server? ('openssh', 'dropbear' or 'none') [openssh] 
 * service sshd added to runlevel default
 * Caching service dependencies ...
 [ ok ]
ssh-keygen: generating new host keys: RSA ECDSA ED25519 
 * Starting sshd ...
 [ ok ]

 Disk & Install
----------------
Available disks are:
  sda	(8.6 GB QEMU     QEMU HARDDISK   )

Which disk(s) would you like to use? (or '?' for help or 'none') [none] sda

The following disk is selected:
  sda	(8.6 GB QEMU     QEMU HARDDISK   )

How would you like to use it? ('sys', 'data', 'crypt', 'lvm' or '?' for help) [?] sys

WARNING: The following disk(s) will be erased:
  sda	(8.6 GB QEMU     QEMU HARDDISK   )

WARNING: Erase the above disk(s) and continue? (y/n) [n] y
Creating file systems...
Installing system on /dev/sda3:
/mnt/boot is device /dev/sda1
* creating /boot/initramfs-virt for 6.18.55-0-virt
* /boot is device /dev/sda1

Installation is complete. Please reboot.

Sortie terminal Ctrl + o

Arrêt

1
qm shutdown 200 # QEMU Guest Agent is not running - VM 200 qga command 'guest-ping' failed - got timeout

Retrait ISO ide2

1
qm set 200 --ide2 none,media=cdrom # update VM 200: -ide2 none,media=cdrom

Changer ordre de boot

1
qm set 200 --boot order=scsi0 # update VM 200: -boot order=scsi0

Démarrer la VM

1
qm start 200

Vérification interface web

En ligne de commande

1
qm config 200 | grep -E 'ide2|boot|agent'
1
2
3
4
5
6
qm agent 200 ping  
agent: enabled=1  
boot: order=scsi0  
ide2: none,media=cdrom  
onboot: 1  
QEMU guest agent is not running

La configuration côté Proxmox est correcte : l’ISO est retirée, le boot se fait sur scsi0 et l’agent est activé. Rien n’est en attente, donc les changements sont bien appliqués. Il reste à faire fonctionner l’agent dans la VM Alpine.

Passer en mode terminal root

1
qm terminal 200 # login root + Mot de passe

Vérifier dépôt communauté
Le fichier résultant devrait ressembler à ceci

1
2
3
#/media/cdrom/apks
http://dl-cdn.alpinelinux.org/alpine/v3.24/main
http://dl-cdn.alpinelinux.org/alpine/v3.24/community

Si incorrect, retirez le # en début de ligne.

1
sed -i 's/^#//' /etc/apk/repositories

Mise à jour

1
apk update

Agent invité (optionnel)

Dans la console de la VM

1
2
3
4
5
apk add qemu-guest-agent
rc-update add qemu-guest-agent default
rc-service qemu-guest-agent start
rc-service qemu-guest-agent status
ls /dev/virtio-ports/

Selon le résultat :

  • apk add échoue : la VM n’a probablement pas de réseau. Vérifie avec ip a et ping 1.1.1.1. Sans réseau, setup-alpine n’a pas configuré eth0, ce qui se corrige avec setup-interfaces puis rc-service networking restart.
  • /dev/virtio-ports/ n’existe pas : charge le module avec modprobe virtio_console, puis relance rc-service qemu-guest-agent restart. Pour le rendre permanent, echo virtio_console >> /etc/modules.
  • Le service refuse de démarrer : consulte cat /etc/conf.d/qemu-guest-agent. Si GA_PATH est défini, il doit valoir /dev/virtio-ports/org.qemu.guest_agent.0.

Teste ensuite depuis Proxmox (Optionnel)

1
qm agent 200 ping

Sans message d’erreur, l’agent fonctionne. Si /dev/virtio-ports/ reste vide malgré le modprobe, c’est que le canal n’a pas été créé au dernier démarrage. Dans ce cas, fais un qm stop 200 puis qm start 200.

Notes

  • --serial0, on peut l’omettre. Il n’est utile que pour qm terminal, et il faut alors ajouter console=ttyS0 dans la config du bootloader d’Alpine.
  • Pour une adresse IP fixe, configuration dans setup-alpine (interface eth0) ou dans /etc/network/interfaces.
  • Pour agrandir le disque plus tard : qm resize 200 scsi0 +4G, puis redimensionner le système de fichiers dans la VM.

Connexion ssh depuis PC1

1
ssh -i ~/.ssh/vm200-tiny alpa@192.168.0.224

sudo et curl

1
2
# Passer en root
su -

Installer sudo et curl

1
apk add sudo curl

Ajouter un utilisateur avec les privlèges root

1
echo "alpa     ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/20-alpa

Docker

Sur Alpine Linux, installer Docker et le plugin Docker Compose avec apk

1
2
# Mettre à jour l'index des paquets
sudo apk update
1
2
# Installer Docker et Docker Compose v2
sudo apk add docker docker-cli-compose

Pour utiliser Docker sans être root, ajouter utilisateur au groupe docker

1
sudo addgroup $USER docker

Ensuite, la session doit être rechargée pour que le groupe soit pris en compte. Déconnectez-vous / reconnectez-vous (ou redémarrez la session SSH)

Sur Alpine (OpenRC), il faut d’abord démarrer le service, puis l’activer au boot

1
2
3
4
# Démarrer Docker maintenant
sudo rc-service docker start
# Activer Docker au démarrage
sudo rc-update add docker default

Vérifie l’installation :

1
2
3
docker version
docker compose version
docker run --rm hello-world

Exemple minimal de test avec Compose :

1
2
3
4
5
6
7
8
9
10
11
12
mkdir -p ~/test-compose
cd ~/test-compose

cat > compose.yml <<'EOF'
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
EOF

docker compose up -d

Le conteneur sera accessible sur http://IP_DU_SERVEUR:8080. Pour l’arrêter :

1
docker compose down

Cette méthode utilise la commande moderne docker compose; l’ancien paquet docker-compose et la commande docker-compose ne sont généralement pas nécessaires.

Portainer

Agent portainer

L’agent portainer a besoin d’accéder au socket Docker pour récupérer les informations des conteneurs

1
2
3
4
5
6
7
# Déployer avec le socket Docker monté
docker run -d \
  --name portainer_agent \
  --publish 9001:9001 \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  --restart unless-stopped \
  portainer/agent:latest

Vérifications

1
docker ps | grep portainer_agent

Doit afficher “Up” (pas “Restarting”)

1
0ce01a4f2ecb   portainer/agent:latest   "./agent"   22 seconds ago   Up 22 seconds   0.0.0.0:9001->9001/tcp, [::]:9001->9001/tcp   portainer_agent

log

1
docker logs portainer_agent --tail 10

Doit afficher “agent running” sans erreurs

1
2026/10/05 04:28:44.514PM INF github.com/portainer/agent/cmd/agent/main.go:99 > agent running on Docker platform

Tester depuis cwwk

1
curl -vk https://192.168.0.224:9001/ping

Doit retourner < HTTP/2 204

Ajout environnement

Une fois que curl retourne 204 No Content depuis cwwk

  1. Portainer UI → https://192.168.0.205:9443 (https://portainer.home.arpa)
  2. Environment-related →Environments → Add environment
  3. Cocher Docker Standalone → Start wizard → Cocher Agent
  4. Name: alpine01, Environment URL: 192.168.0.224:9001
  5. Connect → Environment created

Maintenance

Suppression VM

proxmox cli, forcer l'arrêt d'une VM (impossible sur le web UI) et supprimer la VM entièrement (disque)

Depuis le shell du nœud Proxmox, remplacez VMID par l’identifiant de la VM.

1
VMID=200

Vérifiez d’abord la VM et son état :

1
2
qm status "$VMID"
qm config "$VMID"

Pour forcer l’arrêt :

1
qm stop "$VMID" --overrule-shutdown 1

Sur les versions où cette option n’est pas disponible, utilisez simplement :

1
qm stop "$VMID"

qm stop coupe immédiatement l’alimentation virtuelle de la VM : ce n’est pas un arrêt propre et il peut y avoir une vérification du système de fichiers au prochain démarrage.

Si la VM est verrouillée, par exemple après une tâche interrompue :

1
qm unlock "$VMID"

Puis relancez l’arrêt :

1
qm stop "$VMID"

Ensuite, pour supprimer complètement la VM ainsi que ses disques référencés :

1
qm destroy "$VMID"

Pour supprimer également les disques non référencés portant le même VMID — par exemple d’anciens disques, volumes ou disques devenus unused0 — utilisez :

1
qm destroy "$VMID" --destroy-unreferenced-disks 1

Commande complète typique :

1
2
3
4
5
VMID=123

qm stop "$VMID" --overrule-shutdown 1
qm unlock "$VMID" 2>/dev/null || true
qm destroy "$VMID" --destroy-unreferenced-disks 1

Cette opération est irréversible. L’option --destroy-unreferenced-disks peut supprimer tous les volumes correspondant à cette VM sur les stockages activés ; vérifiez donc la configuration avant :

1
qm config "$VMID"

Pour contrôler qu’il ne reste pas de volumes associés :

1
2
qm list
pvesm list <STORAGE> | grep -E "vm-${VMID}|${VMID}"

S’il y a une tâche de sauvegarde, migration, réplication ou suppression encore active, vérifiez-la avant de lancer qm destroy. La commande qm destroy supprime normalement la configuration et les disques référencés ; l’option supplémentaire sert surtout à nettoyer les disques non référencés.