Docker底层技术-Namespace

Namespace是对全局系统资源的一种封装隔离,使得处于不同Namespace的进程拥有独立的全局系统资源,改变一个Namespace中的系统资源只会影响当前Namespace里的进程,对其他Namespace中的进程没有影响。

Namespace 是 Linux 为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法。在日常使用 Linux 时如果我们在服务器上启动了多个服务,这些服务其实会相互影响的,每一个服务都能看其他服务的进程,也可以访问宿主机器上的任意文件,这是很多时候我们都不愿意看到的,我们更希望运行在同一台机器上的不同服务能做到完全隔离,就像运行在多台不同的机器上一样。

当 Docker 创建一个容器时,它会创建新的以上六种 namespace 的实例,然后把容器中的所有进程放到这些 namespace 之中,使得Docker 容器中的进程只能看到隔离的系统资源。

Namespace6种资源隔离

PID namespace

PID 用来隔离进程的ID空间,使得不同pid namespace里的进程id可以重复且相互之间不影响。

我们能看到同一个进程,在容器内外的 PID 是不同的:

  • 在容器内 PID 是 1,PPID 是 0。
  • 在容器外 PID 是 50349, PPID 是 1059即 containerd-shim 进程.
#容器启动一个镜像
`[root@node1 ~]# docker run -it -d registry.cn-beijing.aliyuncs.com/alexzhang/centos-full`
`f90a6a1cab36effc6a2f5058673320cf8f80b8c65ea84deef3ad4981f3d7baee`
#通过镜像id查找进程
`[root@node1 ~]# ps -ef | grep f90a6a1cab36eff`
`root      50349   1059  0 12:57 ?        00:00:00 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/f90a6a1cab36effc6a2f5058673320cf8f80b8c65ea84deef3ad4981f3d7baee -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc -systemd-cgroup`
`root      50438  47301  0 12:58 pts/0    00:00:00 grep --color=auto f90a6a1cab36effc6a2f5058673320cf8f80b8c65ea84deef3ad4981f3d7baee`
#进入容器
`[root@node1 ~]# docker exec -it f90a6a1cab36eff bash`
#查看容器内进程
`[root@f90a6a1cab36 /]# ps -ef` 
`UID         PID   PPID  C STIME TTY          TIME CMD`
`root          1      0  0 04:57 pts/0    00:00:00 /bin/bash`
`root         14      0  0 04:58 pts/1    00:00:00 bash`
`root         27     14  0 04:58 pts/1    00:00:00 ps -ef

Namespace允许在新的Namespace创建一棵新的进程树,它可以有自己的PID为1的进程。在PID namespace的隔离下,子进程名字空间无法知道父进程名字空间的进程,如在Docker容器中无法看到宿主机的进程,而父进程名字空间可以看到子进程名字空间的所有进程。如图所示:

 

Network namespace

network用来隔离网络设备,ip地址,端口。每个namespace将会有自己独立的网格线,路由表,防火墙规则,socket等。

Docker容器中另一个重要特性是网络独立,使用到Linux 的 NET Namespace以及veth。veth主要的目的是为了跨NET namespace之间提供一种类似于Linux进程间通信的技术,所以veth总是成对出现,如下面的veth0和veth1。它们位于不同的NET namespace中,在veth设备任意一端接收到的数据,都会从另一端发送出去。veth实现了不同namespace的网络数据传输。

 

在Docker中,宿主机的veth端会桥接到网桥中,接收到容器中的veth端发过来的数据后会经由网桥docker0再转发到宿主机网卡eth0,最终通过eth0发送数据。当然在发送数据前,需要经过iptables MASQUERADE规则将源地址改成宿主机ip,这样才能接收到响应数据包。而宿主机网卡接收到的数据会通过iptables DNAT根据端口号修改目的地址和端口为容器的ip和端口,然后根据路由规则发送到网桥docker0中,并最终由网桥docker0发送到对应的容器中。

Docker里面网络模式分为bridge,host,overlay等几种模式,默认是采用bridge模式网络如图所示。如果使用host模式,则不隔离直接使用宿主机网络。overlay网络则是更加高级的模式,可以实现跨主机的容器通信。

User namespace

user namespace用于隔离用户和组信息,在不同的namespace中用户可以有相同的 UID 和 GID,它们之间互相不影响。父子namespace之间可以进行用户映射,如父namespace(宿主机)的普通用户映射到子namespace(容器)的root用户,以减少子namespace的root用户操作父namespace的风险。

Mount namespace

将一个文件系统的顶层目录挂到另一个文件系统的子目录上,使它们成为一个整体,称为挂载。把该子目录称为挂载点。   Mount namespace用来隔离文件系统的挂载点, 使得不同的mount namespace拥有自己独立的挂载点信息,不同的namespace之间不会相互影响,这对于构建用户或者容器自己的文件系统目录非常有用。

UTS namespace

UTS,UNIX Time-sharing System namespace提供了主机名和域名的隔离。能够使得子进程有独立的主机名和域名(hostname),这一特性在Docker容器技术中被用到,使得docker容器在网络上被视作一个独立的节点,而不仅仅是宿主机上的一个进程。

#查看主机hostname
[root@node1 ~]# hostname
node1
#进入容器
[root@node1 ~]# docker exec -it f90a6a1cab36effc6a2f5058673320cf8f80b8c65ea84deef3ad4981f3d7baee bash
#查看容器主机hostname
[root@f90a6a1cab36 /]# hostname
f90a6a1cab36
[root@f90a6a1cab36 /]# 

IPC namespace

IPC全称 Inter-Process Communication,是Unix/Linux下进程间通信的一种方式,IPC有共享内存、信号量、消息队列等方法。所以,为了隔离,我们也需要把IPC给隔离开来,这样,只有在同一个Namespace下的进程才能相互通信。如果你熟悉IPC的原理的话,你会知道,IPC需要有一个全局的ID,即然是全局的,那么就意味着我们的Namespace需要对这个ID隔离,不能让别的Namespace的进程看到。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值