同一个POD中默认共享哪些名称空间
如果通过POD的形式来启动多个容器那么它们的名称空间会是共享的么,所以我这里讨论是在默认情况下同一个POD的不同容器的哪些名称空间是打通的。这里先说一下结论,共享的是UTS、IPC、NET、USER。
UTS名称空间
主机名名称空间,保存内核名称、版本以及主机名和域名。默认情况下同一个POD的不同容器是共享UTS的,看下面的配置:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: centos-dep
  labels:
    app: centos
spec:
  replicas: 1
  selector:
    matchLabels:
      app: centos
  template:
    metadata:
      labels:
        app: centos
    spec:
      containers:
      - name: app1
        image: centos
        imagePullPolicy: IfNotPresent
        command: ["/bin/sh", "-c"]
        args:
          - sleep 3600
      - name: app2
        image: centos
        imagePullPolicy: IfNotPresent
        command: ["/bin/sh", "-c"]
        args:
          - sleep 3600
运行这个POD,然后分别登陆到不同容器去查看主机名,你会发现主机名一样,而且就是POD的名字,如下图:

另外你通过uname -a如果查看到的内容是一致的也说明是共享UTS名称空间的。
实验证明,默认情况下同一个POD中的不同容器的UTS名称空间是共享的。
IPC名称空间
进程间通信名称空间,IPC的隔离就是阻断进程间通信,主要是信号量、队列和共享内存。运行主机进程通过上面的机制进行通信。
下面通过一个实验来看看同一个POD的IPC名称空间是否是共享的,在app2中通过命令ipcmk --queue来创建一个队列,然后在app1中通过命令ipcs来查看,如果有这个队列就说明是共享的,如下图:

实验证明,默认情况下同一个POD中的不同容器的IPC名称空间是共享的。
MNT名称空间
Mount名称空间,提供对磁盘挂载点和文件系统的隔离能力。同一主机上的不同进程访问相同的路径会得到相同的内容,因为它们共享本地主机的磁盘和文件系统。
在同一POD内容器之间挂载点名称空间是隔离的,如果该POD的多个容器挂载一个POD级别的Volume,那么它们就可以实现挂载点的共享,但共享的也仅仅是这一个Volume并不是整个文件系统。

实验证明,默认情况下同一个POD中的不同容器的MNT名称空间不是共享的。
NET名称空间
网络名称空间,同一主机上的不同进程可以进行localhost或者本地unix socket通信。在单独启动容器的时候不同容器是隔离的,但是在POD中不同容器通过一个Infra容器来进行共享网络名称空间,其原理是其他用户自己定义的容器都Join这个Infra容器的网络。这里我启动的就是一个Cetnos镜像,无法做本地通信验证。不过它的确是通过Infra容器来共享的。
PID名称空间
进程ID名称空间,同一主机上的不同进程在同一PID空间内可以看到其他进程的ID,并且同一PID空间的进程的ID不会重复。另外PID名称空间有层级关系,子空间看不到父空间的内容,但是父空间可以管理子空间,比如发送信号。
在POD中则对应为同一POD内的不同容器可以看到对方的进程ID。默认不是共享的,可以设置POD的shareProcessNamespace这个值为true来进行共享,默认为false。我在App2中启动一个top命令,然后在App1中通过ps命令查看,看下面的测试:

实验证明,默认情况下同一个POD中的不同容器的PID名称空间不是共享的。
USER名称空间
隔离用户、组以及相关用户能力的。也就是在不同的User Namespace中,相同的用户可以有不同的UID或者不同的权限。另外还可以通过映射的方式把某个User Namespace的用户映射到另外一个User Namespace的用户上,这样这两个名称可能不同的用户就具有相同的权限。如果想要在本机进行验证需要查看一下这个文件:
cat /proc/sys/user/max_user_namespaces如果是0则表示没有开启,需要给它一个值echo "15000" > /proc/sys/user/max_user_namespaces,然后你再运行unshare -U或者unshare --user就不会报错了。
在Docker中默认并没有开启user namespace。

可以看到当前Bash进程和Dockerd进程的名称空间都一样,因为它们都是在同一个名称空间上运行的。另外需要说明的是uip_map的输出,第一个数字是在当前名称里的用户ID,第二个数字是该用户ID在当前名称空间外部被映射到哪个用户ID上,最后一个数字是映射范围。
然后我们启动一个包含两个容器的POD来看一下,如下图:

容器的User namespace和容器外的是一样的,也就是说没有单独为容器创建User namespace,而且容器内的用户ID是0,映射到容器外也是0,这就是意味着容器内的root用户和容器外的root用户拥有相同的权限。说白了就是容器中的进程是以root用户权限运行的,并且这个容器中的root用户和宿主机上的root用户是同一个,看下图,这2个容器进程就是以root运行的:

如果你需要验证,那么你把宿主机上的一个只能由root打开的文件挂载容器中,你看看能不能打开就知道了。
就算你进入容器查看这个sleep 3600其实也是root运行的,简单来说容器内UID为0的root用户就是容器外UID为0的root用户。为什么会是这样呢?在整个系统共享一个内核,而内核只管理一套uid和gid,并且对内核来说只识别uid不识别用户名,也就是说内核在做权限方面它通过uid来做,用户名只是对于用户来讲方便辨认。
不要误认为你在容器中创建一个用户,然后在宿主机也可以看到,因为/etc/password这个文件在不同的文件系统上,容器和宿主机的文件系统还是隔离的。
但有些时候也不要被用户名所迷惑,你应该检查UID,查看容器进程的uid_map中的信息。
让容器进程使用root账号显然不安全,因为它的root就是宿主机的root,所以通常我们会给dockerd进程建立单独的账号或者使用User Namespace。不过推荐使用User Namesapce,因为有些使用容器进程必须以root来运行,如果使用User Namespace的话,我们就可以把宿主机的一个普通用户映射到容器中的root用户,这样容器进程以为自己是root并且在它所在的名称空间内有各种权限,但是在宿主机上它还是普通用户。
如何开启User Namespace呢:
cat /boot/config-3.10.0-957.el7.x86_64 | grep _NS,先检查一下你的内核是否开启了User Namespace

检查一下是否有下面的文件,如果没有就手动建立:

你可以使用系统中有的用户然后添加到这里,最后在docker的启动参数中加入这个账号,也可以让dockerd自己来建立,如果让dockerd自己来完成,在dockerd的启动docker-daemon.json中加入下面的内容,default表示使用dockerd去建立账号,它使用的名字为dockermap,如果你使用自己的就替换dufault:
{
    "userns-remap": "default",
}
在RHEL 7.5版本,上面的配置在dockerd启动的时候会报错"Can't create ID mappings: %!v(MISSING): No subuid ranges found for user "dockremap"",查询之后判断应该是系统BUG,可以看看Redhat官网的Bug说明Bug-1546870,它会在系统中建立dockremap账号然后使用usermod -v参数来设置dockermap用户的ID范围,但是在Centos 7.5版本上的usermod命里没有-v参数。这就意味着RHEL 7.5不支持动态添加subid。所以我们只能手动来做,不过据说其他发行版可以支持比如Ubantu或者Fedora。
向从属用户和组文件中添加范围(如果你使用dockremap账号,那么你无须手动建立,因为dockerd启动的时候就会建立,如果上面的配置是default):
echo "dockremap:10000:65536" > /etc/subuid
echo "dockremap:10000:65536" > /etc/subgid

一共三个字段:
第一个字段dockremap,这个一个宿主机上的用户名
第二个字段10000,表示子User Namespace中用户ID从哪里开始
第三个字段65536,表示子User Namespace中可以有多少个用户ID
整体含义是宿主机的dockremap账号一共有65536个从属用户,用户ID从10000-165535。这个从事用户的ID不是真实的,只是用来分配,它会从这个范围里拿一个ID映射到容器进程里的用户,比如容器进程还是用root用户,其UID实0,那么我们就可以从dockremap这个从属ID中拿一个来映射容器进程中的root。这样容器中看起来是root且具有root权限,但是在宿主机上它就是一个普通账号dockremap的权限。配置好后重启dockerd进程。配置好重新启动POD,如下:

同一个POD中的User Namespace是共享的,但此时它与宿主机的进程就已经不共享User Namespace了。再看一下uid_map

容器中的UID0映射到容器外的从属ID 10000。
不过这样虽然安全但是有些容器进程无论在容器内还是在容器外都需要root账号,比如prometheus的node_explorer,它是以DaemonSet形式运行的需要共享宿主机的网络名称空间,如果以上的用户来运行则会启动失败,如下图:

其实这个和DaemonSet没关系,主要是在docker上启用User Namspace后会有一些限制,userns-remap ,也就是说启用了User Namespace后容器将不能共享宿主机的PID和NET名称空间。所以我想因为有一些限制所以docker默认才不开启User Namespace。不过如果直接通过docker来启动容器可以指定--usens=host来为某个容器禁用User Namespace,不过在Kubernetes中目前没找到配置POD那个参数可以起到这个效果,有人知道请留言。
实验证明:在默认情况下同一个POD是共享User Namespace的。
最简单的办法来验证一下
在宿主机上找到该POD中的2个容器的容器ID,

通过docker inspect CONTINER_ID --format {{.State.Pid}}查看两个容器在宿主机上的进程号

通过进程ID查看每个进程的ns情况,左侧红色的是被查看进程名称空间文件,右侧则是该文件指向的具体的Namespace文件,中括号里面的是具体Namespace文件号,如果两个进程的指向的Namespace文件号相同,则说明它们处在同一名称空间。

红色箭头编号相同的就是当前POD中2个容器所共享的名称空间。不过在这里我也有些不明白,uts是共享的可是上图中看到的编号确不一样。因为在宿主机的当前终端运行unshare --uts /bin/bash命令将会在一个新的uts名称空间打开一个bash程序,这个bash进程和之前那个就是在不同的uts中,看下图:

进行namespace的api操作
对Namespace的API操作包括clone()、setns()和unshare()。它们有一些不同:
clone():创建新进场的同时可以创建namespace,通过在这个函数中加入不同的名称空间标志来完成。
setns():它是加入一个已经存在的namespace,需要给它传递具体的namespace文件描述符。通常是在调用该函数之后调用clone(),其目的就是让一个新进程在一个已经存在的namespace中运行。
docker exec就是利用这种机制让你指定的命令在容器中运行。unshare():对当前的进程进行namespace隔离,换句话说它不启动新进程,而是让当前进程或者调用它的进程进入到一个新的namespace中。系统命令unshare就是利用这个调用来实现的。
注意在使用unshare系统调用或者命令或者setns系统调用的时候当涉及到PID Namespace的时候它的处理有些特殊,并不是让调用者进入新的PID Namespace,而是让子进程进入,成为该PID Namespace的1号进程。为什么为这样呢?因为一个进程的PID在系统中是常量,一但一个进程运行它的PID就确定了从而它的父子进程也会被确定,所以不能让它在调用setns或者unshare的时候发生变化,一但变化系统就无法维护这个进程表。
同一个POD中默认共享哪些名称空间的更多相关文章
- 问题请教:关于同一个POD中多容器的广播信息问题
		
广大博友好,最近在K8S集群中遇到一个问题,贴出来同大家分享一下 同一个POD中多个容器 如何处理广播信息? 经测试 同一个POD中当先启动的容器占用广播端口后,其他的容器启动就会报bind erro ...
 - python中的作用域与名称空间
		
python中的名称空间以及作用域分析 从Python解释器开始执行之后,就在内存中开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征 ...
 - x名称空间中的内容
		
原文:x名称空间中的内容 x名称空间映射的是http://schemas.microsoft.com/winfx/2006/xaml,它包含的类均与XAML的解析有关,下面分三部分介绍 一:x名称空间 ...
 - 11-TypeScript中的名称空间
		
在后端开发语言中,比如C#中,可以将不同源代码文件中的代码通过名称空间组合到一起.一般一个类定义在一个源代码文件中,在功能上属于一个上下文的源代码文件通过名称空间进行组织. 在TypeScript中, ...
 - 《C++ Primer Plus》读书笔记之七—内存模型和名称空间
		
第九章 内存模型和名称空间 1.不要将函数定义或者变量声明放到头文件中. 2.头文件常包含的内容:函数原型.使用#define或者const定义的常量.结构声明.类声明.模板声明.内联函数. 3.避免 ...
 - 9、XAML名称空间详解
		
XAML命名空间 <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ...
 - 搞懂Python的类和对象名称空间
		
代码块的分类 python中分几种代码块类型,它们都有自己的作用域,或者说名称空间: 文件或模块整体是一个代码块,名称空间为全局范围 函数代码块,名称空间为函数自身范围,是本地作用域,在全局范围的内层 ...
 - [No000013F]WPF学习之X名称空间详解
		
X名称空间里面的成员(如X:Name,X:Class)都是写给XAML编译器看的.用来引导XAML代码将XAML代码编译为CLR代码. 4.1X名称空间里面到底都有些什么? x名称空间映射的是:htt ...
 - WPF学习之X名称空间详解
		
X名称空间里面的成员(如X:Name,X:Class)都是写给XAML编译器看的.用来引导XAML代码将XAML代码编译为CLR代码. 4.1X名称空间里面到底都有些什么? x名称空间映射的是:htt ...
 
随机推荐
- html5 localStorage讲解
			
早期的web中使用cookies在客户端保存诸如用户名等简单的信息,但是,在使用cookies存储永久数据存在以下问题. 1.cookies的大小限制在4kB,不适合大量的数据存储. 2.浏览器还限制 ...
 - 破解Beyond Compare 4
			
Beyond Compare 4 30天试用期后,破解方法. 方法一:在安装目录下找到文件BCUnrar.dll,比如:D:\software\Beyond Compare 4,重命名该文件即可. 重 ...
 - CentOS最小化安装后找不到ifconfig命令
			
1.ifconfig命令是设置或显示网络接口的程序,可以显示出我们机器的网卡信息, 可是有些时候最小化安装CentOS等Linux发行版的时候会默认不安装ifconfig等命令, 这时候你进入终端,运 ...
 - Lodop打印表格带页头页尾 高度是否包含页头页尾 转载
			
通过设置TableHeightScope,可以实现对ADD_PRINT_TABLE,表格带页头页尾,查看本博客另一篇博文:Lodop打印表格带页头页尾 自动分页每页显示头尾 超文本超过打印项高度,会自 ...
 - sikuli for循环例子
			
hover("fiE.png")for x in range(99): type('p',KEY_CTRL) wait("HEIHEUULEWW5.png") ...
 - Dubbo支持的协议(四)
			
1. Dubbo Dubbo 官方推荐的协议 本质:使用 NIO 和线程池进行处理 缺点:大文件传输时可能出现文件传输失败问题. 2. RMI JDK 提供的协议,远程方法调用协议 缺点:偶尔连接失败 ...
 - 启动hadoop后jps没有namenode,并且启动报错9000
			
启动hadoop报错: 解决方法: 我发现没有9000端口被占用,也不知道9000到哪去了,但是也没有NameNode,于是,直接把NameNode格式化了,再重启HDFS即可. 格式化命令:
 - [Python] Python 模拟登录,并请求
			
Python 模拟登录,并请求 # encoding: utf- import requests import socket import time socket.setdefaulttimeout( ...
 - AtCoder Grand Contest 036题解
			
传送门 爆炸的比较厉害--果然还是菜啊-- \(A\) 我们强制一个点为\((0,0)\),那么设剩下两个点分别为\((a,b),(c,d)\),根据叉积可以计算出面积为\(ad-bc=S\),那么令 ...
 - [LeetCode] 214. Shortest Palindrome 最短回文串
			
Given a string s, you are allowed to convert it to a palindrome by adding characters in front of it. ...