Linux Namespace
是容器的基石,可以说没有Linux Namespace
就不存在现在的容器技术。容器最大的功能就是对资源进行隔离,容器正是通过Linux Namespace
技术实现了各种资源的隔离。
Linux Namespace
总共有6种类别的Namespace
,分别为
Namespace | system call flag | kernal version |
---|---|---|
UTS Namespace | CLONE_NEWUTS | 2.6.19 |
Mount Namespace | CLONE_NEWNS | 2.4.19 |
IPC Namespace | CLONE_NEWIPC | 2.6.19 |
PID Namespace | CLONE_NEWPID | 2.6.24 |
Network Namespace | CLONE_NEWNET | 2.6.29 |
User Namespace | CLONE_NEWUSER | 3.8 |
1.UTS Namespace
UTS
是UNIX Time Sharing
的缩写。主要用来隔离hostname
,在每个UTS Namespace
下,每个Namespace
都可以拥有自己的Namespace
。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package main
// 2020-06-11
// UTS Namespace主要用来隔离hostname(主机名用于标识主机)和domainname两个系统标识(已淘汰)
// pstree 命令
// https://www.jianshu.com/p/049f13e55840
import (
"os/exec"
"syscall"
"os"
"log"
)
func main() {
//指定被fork出来的新进程内的初始命令
cmd := exec.Command("sh")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS,
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil{
log.Fatal(err)
}
}
执行这段代码会进入一个sh
运行运行环境。echo $$
是输出当前的PID
,readlink
查看对应的进程是否是在同一个Namespace
。hostname -b bird
修改hostname
为bird
,重新打开一个终端,输入hostname
发现宿主机的hostname
并没有被改变。
2.IPC Namespace
用于隔离System V IPC
和POSIX message queues
。
1 | func main() { |
左边为宿主机,右边为新建的sh
环境。新建的message queue
在右边的隔离Namespace
并不能看到。1
2ipcs -q //查看ipc message queue
ipcmk -Q //新建一个message queue
3.PID Namespace
PID Namespace
用于隔离进程ID
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37func main() {
cmd := exec.Command("sh")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID,
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
}
```
执行上述代码`sudo go /opt/go/bin/go run pidNamespace`。
`echo $$`发现当前的PID为1,而通过`pstree`命令发现运行执行上述代码的PID为58329,而隔离命名空间的PID却为1,说明这个58329在新的命令空间PID映射为1。
![](http://img.hysyeah.top/2020/6/11/20200611221910-pid-namespace.png)
#### 4.Mount Namespace
`Mount Namespace`用于隔离各个进程看到的挂载点视图,是`Linux`实现的第一个`Namespace`类型,在不同的`Namespace`中看到的文件系统是不一样的。
```go
func main() {
cmd := exec.Command("sh")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC |syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run();err != nil{
log.Fatal(err)
}
}
执行上述代码,然后执行ls /proc
发现/proc
中的内容还是宿主机上的。
通过命令mount -t proc proc /proc
将/proc mount
到新建的命名空间,此时再执行ls /proc
发现少了很多文件。
在当前Namespace
中,sh
进程是PID为1的进程。这就说明当前的Mount Namespace
中的mount和外部空间是隔离的,mount操作并没有影响到外部。Docker volume正是利用了这个特性。
5.User Namespace
User Namespace
主要是用于隔离用户的用户组ID。一个进程的User ID和
Group ID在
User Namespace内外是不同的。常用的场景是在宿主机以一个非root用户运行创建一个
User Namespace`,然后在命名空间里面却映射成root用户。
1 | func main() { |
可以看到在宿主机和User Namespace
中它们的UID是不同的。
6.Network Namespace
Network Namespace
用于隔离网络设备,IP地址,端口,路由表,防火墙规则等网络栈的Namespace
。每个容器独占一个Network Namespace
,每个容器都能随意使用自己的端口而不会产生冲突。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17func main() {
cmd := exec.Command("sh")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS |
syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER |syscall.CLONE_NEWNET,
}
// 加上下面这行代码会报没有权限的错误
//cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(1000), Gid: uint32(1000)}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
os.Exit(-1)
}
分别在宿主机和新建sh
环境上分别查看网络设备,发现网络设备是不一样的,说明网络已经隔离。
Network Namespace中的进程如何与宿主机进行通信
1 | ➜ ~ ip netns // 查看Network Namespace列表 |
查询名为netns1
的网络命名空间下的网络设备,此时网卡状态是DOWN
进行netns1
执行本志回环地址,发现网络不通,因为此时设备的状态是DOWN
,通过命令ip netns exec netns1 ip link set dev lo lup
启动设备后可以PING通。但此时只能PING通Network Namespace
中的本地地址,还不能与宿主机进行通信。
我们可以新建一对虚拟的网卡veth pair
与宿主机进行通信。veth pair
总是成对出现且相互连接,报文从一端进去就会从另一端出来。
创建一对虚拟网卡,并查看网络设备;此时veth0
和veth1
都在宿主机的网络命名空间内。
将veth1
加入到网络命名空间netns1
中ip link set veth1 netns netns1
,此时再查看网络设备。发现veth1
已到了netns
下。
设置网卡状态并绑定IP。
从宿主机PING netns1
下的veth1
.
从netns1
下PING 宿主机中的veth0
netns1
中的路由表与防火墙规则也是隔离的
Ref:
1.https://book.douban.com/subject/27082348/
2.https://book.douban.com/subject/34855927/