1. Introducción al espacio de nombres de Linux
1.1 Concepto
El espacio de nombres de Linux es un mecanismo proporcionado por el kernel de Linux, que se utiliza para aislar las vistas de recursos de diferentes procesos, de modo que cada proceso tenga un espacio de recursos independiente, a fin de realizar el aislamiento y la gestión de recursos entre procesos .
El objetivo del diseño de Linux Namespace es proporcionar una tecnología de virtualización ligera para resolver el problema de los conflictos de recursos entre múltiples procesos . Al utilizar Namespace, se pueden crear múltiples entornos virtuales independientes en un host físico, cada uno con sus propias vistas de procesos, sistemas de archivos, redes y usuarios. Proporciona un mecanismo abstracto para aislar los recursos originalmente compartidos globalmente en diferentes colecciones. Los miembros de la colección disfrutan exclusivamente de sus recursos originalmente compartidos globalmente. Como se muestra abajo:
El proceso A y el proceso B pertenecen a dos espacios de nombres diferentes respectivamente, por lo que el proceso A podrá utilizar todos los recursos del espacio de nombres proporcionados por el kernel de Linux: como nombres de host independientes, sistemas de archivos independientes, números de procesos independientes, etc. De manera similar, el proceso B también puede usar recursos similares, pero sus recursos y los recursos utilizados por el proceso A están aislados entre sí y no pueden conocerse entre sí.
Desde la perspectiva del usuario, cada espacio de nombres debería ser como una computadora Linux separada, con su propio proceso de inicio (PID 1) y los PID de otros procesos aumentando en secuencia. Tanto el espacio A como el B tienen inicio con el PID 1. Proceso, el proceso del espacio de nombres secundario se asigna al proceso del espacio de nombres principal. El espacio de nombres principal puede conocer el estado de ejecución de cada espacio de nombres secundario y el espacio de nombres secundario se aísla del espacio de nombres secundario.
1.2 Conceptos relacionados con la virtualización
1.2.1 Tecnologías comunes de virtualización a nivel de procesos:
-
chroot(Change Root)
:chroot
Es una tecnología que cambia el directorio raíz del proceso a un directorio específico. Restringe el alcance de acceso al sistema de archivos del proceso para que el proceso solo pueda ejecutarse en el árbol de directorios especificado. Esto permite un cierto grado de aislamiento del proceso. -
Linux容器(Linux Containers,LXC)
:LXC
Es una tecnología de virtualización a nivel de sistema operativo que utiliza funciones como espacios de nombres(namespaces)
y grupos de control en el kernel de Linux(cgroups)
para lograr el aislamiento de procesos. El aislamiento a nivel de proceso y el control de recursos se pueden lograr creando y administrando múltiples instancias de contenedor, cada una con su propio sistema de archivos, red y espacio de proceso. -
Docker
: Docker es una capa de empaquetado basada en LXC que proporciona herramientas de implementación y administración de contenedores de nivel superior. Hace que el empaquetado, distribución e implementación de aplicaciones sea más conveniente mediante el uso de conceptos de imágenes y contenedores. Docker agrega algunas funciones y herramientas adicionales basadas en LXC para hacer el uso de contenedores más fácil y eficiente. -
systemd-nspawn
:systemd-nspawn
esSystemd
una herramienta del proyecto que proporciona un entorno de contenedor simple basado en el espacio de nombres y chroot de Linux. Puede iniciar un proceso y aislarlo en un entorno de sistema de archivos independiente, logrando el aislamiento del proceso y el control de recursos.
1.2.2 Tecnologías comunes de virtualización de Linux
Virtualización completa: la tecnología de virtualización completa simula un entorno de hardware virtual completo
ejecutando un monitor de máquina virtual en hardware físico . (Hypervisor)
En la virtualización completa, no es necesario modificar el sistema operativo invitado y puede ejecutar un sistema operativo no modificado. Los productos representativos incluyen:
KVM(Kernel-based Virtual Machine)
: KVM es una solución de virtualización completa de código abierto que proporciona capacidades de virtualización basadas en el kernel de Linux. KVM se utiliza como monitor de máquina virtual y proporciona aceleración de hardwareQEMU(Quick Emulator)
a través de extensiones de virtualización de hardware (como IntelVT-x
y AMD ).AMD-V
Paravirtualización:
la tecnología de paravirtualización modifica el sistema operativo dentro de la máquina virtual para que pueda comunicarse y cooperar con la capa de virtualización, mejorando así el rendimiento y la eficiencia. Los productos representativos incluyen:
Xen
:Xen
es una solución de paravirtualización de código abierto que puede ejecutar máquinas virtuales sin modificar el sistema operativo. Xen utiliza un enfoque llamado " Xen Plug-in KernelHypervisor
" para lograr la paravirtualización modificando el kernel del sistema operativo para que se comunique con él.
Virtualización de contenedores (Containerization):
la tecnología de virtualización de contenedores logra el aislamiento de aplicaciones y dependencias mediante la creación de instancias de contenedores aisladas a nivel del sistema operativo. Los contenedores comparten el núcleo del sistema operativo y, por tanto, son más ligeros y eficientes que las máquinas virtuales. Los productos representativos incluyen:
- Docker: Docker es una plataforma de contenedorización popular que utiliza imágenes de contenedores (Imágenes) para empaquetar aplicaciones y sus dependencias, y ejecuta instancias de contenedores en el host a través del motor Docker. Docker proporciona herramientas convenientes de compilación, distribución e implementación que hacen que el uso de contenedores sea simple y eficiente.
- LXC (Contenedores Linux): LXC es una solución de contenedorización liviana que utiliza características como espacios de nombres y grupos de control (cgroups) en el kernel de Linux para lograr el aislamiento de procesos. LXC proporciona un entorno de ejecución de contenedor en el que ejecutar instancias de espacio de usuario aisladas .
Virtualización asistida por hardware:
la tecnología de virtualización asistida por hardware utiliza extensiones de virtualización en procesadores físicos, como VT-x de Intel y AMD-V de AMD, para proporcionar soporte de hardware para la virtualización y mejorar el rendimiento y la eficiencia de las máquinas virtuales. Los mencionados KVM y Xen también son soluciones para la virtualización asistida por hardware.
Virtualización ligera: la tecnología de virtualización ligera
es una forma especial de virtualización que utiliza funciones como espacios de nombres y grupos de control (cgroups) a nivel del sistema operativo para controlar procesos, aislamiento y control de recursos. Los productos representativos incluyen:
- Docker: además de ser una plataforma de contenedorización, Docker también proporciona un método de virtualización ligero. Los contenedores Docker pueden ejecutarse como procesos independientes en la máquina host, con sistemas de archivos, redes y espacios de proceso aislados.
1.3 La historia del desarrollo del espacio de nombres de Linux.
La historia del desarrollo de Linux Namespace se remonta a 2002 y fue propuesto e implementado por primera vez por Eric W. Biederman.
La siguiente es la principal historia de desarrollo de Linux Namespace:
- 2002: Eric W. Biederman introdujo la primera implementación del espacio de nombres de Linux en la versión del kernel 2.4, que incluye
Mount Namespace
yUTS Namespace
. - 2006: Introducido por Eric W. Biederman y Serge E. Hallyn en la versión 2.6.24
PID Namespace
, lo que permite que cada espacio de nombres tenga un espacio de identificación de proceso independiente. - 2008: Introducido en la versión 2.6.29 por Eric W. Biederman y Serge E. Hallyn
Network Namespace
, que permite el aislamiento de red independiente. - 2013: La empresa Docker lanzó la plataforma de contenedores Docker, que implementó una tecnología de virtualización de contenedores liviana basada en Linux Namespace y Cgroups, lo que provocó un auge en la tecnología de contenedores.
IPC Namespace
2016: Se introdujeron la versión 4.6 del kernel de LinuxUser Namespace
para implementar la comunicación entre procesos y el aislamiento de usuarios, respectivamente.- 2017: Introducido en la versión 4.11 del kernel de Linux
CGROUP Namespace
, lo que permite que cada espacio de nombres tenga límites de recursos independientes.
Con el tiempo, el espacio de nombres de Linux se ha convertido gradualmente en una característica importante del kernel de Linux y proporciona una base para el desarrollo de la tecnología de contenedorización. Proporciona un mecanismo de aislamiento flexible y liviano que permite la creación de múltiples entornos virtuales independientes en un solo host, logrando el aislamiento y la administración de recursos.
1.4 El papel del espacio de nombres de Linux
Las funciones del espacio de nombres de Linux incluyen:
- Aislamiento de procesos: el espacio de nombres de Linux puede aislar diferentes procesos: cada proceso se ejecuta en su propio espacio de nombres, no se ve afectado por otros procesos y tiene una vista de proceso independiente.
- Aislamiento del sistema de archivos: a través de Mount Namespace, cada proceso puede tener su propio punto de montaje del sistema de archivos para lograr el aislamiento del sistema de archivos.
- Aislamiento de red: a través del espacio de nombres de red, cada proceso puede tener dispositivos de red, direcciones IP, tablas de enrutamiento y reglas de firewall independientes para lograr el aislamiento de la red.
- Aislamiento de la comunicación entre procesos: a través del espacio de nombres IPC, se logra el aislamiento de la comunicación entre procesos (IPC), de modo que diferentes procesos no pueden comunicarse directamente en diferentes espacios de nombres.
- Aislamiento de usuarios y grupos de usuarios: a través del espacio de nombres de usuario, cada proceso puede tener vistas independientes de usuarios y grupos de usuarios, logrando así el aislamiento de usuarios y grupos de usuarios.
- Restricción de recursos del proceso: a través del espacio de nombres PID y el espacio de nombres CGROUP, puede limitar el uso de recursos del proceso, como CPU, memoria, E/S de disco, etc., para lograr la gestión y el aislamiento de recursos.
Al utilizar Linux Namespace, se pueden crear múltiples entornos virtuales independientes en un host físico, y cada entorno tiene sus propios procesos, sistemas de archivos, redes y restricciones de recursos, para lograr el aislamiento y la gestión de recursos entre procesos y mejorar la seguridad del sexo y rendimiento del sistema.
Dos, la función principal del espacio de nombres.
La lista de funciones principales es la siguiente:
nombre | efecto |
---|---|
clone() |
Se utiliza para crear un nuevo proceso y especificar un nuevo espacio de nombres. Puede utilizar clone() los indicadores CLONE_NEWPID , CLONE_NEWNS , CLONE_NEWNET , y otros de la función para crear un CLONE_NEWIPC nuevo o .CLONE_NEWUSER PID、Mount、Network、IPC User Namespace |
unshare() |
Se utiliza para crear nuevos espacios de nombres sobre la marcha. Puede utilizar unshare() los indicadores CLONE_NEWPID , CLONE_NEWNS , CLONE_NEWNET , y otros de la función para crear un CLONE_NEWIPC nuevo o . A diferencia de las funciones, las funciones no crean un nuevo proceso, sino que cambian el proceso actual a un nuevo espacio de nombres.CLONE_NEWUSER PID、Mount、Network、IPC User Namespace clone() unshare() |
setns() |
Se utiliza para agregar un proceso a un espacio de nombres existente para lograr compartir el espacio de nombres. Puede agregar un proceso al espacio de nombres correspondiente especificando el descriptor de archivo y el tipo de espacio de nombres del espacio de nombres. |
mount() |
Se utiliza para montar el sistema de archivos en el formato Mount Namespace . Puede especificar parámetros como el punto de montaje, el tipo de sistema de archivos y las opciones de montaje para realizar la operación de montaje. |
umount() |
Se utiliza para desmontar el Mount Namespace中 sistema de archivos especificado. Puede especificar el punto de montaje que se desmontará para completar la operación de desinstalación. |
unshare(CLONE_NEWCGROUP) |
Se utiliza para cambiar el proceso a uno nuevo CGROUP Namespace y realizar la limitación de recursos y el control del proceso. |
netns() |
Para crear o gestionar Network Namespace . Puede crear, eliminar, ver o cambiar a uno diferente especificando los parámetros de línea de comando correspondientes Network Namespace . |
ip netns命令 |
Herramientas de línea de comando para crear, eliminar, ver o cambiar Network Namespace . |
ipc_namespace() |
Para crear o gestionar IPC Namespace . |
user_namespace() |
Para crear o gestionar User Namespace . |
2.1 、clone()
clone()
Una función es una de las llamadas al sistema utilizadas para crear un nuevo proceso en Linux y tiene la capacidad de crear un nuevo espacio de nombres . clone()
Es C
una función contenedora definida en la biblioteca de lenguajes que se encarga de crear la pila de un nuevo proceso y realizar llamadas al sistema (wrapper)
que están ocultas para el programador . En realidad, es una implementación más general de las llamadas al sistema Linux , que se puede utilizar para controlar cuántas funciones se utilizan. Hay más de 20 tipos de parámetros al principio que se utilizan para controlar todos los aspectos del proceso de clonación (como si se comparte memoria virtual con el proceso principal, etc.). La siguiente es una introducción detallada a la función:clone()
clone()
fork()
flags
CLONE_
falg(标志位)
clone()
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...);
clone()
El primer parámetro fn de la función es un puntero de función, que apunta a la función que ejecutará el nuevo proceso. Esta función tiene el siguiente prototipo: int fn(void *arg)
. El nuevo proceso se ejecutará desde el punto de entrada de la función especificada. Cuando esta función regresa, el proceso hijo finaliza. Esta función devuelve un número entero que representa el código de salida del proceso hijo.
child_stack
El parámetro es la pila del nuevo proceso, que puede ser un espacio de memoria asignado o un archivo NULL
. En caso child_stack
afirmativo NULL
, el nuevo proceso utiliza la misma pila que el proceso principal.
flags
El argumento es una máscara de bits que establece el comportamiento y las propiedades del nuevo proceso. Los signos comúnmente utilizados incluyen:
CLONE_NEWPID
: Crear nuevoPID Namespace
para que el nuevo proceso se ejecute en una vista de proceso separada, independiente del proceso principal y de otros procesos.CLONE_NEWNS
: Crea uno nuevoMount Namespace
para que el nuevo proceso se ejecute en una vista del sistema de archivos separada, independiente del proceso principal y de otros procesos.CLONE_NEWNET
: Crear nuevoNetwork Namespace
para que el nuevo proceso se ejecute en una vista de red separada, independiente del proceso principal y de otros procesos.CLONE_NEWIPC
: Crear nuevoIPC Namespace
para que el nuevo proceso se ejecute en una vista de recursos IPC separada, independiente del proceso principal y de otros procesos.CLONE_NEWUSER
: Crear nuevoUser Namespace
, para que el nuevo proceso se ejecute en una vista separada de usuario y grupo de usuarios, independiente del proceso principal y de otros procesos.
arg
Los argumentos son los argumentos pasados al nuevo proceso.
clone()
El valor de retorno de la función es el del nuevo proceso ID(PID)
y se devuelve si ocurre un error -1
.
Al especificar diferentes bits de bandera, se pueden crear diferentes tipos de espacios de nombres en la función clone() para lograr el aislamiento de procesos y la gestión de recursos. Esto proporciona la base para la implementación de la tecnología de contenerización.
2.2 setns()
Función
setns()
La función es una de las llamadas al sistema en Linux que se utiliza para agregar un proceso a un espacio de nombres existente.
#define _GNU_SOURCE
#include <sched.h>
int setns(int fd, int nstype);
setns()
La función se utiliza para agregar un proceso a un espacio de nombres existente. Acepta dos parámetros:
fd
: un descriptor de archivo abierto que apunta a un espacio de nombres existente. Este descriptor de archivo se puede/proc/[pid]/ns/[namespace_type]
obtener abriendo el archivo.namespace_type
Un tipo que representa un espacio de nombres, comopid、mnt、net、ipc、uts
etc.nstype
: Especifica el tipo de espacio de nombres al que unirse. Este valor debenamespace_type
corresponder a, comoCLONE_NEWPID
corresponde apid
,CLONE_NEWNS
corresponde amnt
,CLONE_NEWNET
corresponde a ,net
etc.
setns()
El valor de retorno de la función es un número entero, lo que indica el éxito o el fracaso de la operación. Si tiene éxito, regrese 0
; de lo contrario -1
, regrese y establezca el código de error correspondiente.
Utilice setns()
funciones para agregar el proceso actual a un espacio de nombres existente, compartiendo así recursos y contexto en el espacio de nombres. Esto es útil en ciertos escenarios, especialmente en tecnologías de contenedorización, donde varios contenedores pueden compartir el mismo espacio de nombres. En Docker, usar docker exec
el comando para ejecutar un nuevo comando en un contenedor que ya se está ejecutando requiere el uso de setns()
la función.
2.3 unshare()
Función
unshare()
Se pueden utilizar funciones para separar un proceso de un espacio de nombres específico. Al llamar unshare()
a la función y especificar la opción de espacio de nombres adecuada, puede separar el proceso actual del espacio de nombres especificado y convertirlo en el primer miembro del nuevo espacio de nombres.
#define _GNU_SOURCE
#include <sched.h>
int unshare(int flags);
flags
: Especifica el tipo de espacio de nombres que se creará y las opciones relacionadas. Se pueden combinar varias opciones utilizando el operador OR bit a bit. Las opciones comunes son:
CLONE_NEWPID
: crea un nuevo espacio de nombres PID.CLONE_NEWNET
: crea un nuevo espacio de nombres de red.CLONE_NEWNS
: crea un nuevo espacio de nombres de montaje.CLONE_NEWIPC
: cree un nuevo espacio de nombres IPC.CLONE_NEWUTS
: cree un nuevo espacio de nombres UTS (para nombre de host y nombre de dominio).
unshare()
El valor de retorno de la función es un número entero, lo que indica el éxito o el fracaso de la operación. Si tiene éxito, devuelve 0; de lo contrario, devuelve -1 y establece el código de error correspondiente.
Utilice unshare()
la función para crear un nuevo espacio de nombres en el proceso actual y utilícelo como el primer miembro. Esto permite que los procesos tengan recursos y contexto independientes en el nuevo espacio de nombres. Esto es muy útil en tecnologías de aislamiento y contenedorización para lograr el aislamiento de procesos y recursos.
Cabe señalar que unshare()
la función solo puede crear un nuevo espacio de nombres y no puede agregar un proceso a un espacio de nombres existente. Para agregar un proceso a un espacio de nombres existente, use setns()
la función.
unshare
El comando
dejar de compartir se utiliza para crear un nuevo espacio de nombres y hacer que el proceso actual sea el primer miembro del nuevo espacio de nombres.
unshare [options] [command [arguments...]]
unshare
Los comandos pueden tomar algunas opciones y parámetros:
parámetro | explicar |
---|---|
-m o--mount |
Cree un nuevo espacio de nombres de montaje. |
-u o--uts |
Cree un nuevo espacio de nombres UTS. |
-i o--ipc |
Cree un nuevo espacio de nombres IPC. |
-n o--net |
Cree un nuevo espacio de nombres de red. |
-p o--pid |
Cree un nuevo espacio de nombres PID. |
-U o--user |
Cree un nuevo espacio de nombres de usuario. |
-C o--cgroup |
Cree un nuevo espacio de nombres de grupo de control. |
-f o--fork |
Inmediatamente después de crear el nuevo espacio de nombres, ejecute un subcomando (comando). |
-r o--map-root-user |
Asigna el usuario raíz en el espacio de nombres de usuario al usuario actual. |
-s o--setgroups |
Establezca grupos adicionales en el espacio de nombres de usuario. |
-h o--help |
Mostrar información de ayuda. |
unshare
El comando se utiliza para crear un nuevo espacio de nombres y hacer que el proceso actual sea el primer miembro del nuevo espacio de nombres. Se pueden utilizar opciones para especificar el tipo de espacio de nombres a crear. Después de crear un nuevo espacio de nombres, también puede especificar un subcomando para realizar operaciones específicas en el nuevo espacio de nombres.
Por ejemplo, ejecutar el siguiente comando creará un nuevo espacio de nombres de red y ejecutará comandos bash en ese espacio de nombres:
$ unshare -n bash
# 查找新建命名空间
$ ps -ef | grep bash
root 1 0 0 15:47 pts/0 00:00:00 /bin/bash
root 38 0 0 15:47 pts/1 00:00:00 /bin/bash
root 84 38 0 15:48 pts/1 00:00:00 bash
root 139 84 0 15:49 pts/1 00:00:00 grep --color=auto bash
$ ls -l /proc/84/ns
total 0
lrwxrwxrwx 1 root root 0 Sep 4 15:49 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Sep 4 15:49 ipc -> ipc:[4026533180]
lrwxrwxrwx 1 root root 0 Sep 4 15:49 mnt -> mnt:[4026533178]
lrwxrwxrwx 1 root root 0 Sep 4 15:49 net -> net:[4026534452]
lrwxrwxrwx 1 root root 0 Sep 4 15:49 pid -> pid:[4026533181]
lrwxrwxrwx 1 root root 0 Sep 4 15:49 pid_for_children -> pid:[4026533181]
lrwxrwxrwx 1 root root 0 Sep 4 15:49 time -> time:[4026531834]
lrwxrwxrwx 1 root root 0 Sep 4 15:49 time_for_children -> time:[4026531834]
lrwxrwxrwx 1 root root 0 Sep 4 15:49 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Sep 4 15:49 uts -> uts:[4026533179]
Después de ejecutar este comando, el sistema creará un nuevo espacio de nombres de red y colocará el proceso actual (incluidos los procesos secundarios) en el espacio de nombres. Luego se iniciará y ejecutará un nuevo shell bash en el nuevo espacio de nombres de la red.
Al utilizar unshare
comandos, puede crear fácilmente nuevos espacios de nombres y realizar operaciones específicas en el nuevo espacio de nombres. Esto es útil para tareas como el aislamiento de procesos, el aislamiento de recursos y la contenedorización.
Tercero, clasificación del espacio de nombres.
Tipo de espacio de nombres | Parámetros de llamada al sistema | Página | Aisla | Versión del núcleo |
---|---|---|---|---|
Montar | CLONE_NEWNS | espacios_nombres_montaje | Los puntos de montaje aíslan los puntos de montaje del sistema de archivos | 2.4.19 |
UTS | CLONE_NEWUTS | espacios_nombres_uts | El nombre de host y el nombre de dominio NIS aíslan la información del nombre de host y del nombre de dominio | 2.6.19 |
IPC | CLONE_NEWIPC | ipc_espacios de nombres | System V IPC, colas de mensajes POSIX aíslan la comunicación entre procesos | 2.6.19 |
PID | CLONE_NEWPID | pid_namespaces | ID de proceso ID de procesos aislados | 2.6.24 |
Red | CLONE_NEWNET | espacios de nombres de red | Dispositivos de red, pilas, puertos, etc. Aislar recursos de red | 2.6.29 |
Usuario | CLONE_NEWUSER | espacios de nombres de usuario | Los ID de usuarios y grupos aíslan los ID de usuarios y grupos de usuarios | 3.8 |
grupo C | CLONE_NEWCGROUP | espacios de nombres_cgroup | Directorio raíz del grupo C | 4.6 |
Tiempo | CLONE_NEWTIME | espacios de nombres_tiempo | Relojes de arranque y monótonos. | 5.6 |
3.1 、 Montar espacio de nombres
Mount Namespace
Se utiliza para aislar el punto de montaje del sistema de archivos. Diferentes Mount Namesace
procesos tienen diferentes puntos de montaje y también tienen diferentes vistas del sistema de archivos. Mount Namespace
Fue el primero en ser apoyado en la historia Namespace
. mount Namespace
Proporciona una vista de jerarquía de archivos para el proceso que Mount Namespace
llama mount()
y umount()
solo afecta al sistema de archivos en el espacio de nombres actual, pero no tiene ningún efecto en el sistema de archivos global. De hecho, Mount Namespace
se chroot
inventó basándose en la mejora continua y chroot
puede considerarse como el primer espacio de nombres en Linux. Luego, el sistema de archivos que se monta en el directorio raíz del contenedor y se utiliza para proporcionar un entorno de ejecución aislado para la imagen del contenedor es la llamada imagen del contenedor, también conocida como rootfs(根文件系统)
.
3.1.1 chroot
Introducción
chroot(Change Root)
Cree un nuevo entorno de sistema de archivos modificando el directorio raíz del proceso actual. La siguiente es una introducción al principio de chroot:
chroot系统调用:chroot命令是通过chroot系统调用来实现的。chroot系统调用的原型如下:
int chroot(const char *path);
该系统调用将进程的根目录更改为指定的目录。注意,只有具有足够特权的用户可以使用chroot命令,通常需要使用root用户或者具有sudo权限的用户。
修改根目录:chroot命令在执行时,会将指定的目录通过chroot系统调用传递给内核。内核会将当前进程的根目录更改为指定的目录,进程以这个目录作为新的根目录。
文件和目录访问:一旦chroot命令执行成功,进程以新的根目录作为基准进行文件和目录的访问。进程只能访问新的根目录及其子目录下的文件和目录,对于根目录以外的文件和目录则无法访问。
隔离环境:使用chroot命令创建的新的文件系统环境是隔离的,进程在这个环境中运行时无法访问或修改主机系统的文件和目录。这样可以提供一定程度的安全性和隔离性,特别是在系统修复、软件开发和测试等场景中。
需要注意的是,chroot只是修改了进程的根目录,并不能完全隔离进程。进程仍然可以通过其他方式访问和修改主机系统的资源。
3.1.2、rootfs
介绍
rootfs(根文件系统)
是Linux文件系统的最顶层,包含了操作系统的基本文件和目录结构。在引导过程中,rootfs是最早被挂载的文件系统,它是系统启动的基础。
rootfs通常以一个镜像文件或者一个设备文件的形式存在,它包含了操作系统所需的核心文件和目录,如/bin、/sbin、/etc
等。这些文件和目录是构成系统的基础,包括系统初始化脚本、核心命令等。
在Linux系统中,rootfs是只读的,它由操作系统提供并在系统启动时挂载到根目录("/")
。一旦系统启动,rootfs会被切换为可读写模式,此后可以通过写入其他文件系统来改变系统的状态。这种只读的rootfs设计可以保护系统的核心文件和目录,避免意外的修改和损坏。
在容器化技术中,每个容器都有自己的rootfs,容器的应用程序和依赖都存在于该文件系统中。容器可以通过挂载其他文件系统或目录来扩展其功能,但它们的根文件系统仍然是只读的,保证了容器的隔离性和安全性。
3.1.3、Mount Propagation
挂载传播
挂载传播决定了这个挂载操作对于其他进程的可见性和影响。挂载传播定义了挂载对象(mount object)之间的关系,系统利用这些关系决定任何挂载对象中的挂载事件传播到其它挂载对象。所谓传播事件,就是一个挂载对象状态变化导致的其它挂载对象的挂载与解除挂载动作的事件。
- 如果两个挂载对象具有共享关系(share relationship),那么一个挂载对象的挂载事件会传播到另一个挂载对象,反之亦然。
- 如果两个挂载对象形成从属关系(master slave),那么一个挂载对象的挂载事件会传播到另一个挂载对象,但反之不行。在这种关系中,从属对象是事件的接受者。
一个挂载状态可以为如下的其中一种:
- 共享状态(shared)
- 从属状态(slave)
- 共享/从属状态(shared and slave)
- 私有挂载(private)
- 不可绑定挂载(unbindable)
传播事件的挂载对象称为共享挂载(shared mount);接收传播事件的挂载对象称为从属挂载(slave mount)。既不传播也不接收传播事件的挂载对象称为私有挂载(private mount)。另一种特殊的挂载对象称为不可绑定的挂载(unbindable mount),它们与私有挂载相似,但是不允许执行绑定挂载,即创建 mount namespace 时这块文件对象不可被复制。
共享挂载的应用场景非常明显,就是为了文件数据的共享所必须的一种挂载方式;从属挂载更大的意义在于一些“只读”场景;私有挂载则是纯粹的隔离,作为独立个体存在;不可绑定挂载则有助于防止没必要的文件拷贝。
默认情况下,所有挂载都是私有的。从共享挂载克隆的挂载对象也是共享的挂载,它们互相传播挂载事件。
从属挂载克隆的挂载对象也是从属的挂载,它也从属于原来的从属挂载的主挂载对象。
mount --make-shared /mntS # 将挂载点设置为共享关系属性
mount --make-private /mntP # 将挂载点设置为私有关系属性
mount --make-slave /mntY # 将挂载点设置为从属关系属性
mount --make-unbindable /mntU # 将挂载点设置为不可绑定属性
3.1.4、挂载信息的查看
/proc/[pid]/mounts
文件中每行数据的含义为:
字段 | 含义 |
---|---|
挂载源(Source) | 表示文件系统的挂载点,可以是设备文件路径(如/dev/sda1 )、网络路径(如//server/share )或特殊文件系统(如proc、sysfs )。 |
挂载点(Mount Point) | 表示挂载源被挂载到的目录路径。 |
文件系统类型(Filesystem Type) | 指示挂载的文件系统类型,如ext4、tmpfs、proc、sysfs 等。 |
挂载选项(Mount Options) | 表示挂载时使用的选项,多个选项以逗号分隔。 |
使用的主设备号(Major Device Number) | 表示挂载设备的主设备号。仅适用于块设备文件。 |
使用的次设备号(Minor Device Number) | 表示挂载设备的次设备号。仅适用于块设备文件 |
/proc/[pid]/mounts
文件的内容可以提供有关特定进程的挂载信息,帮助用户了解进程所使用的文件系统和挂载选项等信息。可以通过读取该文件来获取进程的挂载点和文件系统类型等相关信息。
需要注意的是,/proc/[pid]/mounts
文件是只读的,只能用于查看挂载信息,不能修改其中的内容。
常见挂载选项:
选项 | 含义 |
---|---|
rw |
挂载为可读写的文件系统。可以在该文件系统上进行读取和写入操作。 |
ro |
挂载为只读的文件系统。只能在该文件系统上进行读取操作,不能进行写入操作。 |
relatime |
更新访问时间,但仅在访问时间超过修改时间时更新。相较于atime选项,relatime选项减少了对文件系统的访问次数,提高了性能。 |
async |
异步写入。文件系统将写入操作放入缓冲区,然后立即返回,而不等待写入操作完成。 |
sync |
同步写入。文件系统在执行写入操作时会等待写入操作完成,然后再返回。 |
noexec |
不允许在该文件系统上执行可执行文件。即禁止在该文件系统上运行程序。 |
nodev |
不允许在该文件系统上创建设备文件。即禁止在该文件系统上创建字符设备或块设备。 |
nosuid |
禁止设置setuid和setgid位。即禁止在该文件系统上设置可执行文件的setuid和setgid权限。 |
noatime |
不更新访问时间。即不会更新文件或目录的访问时间戳。 |
nodiratime |
不更新目录的访问时间。即只有文件的访问时间会被更新。 |
index |
Btrfs文件系统中用于禁用或启用文件系统的索引功能 |
metacopy |
Btrfs文件系统中用于启用元数据拷贝功能 |
/proc/[pid]/mountinfo
字段 | 含义 |
---|---|
Mount ID | 挂载的ID号,用于唯一标识每个挂载点。 |
Parent ID | 父挂载点的ID号,表示当前挂载点的父级挂载点。 |
Major:Minor | 挂载的设备的主次设备号。 |
Root | 挂载点的根目录。 |
Mount Point | 设备或文件系统被挂载到的目标路径。 |
Mount Options | 挂载时使用的选项,多个选项以逗号分隔。 |
Optional Fields | 可选字段,可能包含一些附加的挂载信息,如安全标签(security label)、备份目录(backup directory)等。 |
Filesystem Type | 文件系统的类型,如ext4、tmpfs、proc等。 |
Mount Source | 设备或文件系统的源路径。 |
Super Options | 超级选项,用于指定与挂载点相关的额外选项。 |
Subtree Options | 子树选项,用于指定与挂载点子树相关的选项。 |
proc/[pid]/mountinfo
文件提供了有关挂载点的详细信息,包括设备、文件系统类型、挂载路径、挂载选项等。通过读取该文件,可以了解系统中的挂载点及其相关信息,对于了解文件系统的结构和配置非常有用。
/proc/[pid]/mountstats
字段 | 含义 |
---|---|
device | 挂载设备的路径或标识符。 |
path | 挂载点的路径。 |
type | 文件系统类型。 |
mountinfo | 与挂载点相关的详细信息的文件路径。 |
mountsource | 挂载点的源路径。 |
superoptions | 超级选项,用于指定与挂载点相关的额外选项。 |
options | 挂载选项,用于指定挂载时使用的选项。 |
age | 挂载与卸载之间的时间差,以秒为单位。 |
opts | 挂载选项的统计信息。 |
mount_time | 挂载点的挂载时间,以纳秒为单位。 |
umount_time | 挂载点的卸载时间,以纳秒为单位。 |
num_mounts | 挂载点的总挂载次数。 |
num_mnt_errs | 挂载点的挂载错误次数。 |
num_mount_errors | 挂载点的严重错误次数。 |
num_mounts_succeed | 挂载点的成功挂载次数。 |
num_umounts | 挂载点的总卸载次数。 |
num_umount_errors | 挂载点的卸载错误次数。 |
/proc/[pid]/mountstats
文件提供了有关挂载点的统计信息,包括挂载次数、挂载选项的使用情况、挂载时间等。通过读取该文件,可以了解挂载点的使用情况和性能统计,对于监控和调优文件系统的挂载点非常有用。
3.5、User Namespaces
用户命名空间(User Namespace)用于隔离用户和用户组的视图。它允许在一个命名空间中重新映射用户和用户组的ID,从而实现用户和用户组的隔离和管理。User namespace 主要隔离了安全相关的标识符(identifiers)和属性(attributes),包括用户ID、用户组ID、root目录、 key(指密钥)以及特殊权限
。说得通俗一点,一个普通用户的进程通过clone() 创建的新进程在新user namespace 中可以拥有不同的用户和用户组。这意味着一个进程在容器外属于一个没有特权的普通用户,但是他创建的容器进程却属于拥有所有权限的超级用户,这个技术为容器提供了极大的自由。用户命名空间的主要目的是提供更安全的环境,使不同用户在同一系统上运行时能够相互隔离,避免权限冲突和攻击。以下是用户命名空间的一些重要概念和特性:
用户ID映射:用户命名空间允许重新映射用户ID(UID)和组ID(GID)到不同的值,称为用户ID映射。这样做可以在命名空间中创建和管理独立的用户和用户组。例如,一个用户在一个用户命名空间中可能有ID为0的特权用户,但在全局命名空间中却没有这个特权。
用户权限隔离:用户命名空间隔离了用户和用户组的权限,使得在不同的命名空间中用户的权限不会影响其他命名空间的用户。这提供了更好的安全性和隔离性,防止不同用户之间的权限冲突,以及减少攻击面。
文件系统隔离:用户命名空间还可以隔离文件系统的视图,使得在不同命名空间中的用户可以有独立的文件系统,并且对文件和目录的访问权限不会相互干扰。
容器化和虚拟化:用户命名空间是实现容器化和虚拟化的关键组成部分。它允许不同的容器或虚拟机在同一主机上运行,每个容器或虚拟机都有自己独立的用户和用户组。
3.5.1、查看user ns方法:
$ lsns -t user
NS TYPE NPROCS PID USER COMMAND
4026531837 user 263 1 root /usr/lib/systemd/systemd --system --deserialize 17
$ ls /proc/1/ns/user
/proc/1/ns/user
$ ll /proc/1/ns/user
lrwxrwxrwx 1 root root 0 Sep 1 10:21 /proc/1/ns/user -> user:[4026531837]
$ readlink /proc/1/ns/user
user:[4026531837]
3.5.2、User Namespaces的创建和销毁
# 使用unshare -U /bin/bash 创建新的shell会话
$ lsns -t user
NS TYPE NPROCS PID USER COMMAND
4026531837 user 3 1 root /bin/bash
[root@ce31e508d31c /]
$ unshare -U sh
whoami: cannot find name for user ID 65534
[I have no name!@ce31e508d31c /]
$ sudo ip netns add test
sudo: /etc/sudo.conf is owned by uid 65534, should be 0
sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set
whoami: cannot find name for user ID 65534
[I have no name!@ce31e508d31c /]
$ lsns -t user
NS TYPE NPROCS PID USER COMMAND
4026534745 user 2 155 65534 sh
whoami: cannot find name for user ID 65534
具有足够权限的用户(如root用户)才能销毁用户命名空间。
# root用户下查看
$ lsns -t user
NS TYPE NPROCS PID USER COMMAND
4026531837 user 261 1 root /usr/lib/systemd/systemd --system --deserialize 17
4026534745 user 1 613 root sh
$ kill -9 613
$ lsns -t user
NS TYPE NPROCS PID USER COMMAND
4026531837 user 263 1 root /usr/lib/systemd/systemd --system --deserialize 17
四、namespace 生命周期
每个命名空间都有自己的生命周期,可以创建、运行、销毁和释放。
下面是Linux命名空间的典型生命周期:
1、创建命名空间:
使用系统调用(如clone()
或unshare()
)创建新的命名空间。通过指定不同的标识符,可以创建各种类型的命名空间,例如PID命名空间、网络命名空间、挂载命名空间等。
2、运行命名空间:
在创建命名空间后,可以将进程加入到该命名空间中。通过调用setns()
系统调用或使用nsenter
命令,可以将进程从父命名空间切换到新的命名空间。在命名空间中,进程可以访问和修改属于该命名空间的资源。
3、销毁命名空间:
当不再需要命名空间时,可以将其销毁。通过调用unshare()
系统调用或使用ip netns delete
等命令,可以销毁命名空间。销毁命名空间将释放该命名空间所占用的资源,并将其中的进程重新归入到原始的父命名空间中。
需要注意的是,命名空间可以被继承和共享。例如,一个进程创建了一个新的PID命名空间,并在其中启动了一个子进程,那么该子进程将成为新命名空间的一部分。此外,命名空间可以通过不同的手段进行通信和共享资源,如Unix域套接字或Mount命名空间的绑定挂载点。
总结起来,Linux命名空间的生命周期涉及创建、运行、销毁和释放操作,通过这些操作可以实现进程资源的隔离和管理。
命名空间可能不会被销毁的情况
1、进程仍在命名空间中运行:
如果有一个或多个进程仍在使用命名空间,并且没有退出或切换到其他命名空间,那么该命名空间将保持存在。只有在最后一个进程退出或切换到其他命名空间时,命名空间才会被销毁。
2、子命名空间的存在:
如果一个命名空间是另一个命名空间的子命名空间,并且子命名空间仍然活跃,那么父命名空间将一直保持存在。只有当父命名空间和所有子命名空间中的进程都退出或切换到其他命名空间时,该命名空间才会被销毁。
3、共享命名空间:
如果一个命名空间被多个进程共享,并且这些进程仍在活跃状态,那么该命名空间将一直保持存在。只有当最后一个共享此命名空间的进程退出或切换到其他命名空间时,该命名空间才会被销毁。
需要注意的是,命名空间的生命周期取决于其中的进程和命名空间之间的关系。只要还有进程活跃或者仍有命名空间之间的继承或共享关系存在,命名空间就会被保留下来。因此,确保在不再需要使用命名空间时进行适当的清理操作非常重要,以避免资源的浪费和潜在的问题。
五、查看进程所属的 namespace
5.1、lsns
lsns
命令不需要任何参数,它会列出当前系统上存在的所有命名空间的信息。每个命名空间都有一行输出,包含以下信息:
NS TYPE
:命名空间的类型,如pid、mnt、net、ipc、uts、cgroup
等。NS ID
: El ID del espacio de nombres, utilizado para identificar diferentes espacios de nombres.NPROCS
: la cantidad de procesos que se ejecutan actualmente en el espacio de nombres.FLAGS
: El bit de bandera del espacio de nombres, que indica los atributos y el estado del espacio de nombres.
lsns
Algunas opciones comunes para el comando incluyen:
-a
o--all
: Mostrar todos los espacios de nombres, incluidos los que no están referenciados.-t TYPE
o--type TYPE
: muestra solo espacios de nombres del tipo especificado.-n NAMESPACE
O bien--namespace NAMESPACE
: muestra solo la información del espacio de nombres del ID o nombre del espacio de nombres especificado.
$ lsns
NS TYPE NPROCS PID USER COMMAND
4026531836 pid 217 1 root /usr/lib/systemd/systemd --system --deserialize 17
4026531837 user 262 1 root /usr/lib/systemd/systemd --system --deserialize 17
4026531838 uts 221 1 root /usr/lib/systemd/systemd --system --deserialize 17
4026531839 ipc 217 1 root /usr/lib/systemd/systemd --system --deserialize 17
4026531840 mnt 206 1 root /usr/lib/systemd/systemd --system --deserialize 17
4026531860 mnt 1 50 root kdevtmpfs
4026531992 net 227 1 root /usr/lib/systemd/systemd --system --deserialize 17
4026532380 mnt 9 68131 root nginx: master process /usr/sbin/nginx
4026532384 mnt 1 79144 root /pause
4026532385 uts 1 79144 root /pause
4026532386 ipc 2 79144 root /pause
4026532387 pid 1 79144 root /pause
4026532389 net 2 79144 root /pause
4026532427 mnt 1 9682 ntp /usr/sbin/ntpd -u ntp:ntp -g
4026532464 mnt 1 79146 root /pause
4026532466 uts 1 79146 root /pause
5.2 、ls -l /proc/[pid]/ns
$ ls -l /proc/99997/ns
total 0
lrwxrwxrwx 1 root root 0 Sep 4 14:31 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Sep 1 10:21 ipc -> ipc:[4026532661]
lrwxrwxrwx 1 root root 0 Sep 1 10:21 mnt -> mnt:[4026532659]
lrwxrwxrwx 1 root root 0 Sep 1 10:21 net -> net:[4026532664]
lrwxrwxrwx 1 root root 0 Sep 1 10:21 pid -> pid:[4026532662]
lrwxrwxrwx 1 root root 0 Sep 4 14:31 pid_for_children -> pid:[4026532662]
lrwxrwxrwx 1 root root 0 Sep 4 14:31 time -> time:[4026531834]
lrwxrwxrwx 1 root root 0 Sep 4 14:31 time_for_children -> time:[4026531834]
lrwxrwxrwx 1 root root 0 Sep 1 10:21 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Sep 1 10:21 uts -> uts:[4026532660]
En cada línea de salida, el primer campo representa los permisos y propiedades del enlace simbólico, y el noveno campo representa el destino del enlace simbólico. El formato del destino es [type]:[namespace_id]
, donde tipo representa el tipo de espacio de nombres y namespace_id es el ID del espacio de nombres.
Al ejecutar el comando ls -l /proc/[pid]/ns, puede ver los enlaces simbólicos de todos los espacios de nombres a los que pertenece un proceso específico. Esto le permite conocer el espacio de nombres en el que se encuentra actualmente el proceso y el tipo de espacio de nombres y su ID.
5.3 、pstree -p
El comando pstree -p se utiliza para mostrar procesos y sus subprocesos en una estructura de árbol y mostrar sus PID (ID de proceso).
$ pstree -p | grep nginx
|-nginx(68131)-+-nginx(68132)
| |-nginx(68133)
| |-nginx(68134)
| |-nginx(68135)
| |-nginx(68136)
| |-nginx(68137)
| |-nginx(68139)
| `-nginx(68140)
5.4 、ip netns list
Documentación de referencia
1. https://blog.csdn.net/y3over/article/details/128863060
2. https://www.cnblogs.com/sally-zhou/p/13398260.html
3、http://www.taodudu.cc/news/show-320037.html?action=onClick
4, http://www.360doc.com/content/21/0803/11/31115656_989326901.shtml
5、http://www.noobyard.com/article/p-nqmbazhv-s.html
6, https://www.cnblogs.com/sparkdev/p/8214455.html
7、https://blog.csdn.net/key_3_feng/article/details/129942638