GNU/Linux >> Linux Esercitazione >  >> Linux

Costruire contenitori a mano:lo spazio dei nomi PID

Continuando con la serie degli spazi dei nomi, questo articolo copre il PID spazio dei nomi. Se vuoi una panoramica generale di tutti gli spazi dei nomi, dai un'occhiata al primo articolo. In precedenza, hai creato un nuovo mnt spazio dei nomi. È interessante notare che, come hai scoperto, anche dopo aver creato un nuovo mnt namespace, avevi ancora accesso agli ID di processo (PID) dell'host originale. Quando hai provato a montare /proc namespace, hai ricevuto il permesso negato piuttosto sconcertante errore, come mostrato di seguito:

root@new-mnt$ mount -t proc proc /procmount:permesso negato (sei root?)root@new-mnt$ whoamiroot 

Sebbene tu possa creare tutti i tipi di montaggio nel nuovo spazio dei nomi di montaggio, non puoi interagire o modificare /proc . In questo articolo, passo attraverso il PID namespace e dimostra come puoi usarlo, insieme a mnt namespace, per proteggere ulteriormente il tuo contenitore alle prime armi.

[ Ai lettori è piaciuto anche: Come funzionano gli spazi dei nomi PID di Linux con i container ]

Cosa sono gli ID processo?

Prima di entrare direttamente nel PID namespace, penso che sia una buona idea fornire solo un po' di background sul motivo per cui questo spazio dei nomi è importante.

Quando un processo viene creato sulla maggior parte dei sistemi operativi simili a Unix, gli viene assegnato uno specifico identificatore numerico chiamato ID processo (PID). Questo PID aiuta a identificare un processo in modo univoco anche se sono presenti due processi che condividono lo stesso nome leggibile. Ad esempio, se ci sono più sessioni ssh attive su un sistema ed è necessario chiudere una connessione specifica, il PID fornisce all'amministratore un modo per assicurarsi che la sessione corretta sia chiusa.

Tutti questi processi sono tracciati in uno speciale file system chiamato procfs . Sebbene questo file system possa tecnicamente essere montato ovunque, la maggior parte degli strumenti (e delle convenzioni) si aspettano i procfs da montare sotto /proc . Se fai un elenco di /proc , vedrai una cartella per ogni processo attualmente in esecuzione sul tuo sistema. All'interno di questa cartella ci sono tutti i tipi di file speciali utilizzati per tenere traccia di vari aspetti del processo. Ai fini di questo articolo, questi file non sono importanti. È sufficiente sapere che /proc è dove la maggior parte dei sistemi simili a Unix memorizza le informazioni relative ai processi su un sistema in esecuzione.

Lo spazio dei nomi PID

Uno dei motivi principali del PID namespace serve a consentire l'isolamento del processo. Più precisamente, come dice la pagina man:

Gli spazi dei nomi PID isolano lo spazio dei numeri ID del processo, il che significa che i processi in spazi dei nomi PID diversi possono avere lo stesso PID.

Questo è importante perché significa che è possibile garantire che i processi non abbiano un PID in conflitto con qualsiasi altro processo. Quando si considera un singolo sistema, ovviamente, non vi è alcuna possibilità che i PID siano in conflitto perché il sistema incrementa continuamente il numero ID del processo e non assegna mai lo stesso numero due volte. Quando si ha a che fare con contenitori su più macchine, questo problema diventa più importante. Come descritto nella pagina man:

Gli spazi dei nomi PID consentono ai contenitori di fornire funzionalità come la sospensione/ripresa dell'insieme di processi nel contenitore e la migrazione del contenitore su un nuovo host mentre i processi all'interno del contenitore mantengono gli stessi PID.

A parte l'isolamento, il sistema PID funziona quasi identica a quella al di fuori dello spazio dei nomi. Gli ID di processo all'interno del nuovo spazio dei nomi iniziano da 1 , con il primo processo considerato init processi. L'inizializzazione il processo viene gestito in modo molto diverso da tutti gli altri PID su un host. Ciò ha implicazioni particolari per il sistema in esecuzione che non rientrano nell'ambito di questa serie. Se sei interessato a maggiori informazioni, consulta la sezione "Segnali e processo di inizializzazione" dell'articolo Spazi dei nomi LWN.

Ciò che è degno di nota, tuttavia, è che qualunque processo abbia PID 1 è vitale per la longevità dei namespace. Se PID 1 viene terminato per qualsiasi motivo, il kernel invierà un SIGKILL a tutti i processi rimanenti nello spazio dei nomi, chiudendo di fatto lo spazio dei nomi.

Esplorazione degli spazi dei nomi PID

Se ti stai chiedendo, come me, se puoi annidare PID namespace, la risposta è sì. In effetti, il kernel fa spazio a un massimo di 32 PID nidificati spazi dei nomi. Questa è considerata una relazione a senso unico. Ciò significa che il genitore può vedere i PID di figli, nipoti, ecc. Tuttavia, non può vedere nessuno dei PID dei suoi antenati. Considera quanto segue:

[utente@localhost ~] sudo unshare -fp /bin/bash[root@localhost ~] sleep 90000 &[root@localhost ~] ps -efUID          PID    PPID  C STIME TTY          TIME CMD[troncato ].. ...root       11627   11620  0 09:16 pts/0    00:00:00 sudo unshare -fp /bin/bashroot       11633   11627  0 09:17 pts/0   00:00:00 unshare -fp /bin/bashroot 1   0 4 1  3   0 4 09:17 pts/0    00:00:00 /bin/bashroot       11639   11634  0 09:17 pts/0    00:00:00 sleep 90000root       11641   11634  0 09:17 pts/0    0 0 :00:[ps root @localhost ~] sudo unshare -fp /bin/bash[root@localhost ~] sleep 8000 &[root@localhost ~] ps -ef[troncato ].....UID          PID    PPID  C STIME TTY          TIME CMDroot       11650   11634  0 09 :17 pts/0    00:00:00 sudo unshare -fp /bin/bashroot       11654   11650  0 09:17 pts/0    00:00:00 unshare -fp /bin/bashroot       11655   11654  0 09:17 pts/0: 00:00 /bin/bashroot       11661   11655  0 09:17 pts/0    00:00:00 sonno 8000root       11671   11655  0 09:17 p ts/0    00:00:00 ps -ef 

Noterai che ho troncato l'output perché il PID lo spazio dei nomi appare per avere pieno accesso a tutti i PID in /proc . Osserva cosa succede se tenti di interrompere un processo che si trova in un predecessore:

[root@localhost ~] kill -9 11361bash:kill:(11361) - Nessun processo simile 

Perchè è questo? In poche parole, strumenti tradizionali come ps non sono in grado di riconoscere lo spazio dei nomi e in realtà vengono letti da /proc directory. Se hai eseguito un ls /proc , vedresti comunque tutte le cartelle e i file di prima perché, come discusso nell'ultimo articolo, il PID namespace eredita tutto il mnt monta lo spazio dei nomi. Affronterò questa situazione in seguito. Per ora, torna all'esempio in questione.

In un'altra shell, identifica i processi dormienti:

[user@localhost ~] ps -ef |grep sleeproot       11639   11634  0 09:17 pts/0    00:00:00 sleep 90000root       11661   11655  0 09:17 pts/0    00:00:00 sleep 800  

Se vuoi verificare che questi processi siano in spazi dei nomi diversi, dovrai trovare il bash PID di processo. Ricorda, dal momento che hai eseguito sudo unshare -fp /bin/bash , il bash processo è l'inizializzazione processo nel nuovo spazio dei nomi. Pertanto, è il PID che verrà collegato all'ID dello spazio dei nomi. Prendiamo i PID:

[root@localhost ~] ps -ef |grep bashroot       11627   11620  0 09:16 pts/0    00:00:00 sudo unshare -fp /bin/bashroot       11633   11627  0 09:17 pts/0    00 :00:00 unshare -fp /bin/bashroot       11634   11633  0 09:17 pts/0    00:00:00 /bin/bashroot       11650   11634  0 09:17 pts/0    00:00:00 sudo unshare -fp /bin/ bashroot       11654   11650  0 09:17 pts/0    00:00:00 unshare -fp /bin/bashroot       11655   11654  0 09:17 pts/0    00:00:00 /bin/bash 

Puoi vedere i PID 11634 e 11655 nell'uscita. Se lo confronti con l'output di lsns (elenca gli spazi dei nomi), vedrai quanto segue:

;

Come puoi vedere, gli ID dello spazio dei nomi sono diversi e quindi i processi si trovano in spazi dei nomi diversi.

Ora che hai stabilito che gli spazi dei nomi sono effettivamente diversi, diamo un'occhiata all'ascendenza PID menzionata prima. Puoi farlo identificando il NSpid attributo di un dato PID nel /proc directory, come mostrato di seguito:

sudo cat /proc/11655/status |grep NspidNSpid:    11655    6    1 

Le colonne vengono lette da sinistra a destra e indicano il PID nei rispettivi namespace. Il PID più a sinistra è lo spazio dei nomi primario o radice. In questo caso, ha un PID di 11655 , un PID secondario di 6 e un PID terziario di 1 . Poiché gli spazi dei nomi possiedono ogni PID discendente namespace, puoi pensarlo in questo modo:

  • Sull'host, il bash processo che esegue sleep 8000 comando ha un PID di 11655 .
  • Dentro il primo "contenitore", il bash processo che esegue sleep 8000 comando ha un PID di 6 .
  • All'interno del secondo "contenitore" nidificato, il PID è 1 . Questo è il contenitore che ha effettivamente avviato il processo.

Ognuno di questi bash è stato creato all'interno del proprio spazio dei nomi ma è visibile al genitore (in questo caso, il root spazio dei nomi).

/proc, PID e utenti non privilegiati

Il lettore attento avrebbe notato che, negli ultimi due articoli, un utente normale potrebbe creare entrambi gli utente e non spazi dei nomi. In questo articolo, ho utilizzato sudo comando. Questo perché non puoi creare un PID namespace da solo con un utente senza privilegi. La risposta è combinare più creazioni di spazi dei nomi in un unico evento. Esistono diverse soluzioni per il montaggio di /proc come utente non privilegiato.

Se provi semplicemente a creare un nuovo utente namespace, otterrai uno strano risultato:

[ user@localhost ~] unshare -Urp-bash:fork:Impossibile allocare memory-bash-5.1# ps -ef-bash:fork:Impossibile allocare memory-bash-5.1# ls-bash:fork:Impossibile allocare memoria 

Cosa sta succedendo qui? Ricorda come il primo processo all'interno di un nuovo PID namespace diventa init processi? In questo caso, la shell corrente non può spostare gli spazi dei nomi. Esiste nella radice namespace e quando hai creato un nuovo PID namespace, il sistema non sapeva come gestirlo. La soluzione a questo è avere il fork del processo stesso. Ciò consente alla shell corrente di diventare un processo figlio di unshare comando. Usando il -f flag risulta nella creazione dello spazio dei nomi:

[ utente@localhost ~] unshare -Urfp[ root@localhost ~] 

Tuttavia, vedi ancora la contaminazione di /proc punto di montaggio. Ci sono due soluzioni a questo. Innanzitutto, puoi creare un nuovo mnt namespace e quindi rimontare /proc te stesso:

[ user@localhost  ~]$ unshare -Urpmf[ root@localhost ~]# mount -t proc proc /proc[ root@localhost ~]# ps -efUID          PID    PPID  C STIME TTY          TIME CMDroot           1       0  0 09:31 pts/0    00:00:00 -bashroot          10       1  0 09:31 pts/0    00:00:00 ps -ef 

In effetti, per molti anni questa è stata l'unica opzione, ma un flag --mount-proc è stato creato qualche tempo fa per farlo in un unico passaggio. La pagina man recita:

Appena prima di eseguire il programma, montare il filesystem proc al punto di montaggio (l'impostazione predefinita è /proc). Ciò è utile quando si crea un nuovo spazio dei nomi PID. Implica anche la creazione di un nuovo spazio dei nomi di montaggio poiché il montaggio /proc altrimenti rovinerebbe i programmi esistenti sul sistema. Il nuovo filesystem proc è esplicitamente montato come privato (con MS_PRIVATE|MS_REC).

Quindi, quindi, potresti vedere riferimenti al seguente comando:

annulla condivisione -Urpf --mount-proc 

Questo crea un nuovo mnt namespace durante il montaggio di /proc per te.

Inserimento di uno spazio dei nomi

Per ridurre la complessità, sono uscito dagli spazi dei nomi creati in precedenza. Ho creato un nuovo spazio dei nomi con il seguente comando:

unshare -Urfp --mount-proc 

Ho anche creato un diverso sonno processo solo per aiutare a identificare lo spazio dei nomi. Dato che ho un solo nuovo spazio dei nomi, posso usare lsns comando per determinare il PID corretto:

[ user@localhost  ~]$ lsns |grep bash4026532965 pid         2 13142 user -bash 

Quindi esegui nsenter comando:

sudo nsenter -t 13142 -a 

Il -a flag dice a nsenter comando per inserire tutti gli spazi dei nomi di quel PID. sudo è richiesto con il -a flag, altrimenti non sarai in grado di passare a tutti gli spazi dei nomi appropriati. Ora dovresti essere in grado di elencare tutti i PIDS in questo NS:

; 00:00 sonno 99999root          25       0  0 10:15 pts/1    00:00:00 -bashroot          31      25  0 10:15 pts/1    00:00:00 ps -ef

[ Impara le basi dell'uso di Kubernetes in questo cheat sheet gratuito. ] 

Conclusione

Il PID lo spazio dei nomi è importante quando si tratta di costruire ambienti isolati. Consente ai processi di avere i propri PID indipendentemente dal sistema host. In un mondo in cui più host possono essere coinvolti nell'orchestrazione di ambienti isolati (container), diventa fondamentale disporre di una struttura che garantisca PID univoci durante il congelamento e la migrazione dei processi. Inoltre, per motivi di sicurezza, se stai eseguendo spazi dei nomi per l'isolamento delle applicazioni, il PID lo spazio dei nomi è fondamentale per prevenire la fuga di informazioni attraverso i processi in esecuzione di un host.

Se combinato con l'utente e non namespace, il PID namespace fornisce una grande protezione senza richiedere i privilegi di root. I browser moderni come Firefox e Vivaldi utilizzano gli spazi dei nomi per fornire il sandbox del browser. Nel prossimo articolo mostrerò la rete namespace e scopri come puoi continuare a costruire il tuo container manualmente aggiungendo componenti di rete discreti.


Linux
  1. Perché il Pgid dei processi figlio non è il Pid del genitore?

  2. Come ottenere l'ID del processo per terminare un processo nohup?

  3. Qual è il PID nell'host, di un processo in esecuzione all'interno di un contenitore Docker?

  4. Trovare il PID del processo utilizzando una porta specifica?

  5. Come ottenere il pid di un processo e invocare kill -9 su di esso nello script della shell?

Costruire un contenitore a mano usando gli spazi dei nomi:lo spazio dei nomi di montaggio

Quale processo ha Pid 0?

Come trovare il PID e il PPID di un processo in Linux

Se conosco il numero PID di un processo, come posso ottenere il suo nome?

Determinazione del particolare processore su cui è in esecuzione un processo

Come trovare il file .pid per un determinato processo