一、先谈谈进程

在正式介绍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的更多相关文章

  1. centos7下安装docker(10容器底层--cgroup和namespace)

    cgroup和namespace是实现容器底层的重要技术 cgroup:实现资源限制 namespace:实现资源隔离 1.cgroup:control group Linux操作系统通过cgroup ...

  2. C++ 顺序容器基础知识总结

    0.前言 本文简单地总结了STL的顺序容器的知识点.文中并不涉及具体的实现技巧,对于细节的东西也没有提及.一来不同的标准库有着不同的实现,二来关于具体实现<STL源码剖析>已经展示得全面细 ...

  3. 写给Android App开发人员看的Android底层知识(1)

    这个系列的文章一共8篇,我酝酿了很多年,参考了很多资源,查看了很多源码,直到今天把它写出来,也是战战兢兢,生怕什么地方写错了,贻笑大方. (一)引言 早在我还是Android菜鸟的时候,有很多技术我都 ...

  4. 6.Docker容器底层实现了解与安全机制

    原文地址: 点击直达 0x00 底层实现 我们以 Docker 基础架构来探究Docke底层的核心技术,简单的包括: Linux 上的命名空间(Namespaces) 控制组(Control grou ...

  5. 写给Android App开发人员看的Android底层知识(5)

    (十)Service Service有两套流程,一套是启动流程,另一套是绑定流程.我们做App开发的同学都应该知道. 1)在新进程启动Service 我们先看Service启动过程,假设要启动的Ser ...

  6. JS底层知识理解之执行上下文篇

    JS底层知识理解之执行上下文篇 一.什么是执行上下文(Execution Context) 执行上下文可以理解为当前代码的执行环境,它会形成一个作用域. 二.JavaScript引擎会以什么方式去处理 ...

  7. Java底层知识学习:Bytecode and JMM

    最近在跟着耗子哥的程序员练级指南学习Java底层知识,结合<深入理解Java虚拟机>这本书在看,写笔记,看资料,成长中…… 目前看完了第二章JMM和各内存区OOM的情况 一篇图文并茂介绍字 ...

  8. 容器的进程与namespace、rootfs

    一:容器是什么 容器的本质是一种特殊的进程. 在linux容器中有三个重要的概念:Namespace.Cgroups.rootfs. Namespace做隔离,让进程只能看到Namespace中的世界 ...

  9. 极客时间-左耳听风-程序员攻略-Java底层知识

    Java 字节码相关 字节码编程,也就是动态修改或是动态生成 Java 字节码.Java 的字节码相当于汇编,其中的一些细节. Java Zone: Introduction to Java Byte ...

随机推荐

  1. x86架构:实模式下的中断

    https://www.cnblogs.com/Philip-Tell-Truth/p/5317983.html   这里有详细的过程说明.文字很多,为了方便阅读和理解,提炼了一些要点后归纳.整理了如 ...

  2. 关于python中的 take no arguments 的解决方法

    针对第四章编写的代码出现的错误做一个总结 Traceback (most recent call last): File "H:\image\chapter4\p81_chongxie.py ...

  3. hibernate数据库连接池,常用配置

    <!-- 最大连接数 --> <property name="hibernate.c3p0.max_size">20</property> &l ...

  4. 实验08——java百文百鸡

    package cn.tedu.demo; /** * @author 赵瑞鑫 E-mail:1922250303@qq.com * @version 1.0 * @创建时间:2020年7月17日 下 ...

  5. Json字符串与QVariantList 对象相互转换

    在Qt中QVariantList 使用起来很方便,如果涉及到数据的传输,需要将QVariantList 数据转换为JsonArray字符串,这个转换Qt已经实现好了,只需要调用接口就可以完成转换,代码 ...

  6. 001_解析go语言中的闭包

    go语言中的闭包,是大家学习go语言的一个大难点,笔者在学习时候也是痛苦不堪,在来回对比了其它语言的用法,并且查阅了很多网上的文章,终于对闭包有了一个较为清晰的认识,以下就是关于闭包的解析 首先看一个 ...

  7. Canal v1.1.4版本避坑指南

    前提 在忍耐了很久之后,忍不住爆发了,在掘金发了条沸点(下班时发的): 这是一个令人悲伤的故事,这条情感爆发的沸点好像被屏蔽了,另外小水渠(Canal意为水道.管道)上线一段时间,不出坑的时候风平浪静 ...

  8. python_appium使用原理

    一. appium介绍 Appium是一个开源测试自动化框架,可用于原生,混合和移动Web应用程序测试. 它使用WebDriver协议驱动iOS,Android和Windows应用程序. 多平台支持: ...

  9. JavaFX桌面应用开发系列文章

    ~ JavaFX桌面应用开发系列文章汇总篇 ~ JavaFX桌面应用开发-HelloWorld JavaFX布局神器-SceneBuilder JavaFX让UI更美观-CSS样式 JavaFX桌面应 ...

  10. Java程序员面试必备:Volatile全方位解析

    前言 volatile是Java程序员必备的基础,也是面试官非常喜欢问的一个话题,本文跟大家一起开启vlatile学习之旅,如果有不正确的地方,也麻烦大家指出哈,一起相互学习~ 1.volatile的 ...