| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> Docker隔离技术 -> 正文阅读 |
|
[系统运维]Docker隔离技术 |
前言Docker系列文章: 此篇是Docker系列的第九篇,之前的文章里面或多或少的提到Docker的隔离技术,但是没有很清楚的去聊这个技术,但是经过这么多文章大家一定对Docker使用和概念有了一定的理解,接下来我们聊下底层一些技术,帮助大家解解惑,先从隔离技术开始吧。此外大家一定要按照我做的Demo都手敲一遍,印象会更加深刻的,加油! 如何理解Namespace进入一个容器内部:
通过ps命令查看容器内部的进程,容器内部只有两个进程在运行,看不到操作系统的其他进程,一个进程执行的/bin/bash,另外一个执行的ps,说明此刻容器被 Docker 隔离在了一个跟宿主机在不同的环境中。 img 对于宿主机来说相当于我们在宿主机上执行一个/bin/bash的进程,宿主机给这个进程起一个独一无二名字,比如叫PID=800,用来区分与其他进程的不同,Docker在运行/bin/bash的时候,会与宿主机上的其他进程进行隔离,让他看不到其他进程运行状况,并且重新计算进程号,也就是我们看到202,但是这个进程实际上是宿主机的进程,这种技术,其实就是对被隔离应用的进程空间做了手脚,使得这些进程只能看到重新计算过的进程编号,这就是Linux里面的Namespace机制,也就是Docker采用的隔离技术。 总结一下,Namespace是Linux内核用来隔离内核资源的方式。通过Namespace可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程的相关资源指定在同一个Namespace中。Linux Namespace是对全局系统资源的一种封装隔离,使得处于不同Namespace的进程拥有独立的全局系统资源,改变一个Namespace中的系统资源只会影响当前Namespace里的进程,对其他Namespace中的进程没有影响。 Namespace类型介绍目前,Linux 内核实现了6种 Namespace: img 六种命名空间:
Namespace原理介绍Linux Namespace 是 Linux 提供的一种内核级别环境隔离的方法,因此Linux 提供了多个 API 用来操作 Namespace,它们是 clone()、setns() 和 unshare() 函数,简单介绍一下三个系统调用的功能:
为了确定隔离的到底是哪项 Namespace,在使用这些 API 时,通常需要指定一些调用参数:CLONE_NEWIPC、CLONE_NEWNET、CLONE_NEWNS、CLONE_NEWPID、CLONE_NEWUSER、CLONE_NEWUTS 和 CLONE_NEWCGROUP。下图是各个Namespace对应的调用参数和Linux内核: img 如果要同时隔离多个 Namespace,可以使用 | (按位或)组合这些参数。同时我们还可以通过 /proc 下面的一些文件来操作 Namespace。下面就让让我们看看这些接口的用法: 查看进程所属的Namespace 从版本号为 3.8 的内核开始,/proc/[pid]/ns 目录下会包含进程所属的 Namespace 信息,使用下面的命令可以查看当前进程所属的 Namespace 信息:
这些 Namespace 文件都是链接文件。链接文件的内容的格式为 xxx:[inode number]。其中的 xxx 为 Namespace 的类型,inode number 则用来标识一个 Namespace,我们也可以把它理解为 Namespace 的 ID。如果两个进程的某个 Namespace 文件指向同一个链接文件,说明其相关资源在同一个 Namespace 中。 clone() 函数 我们可以通过 clone() 在创建新进程的同时创建 Namespace。clone() 在 C 语言库中的声明如下:
实际上,clone() 是在 C 语言库中定义的一个封装(wrapper)函数,它负责建立新进程的堆栈并且调用对编程者隐藏的 clone() 系统调用。四个参数代表的意思是:
clone() 与 fork() 类似,都相当于把当前进程复制了一份,但 clone() 可以更细粒度地控制与子进程共享的资源(可以通过 flags 来控制),包括虚拟内存、打开的文件描述符和信号量等等。一旦指定了标志位 CLONE_NEW*,相对应类型的 Namespace 就会被创建,新创建的进程也会成为该 Namespace 中的一员。 setns() 函数 setns() 函数可以将当前进程加入到已有的 Namespace 中。setns() 在 C 语言库中的声明如下:
和 clone() 函数一样,C 语言库中的 setns() 函数也是对 setns() 系统调用的封装:
unshare() 函数 unshare() 函数可以在原进程上进行 Namespace 隔离。也就是创建并加入新的 Namespace 。unshare() 在 C 语言库中的声明如下:
unshare() 函数也是对 unshare() 系统调用的封装。调用 unshare() 的主要作用就是:不启动新的进程就可以起到资源隔离的效果,相当于跳出原先的 Namespace 进行操作。 使用PID Namesapce达到Docker线程隔离状态 Linux下的每个进程都有一个对应的 /proc/PID 目录,该目录包含了大量的有关当前进程的信息。 对一个 PID Namespace 而言,/proc 目录只包含当前 Namespace 和它所有子孙后代 Namespace 里的进程的信息。 创建一个新的 PID Namespace 后,如果想让子进程中的 top、ps 等依赖 /proc 文件系统的命令工作,还需要挂载 /proc 文件系统。使用如下命令创建一个新的PID Namespace:
上图中新生成的PID Namespace的Id并没有发生改变,我们看到在新创建的PID Namespace也可以看到其他的进程的运行情况,显然这个和我们说的隔离是不一致的,接下来我们看下原因是什么: img
这个例子说明当前进程被认为是该 PID namespace 中的 1 号进程了,通过PS命名查看1号进程的详情,发现这个进程是系统的启动相关(CentOS 7开始也由systemd取代了init作为默认的系统进程管理工具)。 造成混乱的原因是当前进程没有正确的挂载 /proc 文件系统,由于我们新的 Mount Namespace 的挂载信息是从老的 Namespace 拷贝过来的,所以这里看到的还是老 Namespace 里面的进程号为 1 的信息。执行下面的命令挂载 /proc 文件系统:
接下来我们再来检查相关的信息,会发现新建的 PID namespace 进程看不到宿主机的进程信息了。 img 我们也可以使用如下命令来创建进程,
这样在创建了 PID 和 Mount Namespace 后,会自动挂载 /proc 文件系统,就不需要我们手动执行 mount -t proc proc /proc 命令了。 总结 Docker容器是在创建容器进程时,指定了这个进程所需要启用的一组Namespace参数,这样容器就只能看到到当前Namespace所限定的资源、文件、设备、状态,或者配置。而对于宿主机以及其他不相关的程序,它就完全看不到了,因此容器本质上就是一个特殊的进程。 结束欢迎大家点点关注,点点赞! |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 | -2024/12/27 11:19:10- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |
数据统计 |