linux namespace

namespace是linux自带的功能用来隔离内核资源的机制,如进程pid,主机名与域名,网络设备端口等。各个docker容器运行在同一个docker主进程并且共 用同一个宿主机系统内核,各docker容器运行在宿主机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间。容器之间是感受不到彼此的存在的,在网络中可以被看做是一个独立的个体存在,而namespace起到的作用就是让资源之间互相隔离,成为一个独立的存在。

实际上,Linux 内核实现 namespace 的一个主要目的就是实现轻量级虚拟化(容器)服务。在同一个 namespace 下的进程能够感知彼此的变化,而对外界的进程一无所知。这样就可让容器中的进程产生错觉,认为本身置身于一个独立的系统中,从而达到隔离的目的。

目前,Linux已经支持8种全局资源的虚拟化。

cgroup namespace:该namespace可单独管理自己的cgroup

ipc namespace:该namespace有自己的IPC,比如共享内存、信号量等

network namespace:该namespace有自己的网络资源,包括网络协议栈、网络设备、路由表、防火墙、端口等

mount namespace:该namespace有自己的挂载信息,即拥有独立的目录层次

pid namespace:该namespace有自己的进程号,使得namespace中的进程PID单独编号,比如可以PID=1

time namespace:该namespace有自己的启动时间点信息和单调时间,比如可设置某个namespace的开机时间点为1年前启动,再比如不同的namespace创建后可能流逝的时间不一样

user namespace:该namespace有自己的用户权限管理机制(比如独立的UID/GID),使得namespace更安全

uts namespace:该namepsace有自己的主机信息,包括主机名(hostname)、NIS domain name

每个进程都有这样8中namesapce,如果两个进程的对应的namespace值是一样的,那么他们就处于同一个namespace,彼此之间是可见的。反之,他们在不同的容器中,彼此是不可见的。

mount namespace

提供磁盘挂载点和文件系统的隔离:

a.每个容器都要有独立的根文件系统有独立的用户空间,以实现在容器里面启动服务并且使 用容器的运行环境。一个宿主机是ubuntu的服务器,可以 在里面启动一个centos运行环 境的容器并且在容器里面启动 一个Nginx服务,此Nginx运行 时使用的运行环境就是centos 系统目录的运行环境,即在容 器里面是不能直接访问宿主机 的文件系统。

b. 宿主机是使用了chroot技术把容器锁定到一个指定的运行目录里面并作为容器的根运行环境。

ipc namespace

提供进程间通信的隔离,IPC namespce隔离进程间通信资源(同一个IPC namespace的进程可实现内 存等资源共享,但是不同的 IPC namespace则严格隔离).
uts namespace
主机名隔离,UTS namespace(UNIX Timesharing System包含了运行 内核的名称、版本、底层体系结构类型等信息)用于系统标识, 其中包含了hostname 和域名 domainname ,它使得一个容器拥有属于自己hostname标 识,这个主机名标识独立于宿主 机系统和其上的其他容器。
pid namespace
    进程隔离,Linux系统中,有一个PID为1的进程(init/systemd)是其他所有进程的父进程,那么在每个容器内也要有一个父进程来管理其下属的子进程,那么多个容器的进程通PID namespace进程隔离(比如PID编号重复、器内的主进程生成与回收子进程等)。
network namespace
  网络隔离,每一个容器都类似于虚拟机一样有自己的网卡、监听端口、TCP/IP协议栈等,docker使用network namespace启动一个vethX接口,这样你的容器将拥有它自己的桥接ip地址,通常是docker0,而docker0 实质就是Linux的虚拟网桥,网 桥是在OSI七层模型的数据链 路层的网络设备,通过mac地址对网络进行划分,并且在不同网络直接传递数据。

 user namesapce
    用户隔离,各个容器内可能会出现重名的用户和用户组名称,或重复的用户UID或者GID,User Namespace允许在各个宿 主机的各个容器空间内创建相同的 用户名以及相同的用户UID和GID,只是会把用户的作用范围限 制在每个容器内,即A容器和B容 器可以有相同的用户名称和ID的账 户,但是此用户的有效范围仅是当 前容器内,不能访问另外一个容器 内的文件系统,即相互隔离、互不 影响。
 

Linux 提供了多个 API 用来操做 namespace,它们是 clone()、setns() 和 unshare() 函数,为了肯定隔离的究竟是哪项 namespace,在使用这些 API 时,一般须要指定一些调用参数:CLONE_NEWIPC、CLONE_NEWNET、CLONE_NEWNS、CLONE_NEWPID、CLONE_NEWUSER、CLONE_NEWUTS 和 CLONE_NEWCGROUP。

clone(): 使用clone()在创建新进程的同时创建namespace。

int clone(int (*child_func)(void *),void *child_stack,int flags,void *arg);

clone()实际上是Linux系统调用fork()的一种更通用的实现方式,它可以通过flags来控制使用多少功能。一共有20多种CLONE_*的flag(标志位)参数来控制clone进程的方方面面(如是否与父进程共享虚拟内存等)

setns():通过setns()加入一个已经存在的namespace。

在进程都已经结束的情况下,也可以通过挂载的形式把namespace保留下来,保留namespace的目的是为以后有进程加入做准备。在docker中,使用docker exec命令在已经运行着的容器中执行一个新的命令,就需要用到改方法。通过setns()系统调用,进程从原先的namespace加入某个已经存在的namespace,通常为了不影响进程的调用者,也为了使新加入的pid namespace生效,会在setns()函数执行后使用clone()创建子进程继续执行命令,让原先的进程结束。

unshare():在原先进程上进行namespace隔离。

它与clone()很像,不同的是,unshare()运行在原先的进程上,不需要启动一个新进程。

调用unshare()的主要作用是,不启动新进程就可以起到隔离的效果,相当于跳出原先的namespace进行操作。这样,就可以在原进程进行一些需要隔离的操作。Linux中自带的unshare命令,就是通过unshare()系统调用实现的。

fork():系统调用

当程序调用fork()函数时,系统会创建新的进程,为其分配资源,例如存储数据和代码的空间,然后把原先进程的所有值都复制到新进程中,只有少量数值与原来的进程值不同,相当于复制了本身,后续代码逻辑根据fork()的返回值用来区分是当前线程是新进程还是父进程。

1. 父进程中,fork()返回新创建子进程的进程id。

2.在子进程中,fork()返回0;

3.如果出现错误,fork()返回一个负值。

使用fork()后,父进程有义务监控子进程的运行状态,并在子进程退出后自己才能正常退出,否则子进程就会成为“孤儿”进程。如果子进程真的成为了“孤儿”进程,则init进程会接管子进程,进行资源的销毁以及释放。

namespace 的生命周期

正常的 namespace 的生命周期与最后一个进程的终止和离开相关。

但有一些情况,即使最后一个进程已经退出了,namespace 仍不能被销毁。

/proc/[pid]/ns/* 中的文件被打开或者 mount ,即使最后一个进程退出,也不能被销毁;

namespace 存在分层,子 namespace 仍存在 ,即使最后一个进程退出,也不能被销毁;

参考:

(5条消息) linux namespace的概述_dizhegccl的博客-CSDN博客

linux内核知识之namespace | 码农家园

Linux Namespace : 简介 - JavaShuo

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值