【原创】探索容器底层知识之Namespace
一、先谈谈进程
在正式介绍Namespace之前,先介绍下进程,因为容器本质上是进程,但是在介绍进程之前,先理清下“程序”和“进程”的关系,这是IT从业人员在日常工作中经常碰到的两个词汇,举个通俗点的例子帮助大家理解,“程序”可以看成是一张机械图,图上的内容都是手工画上去的,相当于是计算机的输入,在机械图未正式设计出产品的时候,它是静态的,而当工程师按照机械图正式设计各个零部件、组合、啮合到最后产品成型的整个动态过程,可看成是一个进程,因此进程可认为是程序运行起来后的计算机执行环境的总和,是静态程序的具体实现。
二、容器的namespace
在上节中介绍了什么是进程,可通过ps命名查看当前宿主机正在运行的进程,如下图所示
[root@k8s-master James]# ps
PID TTY TIME CMD
pts/ :: su
pts/ :: bash
pts/ :: ps
容器本质上对于Linux操作系统来说,和上述进程一样,但是会在进程上加入了很多namespace来实现进程、挂载点、网络、用户信息之间的隔离,这样容器看上去就像一个沙箱,在沙箱内部只能看到和操作限定namespace下的系统资源,以PID namespace为例,我们先创建1个容器
[root@k8s-master James]# docker run -it -d busybox /bin/sh
01a0fd62d2110e54b0c3635b2897e7c18e6b78f026fa57b4214d7662dd3b38ba
[root@k8s-master James]# docker exec -it 01a0fd62d2110e54b0c3635b2897e7c18e6b78f026fa57b4214d7662dd3b38ba /bin/sh
/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh
6 root 0:00 /bin/sh
11 root 0:00 ps
这条命名的意思是我想启动一个容器执行/bin/bash命令,并分配一个伪终端的交互窗口和容器进行交互,docker run是创建和启动容器的意思,-it表示就是分配一个伪终端的输入和输出交互窗口,busybox是镜像,/bin/bash是操作程序。当创建成功后,输入ps可查看容器中正在运行的进程,可以看到有2个进程,PID代表进程的唯一编号,可以看到1号PID的操作程序为/bin/bash,之前谈到容器也是一种进程,回到宿主机查看下此容器的进程
[root@k8s-master James]# docker container top 01a0fd62d2110e54b0c3635b2897e7c18e6b78f026fa57b4214d7662dd3b38ba
UID PID PPID C STIME TTY TIME CMD
root : pts/ :: /bin/sh
其PID为24691了,此PID在容器中不存在,也就是说容器中只能看到自己程序执行后的进程,而看不到其他容器和宿主机上的进程,且容器里面的进程编号PID也做了障眼法般的处理,与宿主机上的PID不一致,而实现这个技术的就是PID namespace,而容器类似的还有NET、IPC、MNT、UTS、USER的namespace,其对应隔离的内容如下表所示:
| namespace | 隔离的内容 |
|---|---|
| PID | 进程 |
| IPC | 信号量、消息队列和共享内容 |
| UTS | 主机名、域名 |
| NET | 网络设备、网络栈、端口 |
| MNT | 文件系统 |
| User | 用户和用户组 |
网络相对比较复杂,我们再详细深入看下,从上表可以看出不同的网络命名空间可以隔离网络设备、网络栈、端口等,为了达到这个目标,LINUX系统就需要支持虚拟化网络协议栈的多个实例,且这些独立的协议栈可处于不同的网络命名空间来进行隔离,达到彼此无法进行通信隔离的效果,如果想要不同的网络命名空间设备进行通信,应如何操作呢?答案是:veth设备对,什么是veth设备对,你可以认为是一根管道,一端连接一个网络命名空间的协议栈,另外一端连接另外一个网络命名空间的协议栈来实现通信,那如何建立veth设备对呢?接下来一起操作下
在root用户下,先创建一个网络命名空间
[root@k8s-master zhanglei]# ip netns add net_test1
[root@k8s-master zhanglei]# ip netns list
net_test1
再创建一个设备对veth:
[root@k8s-master zhanglei]# ip link add veth0 type veth peer name veth1
[root@k8s-master zhanglei]# ip link show
: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu qdisc noop state DOWN mode DEFAULT group default qlen
可以看到veth0和veth1的设备对已经生成,veth的设备支持在不同的网络命名空间进行转移,将veth0设备住转移到net_test1命名空间
[root@k8s-master zhanglei]# ip link set veth0 netns net_test1
此时在宿主机上ip link show,因不同的网络命名空间设备是隔离的,且veth0设备已经被移动到net_test1网络命名空间,因此将无法在宿主机网络命名空间再次找到veth0
[root@k8s-master zhanglei]# ip netns exec net_test1 ip link show
: lo: <LOOPBACK> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/loopback ::::: brd :::::
: tunl0@NONE: <NOARP> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/ipip 0.0.0.0 brd 0.0.0.0
: veth0@if59: <BROADCAST,MULTICAST> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/ether :c0::4d:: brd ff:ff:ff:ff:ff:ff link-netnsid
同时我们将另veth1设置到命名空间net_test2里面
[root@k8s-master zhanglei]# ip netns add net_test2
[root@k8s-master zhanglei]# ip netns show
net_test2
net_test1 (id: )
[root@k8s-master zhanglei]# ip link set veth1 netns net_test2
[root@k8s-master zhanglei]# ip netns exec net_test2 ip link show
: lo: <LOOPBACK> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/loopback ::::: brd :::::
: tunl0@NONE: <NOARP> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/ipip 0.0.0.0 brd 0.0.0.0
: veth1@if60: <BROADCAST,MULTICAST> mtu qdisc noop state DOWN mode DEFAULT group default qlen
link/ether 7e::da:3a:: brd ff:ff:ff:ff:ff:ff link-netns net_test1
到这里,veth0和veth1这个设备对已经配置在不同的网络命名空间了,但是此时还不能通信,就像电线已经搭好,但是还未通电,谁来扮演通电的角色呢?答案就是:IP
[root@k8s-master zhanglei]# ip netns exec net_test1 ip addr add 10.1.1.1/ dev veth0
[root@k8s-master zhanglei]# ip netns exec net_test2 ip addr add 10.1.1.2/ dev veth1
[root@k8s-master zhanglei]# ip netns exec net_test1 ip link set dev veth0 up
[root@k8s-master zhanglei]# ip netns exec net_test2 ip link set dev veth1 up
[root@k8s-master zhanglei]# ip netns exec net_test1 ping 10.1.1.2
PING 10.1.1.2 (10.1.1.2) () bytes of data.
bytes from 10.1.1.2: icmp_seq= ttl= time=0.097 ms
bytes from 10.1.1.2: icmp_seq= ttl= time=0.061 ms
bytes from 10.1.1.2: icmp_seq= ttl= time=0.032 ms
bytes from 10.1.1.2: icmp_seq= ttl= time=0.024 ms
[root@k8s-master zhanglei]# ip netns exec net_test2 ping 10.1.1.1
PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data.
64 bytes from 10.1.1.1: icmp_seq=1 ttl=64 time=0.030 ms
64 bytes from 10.1.1.1: icmp_seq=2 ttl=64 time=0.090 ms
64 bytes from 10.1.1.1: icmp_seq=3 ttl=64 time=0.032 ms
64 bytes from 10.1.1.1: icmp_seq=4 ttl=64 time=0.033 ms
[root@k8s-master zhanglei]# ip netns exec net_test2 ping 10.1.1.1
PING 10.1.1.1 (10.1.1.1) () bytes of data.
bytes from 10.1.1.1: icmp_seq= ttl= time=0.030 ms
bytes from 10.1.1.1: icmp_seq= ttl= time=0.090 ms
bytes from 10.1.1.1: icmp_seq= ttl= time=0.032 ms
bytes from 10.1.1.1: icmp_seq= ttl= time=0.033 ms
如上,给每个设备配备1个ip地址,配备成功后再启动设备,然后就可以进行相互的通信了,前面提到每个容器拥有自己单独的网络命名空间,而网络命名空间之间的通信是通过设备对,而上面演示的就是命名空间通过设备对进行通信的全过程,
事实上容器之间、容器与宿主机之间都是通过设备对的方式进行通信的,当然实际上容器网络命名空间的创建、设备对的创建、IP的分配并不是手动进行的,都是容器在创建的时候会自动完成,对用户来说是无感知的,这里是方便展示内部原理,采用的手动的形式。
三、总结
本文主要重点介绍了容器PID和NET 命名空间(namespace)的隔离原理,其他namespace的隔离原理类似,容器本质上一种特殊的进程,它虽然提供了隔离技术,但与虚拟机的隔离技术要区别开来,虚拟机是在宿主机上通过Hypervisor虚拟了一个独立的GuestOS,它的隔离是彻底的,虚拟机上的进程在宿主机上无法查看;而容器本质上是宿主机上的进程,它的隔离机制是通过在进程上加入不同的namespace参数来实现资源、文件、设备、状态,或者配置的隔离,两者隔离的本质是有差异的,你或许有个疑问,既然容器是宿主机上的一个进程,而不同的进程可以相互共享宿主机的内核,一旦一个容器的应用逃逸影入侵宿主机,是不是会有可能会影响宿主机或者其他容器应用呢,事实上,的确存在这样的安全隐患,由此看来,容器的隔离性并不像虚拟机般隔离的彻底。
【原创】探索容器底层知识之Namespace的更多相关文章
- centos7下安装docker(10容器底层--cgroup和namespace)
cgroup和namespace是实现容器底层的重要技术 cgroup:实现资源限制 namespace:实现资源隔离 1.cgroup:control group Linux操作系统通过cgroup ...
- C++ 顺序容器基础知识总结
0.前言 本文简单地总结了STL的顺序容器的知识点.文中并不涉及具体的实现技巧,对于细节的东西也没有提及.一来不同的标准库有着不同的实现,二来关于具体实现<STL源码剖析>已经展示得全面细 ...
- 写给Android App开发人员看的Android底层知识(1)
这个系列的文章一共8篇,我酝酿了很多年,参考了很多资源,查看了很多源码,直到今天把它写出来,也是战战兢兢,生怕什么地方写错了,贻笑大方. (一)引言 早在我还是Android菜鸟的时候,有很多技术我都 ...
- 6.Docker容器底层实现了解与安全机制
原文地址: 点击直达 0x00 底层实现 我们以 Docker 基础架构来探究Docke底层的核心技术,简单的包括: Linux 上的命名空间(Namespaces) 控制组(Control grou ...
- 写给Android App开发人员看的Android底层知识(5)
(十)Service Service有两套流程,一套是启动流程,另一套是绑定流程.我们做App开发的同学都应该知道. 1)在新进程启动Service 我们先看Service启动过程,假设要启动的Ser ...
- JS底层知识理解之执行上下文篇
JS底层知识理解之执行上下文篇 一.什么是执行上下文(Execution Context) 执行上下文可以理解为当前代码的执行环境,它会形成一个作用域. 二.JavaScript引擎会以什么方式去处理 ...
- Java底层知识学习:Bytecode and JMM
最近在跟着耗子哥的程序员练级指南学习Java底层知识,结合<深入理解Java虚拟机>这本书在看,写笔记,看资料,成长中…… 目前看完了第二章JMM和各内存区OOM的情况 一篇图文并茂介绍字 ...
- 容器的进程与namespace、rootfs
一:容器是什么 容器的本质是一种特殊的进程. 在linux容器中有三个重要的概念:Namespace.Cgroups.rootfs. Namespace做隔离,让进程只能看到Namespace中的世界 ...
- 极客时间-左耳听风-程序员攻略-Java底层知识
Java 字节码相关 字节码编程,也就是动态修改或是动态生成 Java 字节码.Java 的字节码相当于汇编,其中的一些细节. Java Zone: Introduction to Java Byte ...
随机推荐
- PHP is_resource() 函数
is_resource() 函数用于检测变量是否为资源类型. PHP 版本要求: PHP 4, P+-HP 5, PHP 7高佣联盟 www.cgewang.com 语法 bool is_resour ...
- PDO::getAvailableDrivers
PDO::getAvailableDrivers — 返回一个可用驱动的数组(PHP 5 >= 5.1.0, PECL pdo >= 0.1.0) 说明 语法 static array P ...
- Pr剪辑
目录 Pr剪辑教程 入门基础 创建序列类别 处理非正常序列 导出文件 导出设置 导入各类别素材 简单使用: 剪辑素材常用方法 剃刀工具 选择工具 波纹编辑工具 打入点和出点 剪辑速度 整个素材视频速度 ...
- Scala---初探
scala语言量大特性:面向对象+函数式编程 Scala的类型 val指的是引用不可变,而不是值. 值类型 Byte Char Short Int Long Float Double 引用类型 Str ...
- 6月28日考试 题解(GCD约分+动态规划+树状数组二维偏序)
前言:考的一般般吧……T3暴力没打上来挺可惜的,到手的75分没了. ---------------------------------- T1 [JZOJ4745]看电影 Description 听说 ...
- 新浪、腾讯、淘宝为何如此重视Web前端?前端入门容易吗?
为什么新浪.搜狐.网易.腾讯.淘宝等在内的各种规模的IT企业,都对web前端越来越重视了呢?小编为您揭晓答案! web前端的由来 以前会Photoshop和Dreamweaver就可以制作网页.随着时 ...
- C#LeetCode刷题-树状数组
树状数组篇 # 题名 刷题 通过率 难度 218 天际线问题 32.7% 困难 307 区域和检索 - 数组可修改 42.3% 中等 315 计算右侧小于当前元素的个数 31.9% 困难 ...
- jQuery的小测试
1.在div元素中,包含了一个<span>元素,通过has选择器获取<div>元素中的<span>元素的语法是? $('div:has(span)'); 2.在&l ...
- 源码剖析Springboot自定义异常
博主看到新服务是封装的自定义异常,准备入手剖析一下,自定义的异常是如何进行抓住我们请求的方法的异常,并进行封装返回到.废话不多说,先看看如何才能实现封装异常,先来一个示例: @ControllerAd ...
- python设计模式之修饰器模式
python设计模式之修饰器模式 无论何时我们想对一个对象添加额外的功能,都有下面这些不同的可选方法. [ ] 如果合理,可以直接将功能添加到对象所属的类(例如,添加一个新的方法) [ ] 使用组合 ...