Add a node script that shrinks a container's root disk
CI / pytest and ruff (push) Successful in 5m19s

scripts/pct-shrink-rootfs runs as root on the Proxmox node and keeps
the VMID. Without --yes it only measures and prints the plan.

It adds a temporary mp9 of the new size (Proxmox allocates and formats
it), rsyncs the root disk into it, and swaps it into rootfs under
Proxmox's config flock. The config is written like
file_set_contents does on pmxcfs (tmp file, then rename), after
checking that rootfs and mp9 did not change during the copy. The old
volume is kept as the first free unusedK and the exact delete command
is printed; pct rescan is not used, so other orphans of the VMID are
not pulled in.

It refuses snapshots and pending sections, a lock, template,
protection, HA, replication, any mount point, and sizes the data does
not fit (10 % headroom on top of the ext4 reserve and metadata, and an
inode check). On an rsync failure the new volume is freed by its volid.

Tests run the real script against stub pct, df, rsync, flock,
ha-manager, pvesr and id. README documents both shrink routes.

Design: docs/plans/lxc-shrink.md (section B).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DuckbootandClaude Opus 5.5 committed 2026-11-04 19:58:02 +01:00
1 parent 82902edfc8
commit 792667897a
3 files changed
+506 -1

No files matched your search

+34 -1
View File
@@ -47,7 +47,7 @@ uv run cv4pve-tui
| `Enter` then `o` | in info: edit autostart, startup order (order, up and down delay) and tags (one confirmed `set config` call; empty fields remove the setting) |
| `Enter` then `p` / `R` / `D` | in info: take a snapshot (name, description, VM: include RAM) / roll back to the snapshot under the cursor (confirms; starts the guest again if it is running) / delete the snapshot under the cursor (confirms) |
| `Enter` then `f` | in info: fstrim in a running VM with the guest agent enabled (confirms; containers: use `pct fstrim` on the node) |
| `Enter` then `r` | in info: restore the backup under the cursor, as a new VMID (default, the original stays untouched; a copy keeps the original's network settings, so leave Start off until they are changed) or overwriting the guest itself (stopped guests only; type the VMID, then confirm) |
| `Enter` then `r` | in info: restore the backup under the cursor, as a new VMID (default, the original stays untouched; a copy keeps the original's network settings, so leave Start off until they are changed) or overwriting the guest itself (stopped guests only; type the VMID, then confirm); container backups: optional smaller root disk, see *Shrinking a container's root disk* |
| `t` | shell in a running LXC container (`ssh -t root@<node> pct enter <vmid>`) |
| `l` | tasks: recent cluster tasks (start, duration, node, type, VMID, user, status; `!` marks failures); `Enter` shows the log of the task under the cursor, `g` reloads. In info: `l` = only this guest's tasks |
| `U` | package updates: pending updates per online node (node, package, current, new, origin, priority), read-only; `g` reloads. The list is as of the node's last `apt update`. The frame's bottom border shows the count |
@@ -69,6 +69,39 @@ A `!` in the first column marks a guest that no backup job covers (Proxmox's
Empty fields in the edit dialog are left unchanged. If a CPU/memory change cannot be
hot-plugged, the app tells you it applies at the next reboot.
## Shrinking a container's root disk
Proxmox only grows disks. Two ways to get a smaller container root disk, both
**dangerous**; take a backup first and test on a throwaway container.
**In the TUI** (`Enter`, then `r` on a container backup): fill in *Root disk GiB*.
This restores the backup as a **new** guest with a new, smaller root disk
(Proxmox's "advanced restore mode"); overwriting the original with a smaller disk is
refused, because Proxmox deletes the old disks before it unpacks the backup. In this
mode every mount point (`mpN`) of the backup is dropped: files of mount points with
`backup=1` land inside the root disk, `backup=0` ones are not in the backup at all.
Raw `lxc.*` lines (bind mounts too) can come back if cv4pve-cli runs as root@pam, so
do not run both guests at once. A disk that is too small makes the restore fail; the
original is untouched.
**On the node** (root shell, container stopped, keeps the VMID):
```sh
scripts/pct-shrink-rootfs <vmid> <new-size-GiB> # measure and print the plan
scripts/pct-shrink-rootfs --yes <vmid> <new-size-GiB> # do it
```
It adds a temporary `mp9` of the new size (Proxmox allocates and formats it), copies
the root disk into it with rsync, then swaps it into `rootfs` under Proxmox's config
lock. The old root disk stays as an `unusedK` volume until you delete it with the
exact `pct set <vmid> --delete unusedK` the script prints; the old config is copied to
`/root/pct-shrink-<vmid>-<timestamp>.conf`. It refuses containers with snapshots,
pending changes, a lock, template or protection flag, HA, replication, or any mount
point (`mpN`, `lxc.mount.entry`), and sizes the data does not fit with headroom
(5 % ext4 reserve, metadata, inodes). chattr flags (`+i`, `+a`) are not copied. Even
the dry run mounts the container briefly (`pct mount`). Design:
`docs/plans/lxc-shrink.md`.
## Development
```sh