如果通过POD的形式来启动多个容器那么它们的名称空间会是共享的么,所以我这里讨论是在默认情况下同一个POD的不同容器的哪些名称空间是打通的。这里先说一下结论,共享的是UTS、IPC、NET、USER。

UTS名称空间

主机名名称空间,保存内核名称、版本以及主机名和域名。默认情况下同一个POD的不同容器是共享UTS的,看下面的配置:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: centos-dep
  5. labels:
  6. app: centos
  7. spec:
  8. replicas: 1
  9. selector:
  10. matchLabels:
  11. app: centos
  12. template:
  13. metadata:
  14. labels:
  15. app: centos
  16. spec:
  17. containers:
  18. - name: app1
  19. image: centos
  20. imagePullPolicy: IfNotPresent
  21. command: ["/bin/sh", "-c"]
  22. args:
  23. - sleep 3600
  24. - name: app2
  25. image: centos
  26. imagePullPolicy: IfNotPresent
  27. command: ["/bin/sh", "-c"]
  28. args:
  29. - 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:

  1. {
  2. "userns-remap": "default",
  3. }

在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):

  1. echo "dockremap:10000:65536" > /etc/subuid
  2. 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的时候发生变化,一但变化系统就无法维护这个进程表。

Namespace的资源隔离

Docker背后的内核知识1

Linux Namespace User

理解Docker容器的UID和GID

隔离Docker容器中的用户

同一个POD中默认共享哪些名称空间的更多相关文章

  1. 问题请教:关于同一个POD中多容器的广播信息问题

    广大博友好,最近在K8S集群中遇到一个问题,贴出来同大家分享一下 同一个POD中多个容器 如何处理广播信息? 经测试 同一个POD中当先启动的容器占用广播端口后,其他的容器启动就会报bind erro ...

  2. python中的作用域与名称空间

    python中的名称空间以及作用域分析 从Python解释器开始执行之后,就在内存中开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征 ...

  3. x名称空间中的内容

    原文:x名称空间中的内容 x名称空间映射的是http://schemas.microsoft.com/winfx/2006/xaml,它包含的类均与XAML的解析有关,下面分三部分介绍 一:x名称空间 ...

  4. 11-TypeScript中的名称空间

    在后端开发语言中,比如C#中,可以将不同源代码文件中的代码通过名称空间组合到一起.一般一个类定义在一个源代码文件中,在功能上属于一个上下文的源代码文件通过名称空间进行组织. 在TypeScript中, ...

  5. 《C++ Primer Plus》读书笔记之七—内存模型和名称空间

    第九章 内存模型和名称空间 1.不要将函数定义或者变量声明放到头文件中. 2.头文件常包含的内容:函数原型.使用#define或者const定义的常量.结构声明.类声明.模板声明.内联函数. 3.避免 ...

  6. 9、XAML名称空间详解

    XAML命名空间 <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"      ...

  7. 搞懂Python的类和对象名称空间

    代码块的分类 python中分几种代码块类型,它们都有自己的作用域,或者说名称空间: 文件或模块整体是一个代码块,名称空间为全局范围 函数代码块,名称空间为函数自身范围,是本地作用域,在全局范围的内层 ...

  8. [No000013F]WPF学习之X名称空间详解

    X名称空间里面的成员(如X:Name,X:Class)都是写给XAML编译器看的.用来引导XAML代码将XAML代码编译为CLR代码. 4.1X名称空间里面到底都有些什么? x名称空间映射的是:htt ...

  9. WPF学习之X名称空间详解

    X名称空间里面的成员(如X:Name,X:Class)都是写给XAML编译器看的.用来引导XAML代码将XAML代码编译为CLR代码. 4.1X名称空间里面到底都有些什么? x名称空间映射的是:htt ...

随机推荐

  1. 获取APK的appPackage和appActivity

    [法二]AndroidSDK 此方法是采用AndroidSDK\build-tools\23.0.2(这个版本号可能不一定,但是一般每个版本号里面都,任意即可)\aapt.exe aapt dump ...

  2. 201871010123-吴丽丽《面向对象程序设计(Java)》第十一周学习总结

    201871010123-吴丽丽<面向对象程序设计(Java)>第十一周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...

  3. 【使用篇二】SpringBoot热部署(11)

    热部署有三种方式: SpringLoader 插件 DevTools 工具 安装JRebel插件 注意:热部署的功能依赖于工具的自动编译,Eclipse-->Build Automaticall ...

  4. webapi添加basic认证

      BasicAbstractAuthorize:抽象类,子类中校验用户名密码,并创建Principal BasicAuthorize:实现类 //base.OnAuthorization(),此方法 ...

  5. 2019 SDN上机第3次作业

    1. 利用Mininet仿真平台构建如下图所示的网络拓扑,配置主机h1和h2的IP地址(h1:10.0.0.1,h2:10.0.0.2),测试两台主机之间的网络连通性 创建拓扑 配置主机h1和h2的I ...

  6. CF1163E Magical Permutation(线性基,构造)

    虽然做起来有一点裸……但是就是想不到啊…… 首先令 $d_i=p_i\oplus p_{i-1}$,那么 $d_i$ 都是 $S$ 中的数,$a_i=d_i\oplus d_{i-1}\oplus \ ...

  7. 图论问题(1) : hdu 1198

    题目转自hdu 1198,题目传送门 题目大意: 给你11种单位水管摆放位置,若上下或左右有水管连接则视为这两点相连. 最后让你求这些张图中有几个连通块. 解题思路: 本来觉得这道题很简单,不就一个建 ...

  8. [LeetCode] 130. Surrounded Regions 包围区域

    Given a 2D board containing 'X' and 'O'(the letter O), capture all regions surrounded by 'X'. A regi ...

  9. [LeetCode] 112. Path Sum 二叉树的路径和

    Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all ...

  10. DVWA XSS (DOM) 通关教程

    DOM,全称Document Object Model,是一个平台和语言都中立的接口,可以使程序和脚本能够动态访问和更新文档的内容.结构以及样式. DOM型XSS其实是一种特殊类型的反射型XSS,它是 ...