Durante il fine settimana ho avuto la malaugurata sempre buona idea di andare a fare un po’ di manutenzione sul nodo Proxmox di casa e, tra le varie, aggiornare anche tutti i i LXC attivi.
In seguito all’aggiornamento, Uptime Kuma mi ha prontamente segnalato che alcuni container Docker erano KO, cosa che di solito non accade perché, nel post-aggiornamento di Docker e delle sue componenti, tutti i compose vengono fatti ripartire e i container tornano operativi in autonomia. Il nodo ha in pancia un paio di LXC che sono dedicati ad altrettanti servizi che girano – appunto – via Docker, esposti e isolati. Provando a fare un salto su Portainer e forzando l’avvio degli stack, ottengo questo errore:
Failed to deploy a stack: compose up operation failed: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: open sysctl net.ipv4.ip_unprivileged_port_start file: reopen fd 8: permission denied
Dato che volevo rapidamente riportare up&running i servizi, ho chiesto a ChatGPT di spiegarmi e cercare cosa stesse accadendo:
Con gli ultimi update il runtime tenta di impostare il sysctl
net.ipv4.ip_unprivileged_port_start=0all’avvio di ogni container, cosa che in un LXC unprivileged viene ora bloccata da AppArmor/cgroup → “permission denied”. Prima questo passaggio era più permissivo; una recente modifica in runc (per una fix di sicurezza) ha cambiato il modo in cui il sysctl viene applicato, e dentro LXC unprivileged ora salta fuori l’errore.Perché “proprio oggi”?
- runc/containerd aggiornati: c’è un bug/regressione recente in runc 1.3.x che, in LXC non privilegiati, fa fallire l’accesso al sysctl durante l’init del container. È correlato a un hardening introdotto per una CVE e impatta chi esegue Docker dentro LXC.
- Docker tende a settare quel sysctl a 0 di default per i container (così anche gli utenti non root possono aprire porte <1024). In LXC unprivileged, questa scrittura ora viene negata.
- Molti hanno visto il problema dopo “apt upgrade” su Proxmox LXC negli ultimi giorni; alcuni hanno risolto downgradando
containerd.ioa una build precedente.
Se sei curioso e vuoi approfondire, ti ho lasciato qualche riferimento (link) in fondo all’articolo.
Per poter rimettere in piedi il tutto, ho scelto di non effettuare un downgrade di containerd.io (vedi anche questa discussione sul forum di Proxmox), ho preferito modificare il comportamento del LXC e abilitare i permessi extra, così da permettere a sysctl di non rimanere bloccato. Per farlo, ho recuperato l’ID del LXC interessato e poi ho eseguito (occhio: 801, qui di seguito, è l’ID che ho usato io, nel tuo caso dovrai recuperarlo lanciando un pct list sulla console del tuo nodo Proxmox):
pct set 801 -features nesting=1,keyctl=1 echo "lxc.apparmor.profile: unconfined" >> /etc/pve/lxc/801.conf echo "lxc.cgroup2.devices.allow: a" >> /etc/pve/lxc/801.conf echo "lxc.cap.drop:" >> /etc/pve/lxc/801.conf pct restart 801
Dato che avrei dovuto ripetere da lì a poco la medesima operazione, ho scritto due righe di bash (che poi sono diventate ben più di due revisionando il codice con VSCode e Copilot, ma vabbè) per farlo più agilmente:
| #!/usr/bin/env bash | |
| # Proxmox LXC tuning script | |
| # Usage: sudo ./tune-pct.sh <CTID> | |
| # Applies: | |
| # - pct set <CTID> -features nesting=1,keyctl=1 | |
| # - AppArmor unconfined | |
| # - Allow all devices via cgroup2 | |
| # - Empty cap drop line | |
| # - pct restart <CTID> | |
| set -euo pipefail | |
| # --- Helpers --------------------------------------------------------------- | |
| usage() { | |
| echo "Usage: sudo $0 <CTID>" | |
| echo "Example: sudo $0 801" | |
| exit 1 | |
| } | |
| require_root() { | |
| if [[ ${EUID} -ne 0 ]]; then | |
| echo "Error: this script must be run as root." >&2 | |
| exit 1 | |
| fi | |
| } | |
| ensure_ct_exists() { | |
| local ctid="$1" | |
| if ! pct config "$ctid" >/dev/null 2>&1; then | |
| echo "Error: container $ctid does not exist." >&2 | |
| exit 1 | |
| fi | |
| } | |
| ensure_line_in_file() { | |
| # Appends the exact line to the file if it does not already exist. | |
| local line="$1" | |
| local file="$2" | |
| if ! grep -qF -- "$line" "$file"; then | |
| echo "$line" >>"$file" | |
| fi | |
| } | |
| # --- Main ------------------------------------------------------------------ | |
| main() { | |
| [[ $# -eq 1 ]] || usage | |
| require_root | |
| local CTID="$1" | |
| [[ "$CTID" =~ ^[0-9]+$ ]] || { echo "Error: CTID must be numeric."; exit 1; } | |
| ensure_ct_exists "$CTID" | |
| local CFG="/etc/pve/lxc/${CTID}.conf" | |
| # Safety backup before editing | |
| if [[ -f "$CFG" ]]; then | |
| cp -a "$CFG" "${CFG}.bak.$(date +%Y%m%d-%H%M%S)" | |
| else | |
| echo "Error: config file $CFG not found." >&2 | |
| exit 1 | |
| fi | |
| echo ">> Enabling features nesting=1,keyctl=1 on CT $CTID…" | |
| pct set "$CTID" -features nesting=1,keyctl=1 | |
| echo ">> Ensuring required lines are present in $CFG…" | |
| ensure_line_in_file "lxc.apparmor.profile: unconfined" "$CFG" | |
| ensure_line_in_file "lxc.cgroup2.devices.allow: a" "$CFG" | |
| # An empty value after the colon is intentional | |
| ensure_line_in_file "lxc.cap.drop:" "$CFG" | |
| echo ">> Restarting CT $CTID…" | |
| pct reboot "$CTID" | |
| echo "Done." | |
| } | |
| main "$@" |
Puoi scaricarlo sul tuo nodo Proxmox direttamente da GitHub:
wget https://gist.github.com/gioxx/b1b714956ad0dee685c1de52f65e4238/raw/9fb1c98fdb227a51a389b96d7008a00f76d01381/tune-pct.sh -O tune-pct.sh
A quel punto rendilo eseguibile (chmod +x tune-pct.sh) e lancialo così: ./tune-pct.sh 801
Salvo problemi, in console sul tuo nodo Proxmox dovresti vedere un messaggio simile a questo:
explicitly configured lxc.apparmor.profile overrides the following settings: features:nesting
A conferma che il container LXC sta ripartendo rispettando però i tuoi nuovi settaggi. Ora, sperando di non portare iella, dovresti riuscire a far ripartire tutto senza problemi.
In caso di dubbi, come al solito, hai l’area commenti a tua disposizione.
#KeepItSimple