© Copyright 2026 Ferrantino Francesco

I namespaces sono una funzionalità del kernel Linux che permette di suddividere e isolare le risorse del sistema. In questo modo il kernel è in grado di separare i processi tra loro facendo sì che ciascun gruppo abbia una propria visione del sistema indipendente dagli altri.




Nel precedente articolo abbiamo visto chroot, un meccanismo che limita la visione del filesystem ma non isola processi né risorse. Ogni namespace isola un particolare aspetto del sistema come i processi, la rete, il filesystem o gli utenti. È proprio la combinazione di più namespace che consente di creare ambienti fortemente isolati come quelli utilizzati dai container.

Quando si parla di namespaces in generale in realtà ci si riferisce a un insieme di namespaces distinti e non a un singolo meccanismo.

I tipi di namespace messi a disposizione dal kernel Linux:

Linux mette a disposizione alcuni comandi che permettono di osservare e analizzare i namespaces presenti nel sistema. Questi strumenti sono utili per capire quali namespaces esistono e come sono associati ai processi. Uno dei comandi principali è lsns che viene utilizzato per visualizzare i namespaces attualmente presenti sul sistema.

Le informazioni sui namespaces sono in /proc/<PID>/ns per vedere informazioni su namespace di un processo dato il suo PID.

lsns mostra tutti i namespace attivi nel sistema e quali processi li stanno usando:
frank@laptop01:~$ lsns
        NS TYPE   NPROCS   PID USER  COMMAND
4026531832 mnt        86  1548 frank /usr/bin/dbus-broker-launch --scope user
4026531833 net        74  1548 frank /usr/bin/dbus-broker-launch --scope user
4026531834 time       86  1548 frank /usr/bin/dbus-broker-launch --scope user
4026531835 cgroup     86  1548 frank /usr/bin/dbus-broker-launch --scope user
4026531836 pid        74  1548 frank /usr/bin/dbus-broker-launch --scope user
4026531837 user       74  1548 frank /usr/bin/dbus-broker-launch --scope user
4026531838 uts        86  1548 frank /usr/bin/dbus-broker-launch --scope user
4026531839 ipc        86  1548 frank /usr/bin/dbus-broker-launch --scope user
4026532636 user       12  3392 frank /opt/google/chrome/chrome --type=zygote -- crashpad-handler-pid=3383 --enable-crash-reporter=, --change-stack-guard-on-fork=enable
Il significato delle colonne:
  • NS: ID interno del namespace (inode)
  • TYPE: tipo di namespace
  • NPROCS: quanti processi ci stanno dentro
  • PID: processo principale del namespace
  • USER: utente proprietario
  • COMMAND: comando associato
Esempio della spiegazione della prima riga sopra:
4026531832 mnt 86 1548 frank /usr/bin/dbus-broker-launch --scope user
  • 4026531832 è l'identificativo interno del namespace (inode)
  • mnt è il namespace dei mount (filesystem)
  • 86 processi condividono questo namespace
  • il processo di riferimento è PID 1548
  • appartiene all’utente frank
  • è stato creato/gestito da dbus

Con il comando lsns è possibile osservare come i namespaces siano usati continuamente dal sistema operativo anche al di fuori dei container. Browser e servizi di sistema creano namespaces dedicati per aumentare isolamento e sicurezza.



PID namespace (Process ID)


Il namespace di tipo PID fa sì che i processi visti all’interno del namespace abbiano un PID differente rispetto a quelli visti dall’esterno. All’interno del namespace si riparte dal PID come se fosse un sistema a sé con un proprio albero di processi.

Esempio PID in un ambiente isolato
Aprire una shell bash dentro un nuovo ambiente isolato usando i namespaces Linux.
frank@laptop01:~$ sudo unshare --pid --fork --mount-proc bash
Il comando è così spiegato:
  • sudo: serve perché creare namespaces richiede privilegi di root
  • unshare: è il comando che chiede al kernel Linux di avviare un processo in un contesto separato, facendo in modo che da quel momento in poi alcune risorse di sistema come processi, filesystem o rete non siano più condivise con l’host
  • --pid: crea un nuovo PID namespace
  • --fork: indica ad unshare di creare un nuovo processo figlio e di eseguirlo all’interno del namespace appena creato
  • --mount-proc: monta un nuovo /proc dentro il namespace, fà sì che /proc mostri solo i processi del namespace e non quelli dell’host.
  • bash: è la shell che viene avviata dentro l’ambiente isolato

Dentro l'ambiente isolato nella shell con il comando ps aux vedrai la bash con PID 1 mentre fuori dall'ambiente isolato nell’host con il comando ps aux | grep bash vedrai la stessa bash ma con un PID completamente diverso.

A questo punto ti trovi all’interno del PID namespace. Ora esegui:

root@laptop01:~# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root   1   1.6  0.0 233464 5780 pts/2 S   09:07 0:00 bash
root   40    0.0  0.0 234384 4456 pts/2 R+  09:07 0:00 ps aux

Noterai che la shell in esecuzione ha PID 1 come se fosse il processo iniziale di un sistema a sé con un proprio albero dei processi.

Aprendo un secondo terminale sull’host e cercando lo stesso processo vedrai invece un PID differente:
frank@laptop01:~$ ps aux | grep bash
frank  7311  0.0  0.0 233608  5800 pts/1 Ss  08:49 0:00 /bin/bash
frank  7874  0.0  0.0 233608  5792 pts/3 Ss  08:57 0:00 /bin/bash
root   8520  0.0  0.1 246544 10496 pts/1 S+  09:07 0:00 sudo unshare --pid --fork --mount-proc bash
root   8554  0.0  0.0 246544  3028 pts/2 Ss  09:07 0:00 sudo unshare --pid --fork --mount-proc bash
root   8555  0.0  0.0 230368  2108 pts/2 S   09:07 0:00 unshare --pid --fork --mount-proc bash
root   8556 0.0  0.0 233464  5784 pts/2 S+  09:07 0:00 bash
frank  8728  0.0  0.0 231292  2644 pts/3 S+  09:10 0:00 grep --color=auto bash

All’interno del PID namespace questo processo aveva PID 1 mentre dall’esterno viene visto con PID 8556. È lo stesso processo ma con due PID diversi a seconda del namespace da cui viene osservato.

root   8556  0.0  0.0 233464  5784 pts/2 S+  09:07 0:00 bash

Questo esempio mostra come il PID namespace non crei nuovi processi ma isoli la vista dei PID uno dei meccanismi fondamentali su cui si basa l’isolamento dei container.

Quindi lo stesso processo può avere due PID diversi:
  • dentro il namespace: PID = 1
  • fuori dal namespace (host): PID = 8556
Quindi, possiamo eliminare il nuovo PID namespace appena creato e chiudere la shell al suo interno eseguendo il comando exit:
root@laptop01:~# exit
Sei uscito dalla bash che era PID 1 nel PID namespace e ora sei sull’host ed esegui:
frank@laptop01:~$ ps aux | grep bash
frank       7311  0.0  0.0 233608  5804 pts/1    Ss+  08:49   0:00 /bin/bash
frank       7874  0.0  0.0 233608  5792 pts/3    Ss   08:57   0:00 /bin/bash
frank       9134  0.0  0.0 231292  2516 pts/3    S+   09:19   0:00 grep --color=auto bash

Non vedi più nessun sudo unshare, nessun unshare e nessuna bash con PID 8556. Questo conferma che il PID namespace non esiste più e i processi al suo interno sono stati terminati.

INFO: monitorare i processi con htop
  • Premi F5 per attivare la Tree View (vista ad albero)
  • Premi F3 e cerca NOME_PROCESSO (esempio: stress) per visualizzare solo i processi interessati
  • Premi F2 -> Setup -> Display options per migliorare la leggibilità:
    • Tree View (se non attiva)
    • Show custom thread names
    • Highlight program path


Esempio PID in un ambiente isolato con esecuzione dell'applicazione stress

Ora ripetiamo lo stesso esperimento fatto con chroot con il comando stress ma usando un PID namespace.

Creiamo un nuovo PID namespace e apriamo una shell al suo interno:
frank@laptop01:~$ sudo unshare --pid --fork --mount-proc bash
All’interno del namespace eseguiamo stress:
root@laptop01:~# stress --cpu 1 --vm 1 --vm-bytes 100M&
Verifichiamo i processi:
root@laptop01:~# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 233464 5708 pts/2 S 10:48 0:00 bash
root 69 0.0 0.0 3552 2184 pts/2 S 11:01 0:00 stress --cpu 1
root 71 98.4 0.0 3552 696 pts/2 R 11:01 0:02 stress --cpu 1
root 72 96.0 0.6 105956 50284 pts/2 R 11:01 0:02 stress --cpu 1
root 80 0.0 0.0 234384 4440 pts/2 R+ 11:01 0:00 ps aux

All’interno del PID namespace, stress non eredita i PID dell’host. I processi partono da PID 1 e costruiscono un albero di processi separato.

root@laptop01:~# pstree -p | grep stress
        `-stress(69)-+-stress(71)
                     `-stress(72)

Il processo stress con PID 69 è il processo padre e da esso vengono generati due processi figli con PID 71 e 72.

Usare pidstat per visualizzare l'uso della CPU e della RAM:
frank@laptop01:~$ pidstat -u -r -p 69,71,72 1

Time UID PID %usr %system %guest %wait %CPU CPU Command
11:21:17 0 69 0,00 0,00 0,00 0,00 0,00 2 stress
11:21:17 0 71 99,00 0,00 0,00 0,00 99,00 1 stress
11:21:17 0 72 31,00 66,00 0,00 1,00 97,00 2 stress
Time UID PID minflt/s majflt/s VSZ RSS %MEM Command
11:21:17 0 69 0,00 0,00 3552 1964 0,02 stress
11:21:17 0 71 0,00 0,00 3552 588 0,01 stress
11:21:17 0 72 156407,00 0,00 105956 16812 0,21 stress

Aprendo un secondo terminale sull’host ed eseguendo:
frank@laptop01:~$ ps aux | grep stress
vediamo comunque i processi stress ma con PID diversi:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 6526 0.0 0.0 3552 2184 pts/2 S 11:01 0:00 stress --cpu 1 --vm 1 --vm-bytes 100M
root 6528 95.1 0.0 3552 696 pts/2 R 11:01 5:07 stress --cpu 1 --vm 1 --vm-bytes 100M
root 6529 93.0 0.0 105956 6088 pts/2 R 11:01 5:00 stress --cpu 1 --vm 1 --vm-bytes 100M
frank 6819 0.0 0.0 231292 2520 pts/3 S+ 11:07 0:00 grep --color=auto stress
notiamo che:
  • dentro il namespace i PID sono piccoli e isolati
  • fuori dal namespace l’host vede i PID reali

Il processo stress con PID 6526 è il processo padre e da esso vengono generati due processi figli con PID 6528 e 6529.

Il PID namespace non nasconde l’esecuzione dei processi, ma isola la loro visibilità tra l’interno del namespace e il sistema host. All’interno del namespace i processi hanno una propria vista dei PID mentre l’host continua a vederli con i PID reali.

root@laptop01:~# pstree -p | grep stress
| |-konsole(5938)-+-bash(5954)---sudo(6009)---sudo(6044)---unshare(6045)---bash(6047)---stress(6526)-+-str+

Terminare l'esecuzione del processo stress

Soluzione 1: uscendo direttamente dalla shell del namespace
root@laptop01:~# exit
Soluzione 2: terminare il processo stress dal namespace
Dal PID namespace possiamo terminare il processo padre e tutti i processi figli vengono terminati:
root@laptop01:~# kill 69
[1]+  Terminato                  stress --cpu 1 --vm 1 --vm-bytes 100M
root@laptop01:~# exit
Soluzione 3: terminare il processo stress dall'host
frank@laptop01:~$ sudo kill 6526
frank@laptop01:~$ ps aux | grep stress

Con i namespaces abbiamo risolto il problema della visibilità: i processi sono isolati all’interno del namespace e i PID risultano separati rispetto al sistema host.

L’esecuzione dei processi continua però a incidere sul sistema host: i PID namespace isolano i processi ma non limitano l’uso delle risorse.

Rimane quindi un problema evidente: stress può ancora saturare CPU e memoria.

Nel prossimo articolo vedremo i cgroups che permettono di limitare e controllare l’uso delle risorse completando il modello dei container Linux.



User namespace (UID/GID)


Il namespace USER isola gli ID utente. Questo significa che lo stesso utente può avere uno User ID diverso all’interno del namespace rispetto a quello che ha al di fuori di esso.

Esempio UID in 1 ambiente isolato

Per capire come funziona la mappatura degli UID (User ID) è possibile eseguire un comando all’interno di un nuovo USER namespace e aprire una shell al suo interno.

Informazioni sull'utente corrente:

frank@laptop01:~$ id
uid=1000(frank) gid=1000(frank) gruppi=1000(frank),36(kvm),971(libvirt) contesto=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

frank@laptop01:~$ unshare -U bash
Il comando è così spiegato:
  • sudo non serve
  • unshare esegue un processo in un ambiente isolato. E' il comando che chiede al kernel Linux di avviare un processo in un contesto separato, facendo in modo che da quel momento in poi alcune risorse di sistema come processi, filesystem o rete non siano più condivise con l’host
  • -U: crea un user namespace
  • bash: è la shell che viene avviata dentro l’ambiente isolato

In questo caso, eseguendo il comando id si nota che l’utente non è più frank ma nobody un utente senza privilegi: questo dimostra che gli UID e i permessi all’interno del namespace sono distinti da quelli del sistema host.

nobody@laptop01:~frank@laptop01:~frank@laptop01:~$ id
uid=65534(nobody) gid=65534(nobody) gruppi=65534(nobody) contesto=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

Con il flag --map-root-user è possibile far finta di essere root all’interno di un user namespace perché il nostro UID viene rimappato a 0. Dal punto di vista del processo che gira nel namespace sembriamo quindi l’utente root. In realtà si tratta solo di una mappatura interna: non siamo davvero root sul sistema host e provando ad accedere alla directory /root il risultato sarà permesso negato. Ciò garantisce l'aumento della sicurezza perché anche se l’app crede di essere root non può fare danni fuori dal namespace.

frank@laptop01:~$ unshare -U --map-root-user bash

root@laptop01:~# id
uid=0(root) gid=0(root) gruppi=0(root),65534(nobody) contesto=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
root@laptop01:~# ls /root
ls: impossibile aprire la directory '/root': Permesso negato



Cgroup namespace


Il namespace cgroup serve a nascondere al processo a quale cgroup appartiene.

I cgroup sono il meccanismo che Linux usa per dire a un processo quanta CPU, quanta memoria o quante altre risorse può consumare. Nei container servono soprattutto a evitare che un container si prenda tutte le risorse dell’host a scapito degli altri.

All’inizio i cgroup non erano isolati tra loro, quindi un processo poteva intravedere informazioni sui cgroup di altri container. Per migliorare l’isolamento è stato introdotto il cgroup namespace, che fa sì che ogni container veda solo i propri limiti e le proprie regole.




Time namespace


Il namespace TIME permette a un processo di vedere un boot time diverso. Con time non si intende l’ora dell’orologio ma il tempo di avvio del sistema (ad esempio quello usato da uptime). Questo meccanismo è usato soprattutto per mantenere coerente il tempo di esecuzione delle applicazioni quando un container viene spostato da una macchina a un’altra.
Il namespace TIME fa vedere al processo un tempo di avvio diverso del sistema. Non riguarda l’orologio o l’ora corrente ma da quanto tempo il sistema risulta acceso. Questo serve, ad esempio, quando un container viene spostato su un’altra macchina così l’applicazione continua a vedere un tempo coerente.

Questo comando mostra la data e l’ora di avvio del sistema (boot time) così come vista dall’host. È il tempo reale da quando la macchina è stata avviata.
uptime -s
Questo comando esegue uptime -s all’interno di un nuovo time namespace separato da quello dell’host.
sudo unshare -fT --boottime 13371337 uptime -s 

In pratica, al processo viene presentata una percezione del tempo diversa: il valore di boot time non è quello reale del sistema, ma uno artificiale, impostato manualmente con --boottime. Dal punto di vista del processo, il sistema sembra essersi avviato in un momento completamente diverso pur girando sulla stessa macchina.



Mount namespace (MNT)


Il mount namespace (mnt) fornisce a un processo una vista isolata del filesystem, assegnandogli un proprio insieme di mount separato da quello dell’host.


È possibile verificare quali namespace di mount sono utilizzati da un processo ispezionando il filesystem /proc:
  • le informazioni si trovano in /proc/<PID>/mountinfo
  • in alternativa, possiamo usare uno strumento come findmnt che mostra gli stessi dati in un formato più leggibile.
Per usare questi strumenti dobbiamo prima individuare il PID del container. Un modo semplice è usare docker inspect:
docker inspect -f '{{.State.Pid}}' <CONTAINER>
Una volta ottenuto il PID possiamo visualizzare le informazioni di mount del processo con:
findmnt -N <PID>
In alternativa, possiamo leggere direttamente il file del kernel:
cat /proc/<PID>/mountinfo

I container utilizzano un filesystem root memorizzato sotto /var/lib/docker, dove il runtime gestisce i livelli delle immagini tramite OverlayFS per efficienza e prestazioni. Poiché tutti i filesystem dei container risiedono in questa directory è fondamentale proteggerla con permessi adeguati e monitorarla, mentre i dettagli sui mount attivi sono visibili in /proc/[PID]/mountinfo.

ls /var/lib/docker
sudo cat /proc/[PID]/mountinfo
Strumenti Linux come nsenter permettono di interagire direttamente con i namespace di un container ed eseguire comandi al suo interno senza usare la Docker CLI.
sudo nsenter --target [PID] --mount ls /
Esempio MNT confronto del mount namespace in due ambienti isolati e l'host

In questo esempio ci concentriamo esclusivamente sul mount namespace. Creiamo due ambienti separati e confrontiamo il comportamento dei mount tra ciascun ambiente e il sistema host.

L’obiettivo è mostrare che il mount namespace non modifica la vista iniziale del filesystem ma isola le modifiche ai mount.

1. Creazione di due ambienti con mount namespace
Apriamo due shell separate ciascuna con il proprio mount namespace ed esegui lo stesso comando:
frank@laptop01:~$ sudo unshare --mount --fork bash
Il comando è così spiegato:
  • sudo: necessario perché il mount namespace isola e modifica la visione del filesystem
  • unshare è il comando che chiede al kernel Linux di avviare un processo in un contesto separato, facendo in modo che da quel momento in poi alcune risorse di sistema come processi, filesystem o rete non siano più condivise con l’host
  • --mount crea un mount namespace: i mount fatti qui dentro non influenzano l’host
  • --fork: indica ad unshare di creare un nuovo processo figlio e di eseguirlo all’interno del namespace appena creato
  • bash: è la shell che viene avviata dentro l’ambiente isolato

2. Verifica iniziale dei mount
In entrambi gli ambienti e sull’host esegui:
frank@laptop01:~$ mount | head

Noterai che la lista dei filesystem montati è inizialmente identica: il mount namespace parte dalla stessa vista dell’host.


3. Modifica dei mount nel primo ambiente
Nel primo ambiente esegui:
root@laptop01:/home/frank# mkdir /tmp/mnt-ns1
  
root@laptop01:/home/frank# mount -t tmpfs tmpfs /tmp/mnt-ns1
  
root@laptop01:/home/frank# mount | grep mnt-ns1
tmpfs on /tmp/mnt-ns1 type tmpfs (rw,relatime,seclabel,inode64)

Il filesystem tmpfs è ora visibile solo nel primo ambiente.


4. Confronto con il secondo ambiente
Nel secondo ambiente esegui:
root@laptop01:/home/frank# mount | grep mnt-ns1

Non verrà mostrato alcun risultato: il mount non è condiviso tra i due ambienti.


5. Confronto con l’host
Sull’host esegui:
frank@laptop01:~$ mount | grep mnt-ns1

Anche in questo caso non verrà mostrato nulla: le modifiche al mount restano confinate al namespace.


6. Modifica dei mount nel secondo ambiente
Nel secondo ambiente esegui:
root@laptop01:/home/frank# mkdir /tmp/mnt-ns2

root@laptop01:/home/frank# mount -t tmpfs tmpfs /tmp/mnt-ns2
  
root@laptop01:/home/frank# mount | grep mnt-ns2
tmpfs on /tmp/mnt-ns2 type tmpfs (rw,relatime,seclabel,inode64)

Il mount è visibile solo nel secondo ambiente.



IPC namespace


L’IPC namespace fornisce isolamento per i meccanismi di comunicazione tra processi, come le code di messaggi POSIX, ed è abilitato di default nei container anche se spesso passa inosservato nei casi d’uso comuni.



Network namespace (NET)


Il network namespace (NET) fornisce a un processo un ambiente di rete isolato (interfacce, routing e porte) permettendo ai container di usare le proprie configurazioni di rete senza interferire tra loro.

E' possibile ispezionare il network namespace di un container usando strumenti Linux standard come nsenter, ottenendo prima il PID del container e poi accedendo al namespace di rete per analizzarne configurazione e indirizzi IP:
sudo nsenter --target 3619 -n ip addr
Esempio NET con 2 ambienti isolati in comunicazione tra loro e con l’host

In questo esempio creiamo due ambienti isolati: ogni ambiente è realizzato con namespace network in modo da ottenere un’istanza separata dal sistema host collegati tra loro.


Prima di iniziare il laboratorio è utile chiarire il ruolo dei principali elementi utilizzati negli esempi di configurazione dei network namespace.

Network namespace
  • ns1 – primo ambiente isolato a livello di rete. Possiede una propria interfaccia di loopback, una tabella di routing indipendente e non vede direttamente la rete dell’host.
  • ns2 – secondo ambiente isolato a livello di rete completamente separato da ns1 e dal sistema host.
Interfacce di rete virtuali (veth)

Le interfacce veth funzionano sempre a coppie e rappresentano un collegamento Ethernet virtuale tra due contesti di rete.

  • veth-host1 – estremità della coppia veth presente sul sistema host e collegata al namespace ns1.
  • veth-ns1 – estremità della stessa coppia veth spostata all’interno del namespace ns1 e visibile solo da esso.
  • veth-host2 – estremità della coppia veth presente sul sistema host e collegata al namespace ns2.
  • veth-ns2 – estremità della stessa coppia veth spostata all’interno del namespace ns2.
Relazione tra host e ambienti isolati
Host
 |__ veth-host1 _______ veth-ns1 -> ns1
 |__ veth-host2 _______ veth-ns2 -> ns2

In questo laboratorio l’host possiede entrambe le interfacce veth-host1 e veth-host2 e agisce da punto di collegamento (router) tra i due ambienti isolati.

I network namespace forniscono l’isolamento della rete mentre le interfacce veth permettono la comunicazione controllata tra ambienti isolati e sistema host.


1. Creazione della rete degli ambienti isolati
Sull'host eseguiamo i rispettivi comandi:
frank@laptop01:~$ sudo ip netns add ns1
frank@laptop01:~$ sudo ip netns add ns2

Questi comandi creano i network namespace che verranno utilizzati dai due ambienti isolati.

Verifica sull’host:
frank@laptop01:~$ ip netns list

2. Creazione delle interfacce virtuali

Sull’host creiamo due coppie di interfacce virtuali (veth) che collegano ciascun ambiente isolato al sistema host.

Comandi eseguiti sull’host:
frank@laptop01:~$ sudo ip link add veth-ns1 type veth peer name veth-host1
frank@laptop01:~$ sudo ip link add veth-ns2 type veth peer name veth-host2
Associare un’estremità di ogni coppia al rispettivo ambiente isolato:
frank@laptop01:~$ sudo ip link set veth-ns1 netns ns1
frank@laptop01:~$ sudo ip link set veth-ns2 netns ns2

3. Configurazione della rete sull’host
Comandi eseguiti sull’host:
frank@laptop01:~$ sudo ip addr add 10.0.0.1/24 dev veth-host1
frank@laptop01:~$ sudo ip addr add 10.0.1.1/24 dev veth-host2
frank@laptop01:~$ sudo ip link set veth-host1 up
frank@laptop01:~$ sudo ip link set veth-host2 up

L’host diventa il punto di collegamento tra i due ambienti isolati.


4. Configurazione della rete nei due ambienti isolati

I seguenti comandi vengono lanciati dall’host ma eseguiti all’interno dei due ambienti isolati.

frank@laptop01:~$ sudo ip netns exec ns1 ip addr add 10.0.0.2/24 dev veth-ns1
frank@laptop01:~$ sudo ip netns exec ns1 ip link set veth-ns1 up
frank@laptop01:~$ sudo ip netns exec ns1 ip link set lo up

frank@laptop01:~$ sudo ip netns exec ns2 ip addr add 10.0.1.2/24 dev veth-ns2
frank@laptop01:~$ sudo ip netns exec ns2 ip link set veth-ns2 up
frank@laptop01:~$ sudo ip netns exec ns2 ip link set lo up

5. Abilitare il routing sull’host

Con net.ipv4.ip_forward=1 l’host diventa un punto di passaggio tra reti diverse permettendo la comunicazione tra i network namespace.

Comando eseguito sull’host:
frank@laptop01:~$ sudo sysctl -w net.ipv4.ip_forward=1

In questo laboratorio l’host non è solo un sistema di supporto ma svolge il ruolo di router software tra i due ambienti isolati.


6. Rotte e firewall
Ogni ambiente isolato conosce solo la propria rete locale. Per permettere la comunicazione con l’altro ambiente è necessario configurare una rotta di default verso l’host che agisce da router tra le due reti.
Nel namespace ns1:
frank@laptop01:~$ sudo ip netns exec ns1 ip route add default via 10.0.0.1

Nel namespace ns2:
frank@laptop01:~$ sudo ip netns exec ns2 ip route add default via 10.0.1.1

Anche se il routing IP è abilitato sull’host il traffico tra i namespace può essere bloccato dal firewall. È quindi necessario consentire il forwarding tra le interfacce veth altrimenti i pacchetti vengono filtrati.

Se usi firewalld (Fedora / AlmaLinux / Rocky Linux)
frank@laptop01:~$ sudo firewall-cmd --zone=trusted --add-interface=veth-host1 --permanent
frank@laptop01:~$ sudo firewall-cmd --zone=trusted --add-interface=veth-host2 --permanent
frank@laptop01:~$ sudo firewall-cmd --reload

7. Avvio dei due ambienti isolati completi

Ora avviamo una shell completa all’interno di ciascun ambiente isolato aggiungendo anche il PID e il mount namespace.

Comandi eseguiti sull’host:
frank@laptop01:~$ sudo ip netns exec ns1 unshare --pid --mount --fork --mount-proc bash
frank@laptop01:~$ sudo ip netns exec ns2 unshare --pid --mount --fork --mount-proc bash

I due comandi avviano una shell bash in due ambienti isolati distinti ns1 e ns2. Ogni ambiente ha rete, processi e mount separati, con un proprio PID 1 e un /proc dedicato. I due ambienti non vedono né i processi né il filesystem né la rete l’uno dell’altro e dell’host.


8. Test di comunicazione tra ambienti isolati e host
Esecuzione all'interno dell'host:
frank@laptop01:~$ ip a
Esecuzione all'interno del primo ambiente isolato:
root@laptop01:~# ip a
root@laptop01:~# ping 10.0.1.2
Esecuzione all'interno del secondo ambiente isolato:
root@laptop01:~# ip a
root@laptop01:~# ping 10.0.0.2
Esecuzione all'interno del primo ambiente isolato verso l’host:
root@laptop01:~# ping 10.0.0.1
Esecuzione all'interno del secondo ambiente isolato verso l’host:
root@laptop01:~# ping 10.0.1.1

9. Esecuzione del comando stress nei due ambienti isolati

All’interno di ciascun ambiente isolato eseguiamo il comando stress.

Comando eseguito all’interno degli ambienti isolati:
root@laptop01:~# stress --cpu 1 --vm 1 --vm-bytes 100M&
Verifichiamo i processi nei due ambienti isolati:
root@laptop01:~# ps aux | grep stress
root@laptop01:~# pstree -p | grep stress

Ogni ambiente isolato vede processi con PID che partono da 1 mentre l’host continua a vedere l’esecuzione reale dei processi con PID differenti.


10. Uscita dai due ambienti isolati
Possiamo eliminare il nuovo network namespace appena creato e chiudere la shell al suo interno eseguendo il comando exit nei due ambienti isolati:
root@laptop01:~# exit

Ora sull’host esegui:

frank@laptop01:~$ ip a
frank@laptop01:~$ ps aux | grep stress

Il comando ip a eseguito sull’host mostra esclusivamente le interfacce di rete appartenenti al sistema host.

Dopo l’uscita dai due ambienti isolati con il comando exit rilanciando ip a sull’host si osserva che le interfacce veth-host1 e veth-host2 sono ancora presenti.

Questo comportamento è normale: la chiusura della shell termina i processi e il PID namespace ma non rimuove automaticamente le interfacce di rete né i network namespace.

Solo dopo aver eliminato esplicitamente le interfacce veth con il comando ip link delete e i network namespace con ip netns delete il comando ip a tornerà a mostrare esclusivamente le interfacce di rete originali dell’host.


11. Pulizia: eliminare le interfacce di rete create sull’host

Al termine del laboratorio è buona pratica rimuovere le interfacce veth create sull’host in modo da ripristinare lo stato iniziale della rete. Le interfacce veth-host1 e veth-host2 esistono sul sistema host e quindi vanno eliminate dall’host.

frank@laptop01:~$ sudo ip link delete veth-host1
frank@laptop01:~$ sudo ip link delete veth-host2

Dopo questi comandi verranno eliminati automaticamente anche:

  • veth-ns1
  • veth-ns2

Verifica che le interfacce non siano più presenti:

frank@laptop01:~$ ip link

Non dovresti più vedere veth-host1 e veth-host2.

Per eliminare completamente anche i network namespace creati per il test:

frank@laptop01:~$ sudo ip netns delete ns1
frank@laptop01:~$ sudo ip netns delete ns2

Verifica che l’elenco sia vuoto:

frank@laptop01:~$ ip netns list

Verifica che l’elenco sia vuoto:

frank@laptop01:~$ ip a

12. Pulizia aggiuntiva (opzionale): IP forwarding e firewalld

Se avevi abilitato il routing IP solo per questo esempio puoi disattivarlo:

frank@laptop01:~$ sudo sysctl -w net.ipv4.ip_forward=0

Se avevi aggiunto le interfacce alla zona trusted di firewalld puoi rimuoverle:

frank@laptop01:~$ sudo firewall-cmd --zone=trusted --remove-interface=veth-host1 --permanent
frank@laptop01:~$ sudo firewall-cmd --zone=trusted --remove-interface=veth-host2 --permanent
frank@laptop01:~$ sudo firewall-cmd --reload

Il comando ip a eseguito sull’host mostra esclusivamente le interfacce di rete appartenenti al sistema host.

In questo modo è possibile verificare visivamente che l’ambiente di test è stato completamente rimosso e che il sistema è tornato allo stato iniziale.



UTS namespace


Il namespace UTS consente a un processo di avere un proprio hostname isolato e viene abilitato di default dai runtime dei container, permettendo ai container di avere nomi host diversi da quelli dell’host o della VM sottostante.

Ferrantino Francesco

Ferrantino Francesco

Cookie Policy

Leggi  informativa Cookie Policy
Il "Sito" utilizza i Cookie per rendere i propri servizi semplici e efficienti per l’utenza che visiona le pagine di franksoft.it

Disclaimer

L'autore degli articoli non si assume nessuna responsabilità per eventuali danni ai vostri dispositivi. Tutto ciò che viene spiegato è puramente a scopo dimostrativo.
Il presente sito non costituisce testata giornalistica in quanto non ha carattere periodico ed è aggiornato secondo la mia disponibilità e la reperibilità dei materiali ivi contenuti. Pertanto, non può essere considerato in alcun modo un prodotto editoriale ai sensi della Legge n. 62 del 7/03/2001.

Licenza

Tutte le immagini presenti nel sito appartengono ai rispettivi titolari e sono utilizzate senza alcuno scopo di lucro. Ogni eventuale violazione del copyright non è intenzionale.
Quest'opera è distribuita con Licenza Creative Commons Attribuzione - Non commerciale - Non opere derivate 4.0 Internazionale.  Licenza Creative Commons