Aislamiento de procesos de Linux Aprendizaje de espacios de nombres

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:
Insertar descripción de la imagen aquí

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): chrootEs 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): LXCEs 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-nspawnes Systemduna 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 hardware QEMU(Quick Emulator)a través de extensiones de virtualización de hardware (como Intel VT-xy 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: Xenes 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 Namespacey UTS 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 Namespace2016: Se introdujeron la versión 4.6 del kernel de Linux User Namespacepara 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.
Insertar descripción de la imagen aquí

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_NEWIPCnuevo o .CLONE_NEWUSERPID、Mount、Network、IPCUser 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_NEWIPCnuevo 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_NEWUSERPID、Mount、Network、IPCUser Namespaceclone()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 Namespacey 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 Cuna 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()flagsCLONE_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_stackEl parámetro es la pila del nuevo proceso, que puede ser un espacio de memoria asignado o un archivo NULL. En caso child_stackafirmativo NULL, el nuevo proceso utiliza la misma pila que el proceso principal.

flagsEl 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 nuevo PID Namespacepara que el nuevo proceso se ejecute en una vista de proceso separada, independiente del proceso principal y de otros procesos.
  • CLONE_NEWNS: Crea uno nuevo Mount Namespacepara 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 nuevo Network Namespacepara que el nuevo proceso se ejecute en una vista de red separada, independiente del proceso principal y de otros procesos.
  • CLONE_NEWIPC: Crear nuevo IPC Namespacepara que el nuevo proceso se ejecute en una vista de recursos IPC separada, independiente del proceso principal y de otros procesos.
  • CLONE_NEWUSER: Crear nuevo User 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.

argLos 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_typeUn tipo que representa un espacio de nombres, como pid、mnt、net、ipc、utsetc.
  • nstype: Especifica el tipo de espacio de nombres al que unirse. Este valor debe namespace_typecorresponder a, como CLONE_NEWPIDcorresponde a pid, CLONE_NEWNScorresponde a mnt, CLONE_NEWNETcorresponde a , netetc.

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 execel 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.

unshareEl 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...]]

unshareLos comandos pueden tomar algunas opciones y parámetros:

parámetro explicar
-mo--mount Cree un nuevo espacio de nombres de montaje.
-uo--uts Cree un nuevo espacio de nombres UTS.
-io--ipc Cree un nuevo espacio de nombres IPC.
-no--net Cree un nuevo espacio de nombres de red.
-po--pid Cree un nuevo espacio de nombres PID.
-Uo--user Cree un nuevo espacio de nombres de usuario.
-Co--cgroup Cree un nuevo espacio de nombres de grupo de control.
-fo--fork Inmediatamente después de crear el nuevo espacio de nombres, ejecute un subcomando (comando).
-ro--map-root-user Asigna el usuario raíz en el espacio de nombres de usuario al usuario actual.
-so--setgroups Establezca grupos adicionales en el espacio de nombres de usuario.
-ho--help Mostrar información de ayuda.

unshareEl 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 unsharecomandos, 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 NamespaceSe utiliza para aislar el punto de montaje del sistema de archivos. Diferentes Mount Namesaceprocesos tienen diferentes puntos de montaje y también tienen diferentes vistas del sistema de archivos. Mount NamespaceFue el primero en ser apoyado en la historia Namespace. mount NamespaceProporciona una vista de jerarquía de archivos para el proceso que Mount Namespacellama 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 Namespacese chrootinventó basándose en la mejora continua y chrootpuede 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 chrootIntroducció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 时这块文件对象不可被复制。
Insertar descripción de la imagen aquí

共享挂载的应用场景非常明显,就是为了文件数据的共享所必须的一种挂载方式;从属挂载更大的意义在于一些“只读”场景;私有挂载则是纯粹的隔离,作为独立个体存在;不可绑定挂载则有助于防止没必要的文件拷贝。

默认情况下,所有挂载都是私有的。从共享挂载克隆的挂载对象也是共享的挂载,它们互相传播挂载事件。
从属挂载克隆的挂载对象也是从属的挂载,它也从属于原来的从属挂载的主挂载对象。

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.

lsnsAlgunas opciones comunes para el comando incluyen:

  • -ao --all: Mostrar todos los espacios de nombres, incluidos los que no están referenciados.
  • -t TYPEo --type TYPE: muestra solo espacios de nombres del tipo especificado.
  • -n NAMESPACEO 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

Supongo que te gusta

Origin blog.csdn.net/yuelai_217/article/details/132664238
Recomendado
Clasificación