1. 一个新的namesapce

Introduction

实际上那些我们常见的东西, 比如挂载点, POSIX消息队列, pid空间等等都是在一个指定的命名空间下的, 换句话说如果我们有两个命名空间, 那么你的电脑上能出现两个相同pid的进程, 神奇.

$ docker run -it ubuntu:latest bash
$ ps -aux

你会发现你的 pid=1 的进程就是bash, 我电脑上的一号进程是bash吗? 这是因为docker帮你创建了一个新的 pid namesapce, 在两个不同的namespace下自然是可以做到pid重叠的, 就好像在c++不同的namespace下能出现两个同名变量一样

除了能帮你隔离pid, Linux上还有一大堆别的命名空间:

  • ipc namespace : 隔离进程间通信

  • mount namespace: 隔离挂载点

  • network namespace[今天的重点] : 隔离网络资源

搞个命名空间玩玩

ok 开始我们的Linux网络之旅, 我们按照顺序执行以下的内容:

ip netns add xiaohan

创建一个nns, 创建完成以后执行ip netns list, 来看看自己现在除了默认nns以外还有那些命名空间, 会发现多了一个名为xiaohan的nns. 然后好玩的就开始了, 我们现在有了一个nns了, 走进去玩嘿嘿

ip netns exec xiaohan bash

现在我们就进入了名为xiaohan的命名空间了, 整点啥好呢?

# 强的, 只有一个loop设备, 状态害是DOWN呢, loop设备DOWN了会怎样?
$ ip link list # 检查网络设备
  1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN 

# 太强了, 这世界上有人ping自己都ping不通, 果然是强者的世界
$ ping localhost
connect: Network is unreachable

# 给我起!
$ ip link set dev lo up

# 可以了嘿嘿
$ ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.014 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.032 ms

搞个veth玩一玩

我们就先玩一玩, 关于veth的详细使用下一节说, 反正你现在只要知道veth是成对出现的, 类似于电话一样, 一头讲一头听的, 我们先玩一把

$ ip link add veth0 \      # 创建一个名为veth0的设备
          type veth \      # 类型为veth设备
          peer name veth1  # 对端名称为veth1


$ ip link set veth1 \      # 设置一下veth1这一头
          netns xiaohan    # 放到xiaohan的命名空间里

现在爽了, 我们给[默认]命名空间 & [xiaohan]命名空间, 拉了一条网线, 然后给他俩一人一个IP, 那么两个命名空间内就可以相互聊天了!

$ ifconfig veth0 10.1.1.1/24 up   # veth0 一个IP 
$ ip netns exec xiaohan bash      # 然后进入命名空间
$ ifconfig veth1 10.1.1.2/24 up   # veth1 也一个IP

$ ping 10.1.1.2  # 两个veth开始聊天...
64 bytes from 10.1.1.2: icmp_seq=1 ttl=64 time=0.022 ms
64 bytes from 10.1.1.2: icmp_seq=2 ttl=64 time=0.030 ms

API - 创建一个进程+ns

int clone(
        void* child_func,
        void* child_stack,
        void* child_args,
        int   flags,
)

进入一种严肃的玩法, 以上的函数ok帮你创建一个新的进程, 创建一个(新进程+新空间)的组合, 创建出来的新进程就在这个新进程里面. 当然这些并不是重点, 重点是这些参数太熟悉了...

回忆一下我们在Go语言里面如何创建出一个新g? 我们切换到g0栈上, 分配栈, 将函数执行指针拷贝, 然后将函数参数拷贝到栈内. 换句话说对待任何人, 想要执行一个"任务", 都必须提供函数执行体 + 参数 + 栈 . 我们创建进程是这么做, Go创建协程也这么做 因此你可以这么说: "任务" = "函数+参数+栈"

API - 往ns里丢一个进程

int setns(int fd)

这个函数能负责把当前进程加入指定的命名空间下, 其中的fd就代表了命名空间. 一个常见的玩法是把当前进程换成bash, 那么就相当于切换到nns下开始执行操作, 是不是很像我们之前看到的ip netns exec xiaohan bash, 这个操作使用API来完成就是这样的:

fd = open(xiaohan, O_RDONLY) // 打开xiaohan文件描述符
setns(fd,0)                  // 现在你在xiaohan下了
execvp("/bin/bash")          // 本进程被替换成bash了, 玩吧

Last updated

Was this helpful?