:::info Linux 命名空间(Namespaces)是 Linux 内核中的一种机制,它能够为进程提供一个独立的命名空间,使得这个进程看到的系统资源与其他进程看到的资源隔离开来。 ::: Linux 系统中目前有 6 种命名空间:
- Mount namespace(挂载命名空间):每个进程都有自己的挂载点,所以每个进程看到的文件系统都是独立的。
- UTS namespace(主机名命名空间):每个进程都有自己的主机名和域名,所以每个进程看到的主机名都是独立的。
- IPC namespace(进程间通信命名空间):每个进程都有自己的 System V IPC 对象和 POSIX 消息队列,所以每个进程间的 IPC 通信都是独立的。
- Network namespace(网络命名空间):每个进程都有自己的网络设备、IP 地址、路由表和 iptables 规则,所以每个进程看到的网络环境都是独立的。
- PID namespace(进程 ID 命名空间):每个进程都有自己的进程 ID 编号,所以每个进程看到的进程树都是独立的。
- User namespace(用户命名空间):每个进程都有自己的用户 ID 和组 ID,所以每个进程看到的用户和组信息都是独立的。
命名空间机制可以让我们在一个系统上运行多个隔离的环境,每个环境中的进程都有自己独立的命名空间。这个机制在容器技术中非常重要,例如 Docker 就是使用命名空间机制来实现容器隔离的。
Linux 网络命名空间
(Network namespace)是 Linux 内核中的一种机制,它能够为进程提供一个独立的网络命名空间,使得这个进程看到的网络设备、IP 地址、路由表和 iptables 规则与其他进程看到的网络信息隔离开来。
在 Linux 系统中,每个进程都有自己的网络命名空间。如果一个进程创建了一个新的网络命名空间,那么在这个新的网络命名空间中,进程看到的网络信息就与原来的命名空间隔离开来。
Linux 网络命名空间提供了如下功能:
- 多个进程可以在同一台机器上使用同一个端口,因为每个进程看到的端口都是独立的。
- 多个进程可以在同一台机器上使用同一个 IP 地址,因为每个进程看到的 IP 地址都是独立的。
- 多个进程可以在同一台机器上运行同一个服务,因为每个进程看到的服务都是独立的。
Linux 网络命名空间是容器技术中非常重要的一部分,例如 Docker 就是使用网络命名空间来实现容器隔离的。
示例1
下面是一个使用 Linux 网络命名空间的示例,这个示例演示了如何在同一台机器上运行两个 webserver,两个 webserver 看到的网络环境是隔离的:
# 创建一个新的网络命名空间
ip netns add webserver1
# 在新的网络命名空间中创建一个虚拟网络接口
ip link add veth0 type veth peer name veth1
# 将 veth0 接口放到 webserver1 命名空间中
ip link set veth0 netns webserver1
# 在 webserver1 命名空间中配置 IP 地址
ip netns exec webserver1 ip addr add 192.168.0.1/24 dev veth0
# 在 webserver1 命名空间中启动 webserver
ip netns exec webserver1 python3 -m http.server 8080
# 创建另一个新的网络命名空间
ip netns add webserver2
# 将 veth1 接口放到 webserver2 命名空间中
ip link set veth1 netns webserver2
# 在 webserver2 命名空间中配置 IP 地址
ip netns exec webserver2 ip addr add 192.168.0.2/24 dev veth1
# 在 webserver2 命名空间中启动 webserver
ip netns exec webserver2 python3 -m http.server 8080
这个示例中,我们在同一台机器上运行了两个 webserver,两个 webserver 看到的网络环境是隔离的。你可以通过访问 http://192.168.0.1:8080 和 http://192.168.0.2:8080 来访问这两个 webserver。
示例2
下面是另一个使用 Linux 网络命名空间的示例,这个示例演示了如何在同一台机器上运行两个隔离的 web 服务器,并且演示了如何使用 iptables 规则来限制进出流量:
# 创建一个新的网络命名空间
ip netns add webserver1
# 在新的网络命名空间中创建一个虚拟网络接口
ip link add veth0 type veth peer name veth1
# 将 veth0 接口放到 webserver1 命名空间中
ip link set veth0 netns webserver1
# 在 webserver1 命名空间中配置 IP 地址
ip netns exec webserver1 ip addr add 192.168.0.1/24 dev veth0
# 在 webserver1 命名空间中启动 web 服务器
ip netns exec webserver1 python3 -m http.server 8080
# 在 webserver1 命名空间中设置 iptables 规则,只允许来自 192.168.0.2 的流量进入
ip netns exec webserver1 iptables -A INPUT -s 192.168.0.2 -j ACCEPT
ip netns exec webserver1 iptables -A INPUT -j DROP
# 创建另一个新的网络命名空间
ip netns add webserver2
# 将 veth1 接口放到 webserver2 命名空间中
ip link set veth1 netns webserver2
# 在 webserver2 命名空间中配置 IP 地址
ip netns exec webserver2 ip addr add 192.168.0.2/24 dev veth1
# 在 webserver2 命名空间中启动 web 服务器
ip netns exec webserver2 python3 -m http.server 8080
# 在 webserver2 命名空间中设置 iptables 规则,只允许流量出发到 192.168.0.1
ip netns exec webserver2 iptables -A OUTPUT -d 192.168.0.1 -j ACCEPT
ip netns exec webserver2 iptables -A OUTPUT -j DROP
这个示例中,我们在同一台机器上运行了两个 web 服务器,两个 web 服务器看到的网络环境是隔离的。我们还使用 iptables 规则来限制了进出流量。
你可以通过访问 http://192.168.0.1:8080 和 http://192.168.0.2:8080 来访问这两个 web 服务器。此时,你会发现只能从 webserver2 访问 webserver1,而不能从 webserver1 访问 webserver2。
Linux 挂载命名空间
示例1
下面是一个使用 Linux 挂载命名空间的示例,这个示例演示了如何在同一台机器上运行两个隔离的进程,两个进程看到的文件系统是隔离的:
# 创建一个新的挂载命名空间
unshare -m
# 在新的挂载命名空间中挂载一个文件系统
mount -t tmpfs tmpfs /mnt
# 在新的挂载命名空间中运行进程
chroot /mnt bash
# 在原来的挂载命名空间中再次运行进程
bash
这个示例中,我们在同一台机器上运行了两个进程,两个进程看到的文件系统是隔离的。你可以在新的挂载命名空间中挂载一个新的文件系统,并在新的文件系统中运行进程。
示例2
下面是另一个使用 Linux 挂载命名空间的示例,这个示例演示了如何在同一台机器上运行两个隔离的进程,两个进程看到的文件系统是隔离的,并且演示了如何使用 pivot_root 命令来更改根文件系统:
# 创建一个新的挂载命名空间
unshare -m
# 在新的挂载命名空间中挂载一个文件系统
mount -t tmpfs tmpfs /mnt
# 在 /mnt 中创建一个新的目录作为根文件系统
mkdir /mnt/rootfs
# 将根文件系统挂载到 /mnt/rootfs 中
mount -o bind / /mnt/rootfs
# 使用 pivot_root 命令将根文件系统更改为 /mnt/rootfs
pivot_root /mnt/rootfs /mnt/rootfs/mnt
# 删除原来的根文件系统
umount /mnt
# 在新的根文件系统中运行进程
chroot / bash
# 在原来的挂载命名空间中再次运行进程
bash
这个示例中,我们在同一台机器上运行了两个进程,两个进程看到的文件系统是隔离的。我们还使用了 pivot_root 命令来更改根文件系统。