[k8s理论知识]3.docker基础(二)隔离技术

news2024/11/26 8:21:49

容器其实是一种沙盒技术,其核心是通过约束和修改进程的动态表现,为其创建一个边界。这个边界确保了应用与应用之间不会相互干扰,同时可以方便在不同的环境中迁移,这是PaaS最理想的状态。

程序是代码的可执行镜像,通常以二进制文件的形式存储在磁盘上。但是当程序被执行时,操作系统会将程序的数据加载到内存中,读取计算指令并指示CPU执行。CPU与内存协作进行计算,使用寄存器存放数值,内存堆栈保存执行的命令和变量,此外,程序还可能打开文件和调用IO设备。所有这些状态信息和数据信息的集合,构成了进程的动态表现。

进程可以理解为是 动态的程序,但更准确地说,进程是程序在计算机系统中的一个 执行实例。程序本身只是静态的代码文件(通常指由源代码编译得到的可执行文件),而进程则是该程序的一个活动状态,它包含了程序的执行上下文和资源。

那么,如果给进程之间确立边界,也就是给程序创建了边界。而容器技术的核心,就是通过约束和修改进程的动态表现,从而为其创造一个边界。

Nampespace技术

启动一个busybox容器,通过以下操作让我们更好的理解进程隔离。

[root@master ~]# docker run -it busybox:v1 /bin/sh
/ # pid
/bin/sh: pid: not found
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
    6 root      0:00 ps

可以看到,我们在 Docker 里最开始执行的 /bin/sh,就是这个容器内部的第 1 号进程(PID=1),而这个容器里一共只有两个进程在运行。这就意味着,前面执行的 /bin/sh,以及我们刚刚执行的 ps,已经被 Docker 隔离在了一个跟宿主机完全不同的世界当中。

当我们不要关闭这个命令行(否则容器会销毁),而打开另一个窗口,查看这个容器的pid,可以看到这个容器的PID实际为16043。

[root@master ~]# docker ps | grep busybox
e45240f24ffb   busybox:v1                                          "/bin/sh"                 12 seconds ago   Up 11 seconds             epic_moser
[root@master ~]# docker inspect --format '{{.State.Pid}}' e45240f24ffb 
16043

以上表述实际上是非常不严谨的,因为容器本身没有PID,容器只是为程序提供一个隔离的视图,而运行在容器里的程序(在我们的例子中是/bin/bash)才拥有PID。也就是说在查看容器的PID的时候,查看的实际上是它内部程序的PID。

所以我们可以理解,这个bin/bash本身的PID是16043,而容器实施了一个障眼法,让前面的所有PID都看不见了,这个程序的PID也就成了1。

事实上,以上只是将进程空间进行了Namespace隔离,容器还需要进行文件系统、IO设备等的隔离。这些在后面会一一演示。

在理解了 Namespace 的工作方式之后,你就会明白,跟真实存在的虚拟机不同,在使用 Docker 的时候,并没有一个真正的“Docker 容器”运行在宿主机里面。Docker 项目帮助用户启动的,还是原来的应用进程,只不过在创建这些进程时,Docker 为它们加上了各种各样的 Namespace 参数。

Cgroups

从上面例子可以看出,Namespace技术改变了进程看待计算机的视图,但是计算机并没有改变看待进程的视图,对于底层操作系统而言,容器里的进程和直接运行的进程没有区别。也就是说,虽然上面例子中的bin/bash进程表面上被隔离了起来,但是实际上它能得到的内存和cpu资源,却可以随意的被其他进程占用。而这个进程本身也可以吃掉别的进程的资源,这不符合一个沙盒的行为表现。而且,在linux内核中,有很多的资源是不能namespace化的,比如时间。

Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。通过以下命令可以看到cgroup在系统中挂载的位置。

[root@master ~]# mount -t cgroup 
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_prio,net_cls)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)

可以看到,在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是我这台机器当前可以被 Cgroups 进行限制的资源种类。我们进入CPU目录,可以看到有很多cpu的配置文件。在这些文件中,文件夹container是我们后来创建的。

当我们进入container文件夹,会看到里面已经创建了完整的cgoups文件系统。 这是因为当你在cgroups的某个子系统(比如cpu或者sys等),你实际上在创建一个新的控制组,控制组允许你为该组内的进程设置资源限制或监控资源使用情况。因此Linux内核会在这个子目录下生成一系列与该子系统相关的文件。

 但是这些文件实际上是虚拟的,并不是存储载物理磁盘上的文件,只是为用户提供的与内核交互的接口。

 随后打开另一个终端,执行以下命令。这条命令是一个死循环,会吃光所有cpu资源。

可以看到这个进程PID是47975。

接下来进入container目录, 看到 container 控制组里的 CPU quota 还没有任何限制(即:-1),CPU period 则是默认的 100  ms(100000  us)

[root@master container]# cat cpu.cfs_period_us 
100000
[root@master container]# cat cpu.cfs_quota_us 
-1

接下来我们进行控制组的限制操作,向container组里的cfs_quota和cfs_period文件写入参数进行限制。

以下的操作意思是100000us(100ms)里面有20000us(20ms)可以给这个控制组使用。

接下来要将这个PID(47975)放入这个控制组。

重新用top命令查看,发现 它虽然是一个死循环,但是只占用了20%的cpu资源。

控制组 

不是每一个Linux进程都有自己的控制组,但是每个进程都会属于某一个资源控制组。在没有配置自定义 cgroups 的情况下,所有进程都会被分配到系统的默认控制组,这些默认的 cgroups 通常是由 init 系统(如 systemd)或直接由内核管理的。多个进程也可以被放置在同一个控制组中。

比如说我们查看cgroup/cpu里的user.slice文件夹,可以看到里面有一个procs文件,打开可以看到这个资源控制组的所有进程。

假设有一个进程PID是12345,我们可以将它加入控制组中。

echo 12345 > /sys/fs/cgroup/cpu/user.slice/cgroup.procs

创建一个docker,并规定了他的cpu资源限制。可以看到docker ID是b47efc8e7d29,cgroup目录是system.slice下的以b47efc8e7d29开头的文件夹。

[root@master ~]# docker run  -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash
root@b47efc8e7d29:/# cat /proc/self/cgroup
11:pids:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
10:memory:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
9:perf_event:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
8:cpuset:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
7:net_prio,net_cls:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
6:devices:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
5:blkio:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
4:cpuacct,cpu:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
3:hugetlb:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
2:freezer:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope
1:name=systemd:/system.slice/docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope

进入文件夹,可以看到他的cpu资源限制。 也就是说docker可以在创建容器的时候进行资源限制。

[root@master system.slice]# cd docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope/
[root@master docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope]# ls
cgroup.clone_children  cgroup.procs  cpuacct.usage         cpu.cfs_period_us  cpu.rt_period_us   cpu.shares  notify_on_release
cgroup.event_control   cpuacct.stat  cpuacct.usage_percpu  cpu.cfs_quota_us   cpu.rt_runtime_us  cpu.stat    tasks
[root@master docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope]# cat cpu.rt_period_us 
1000000
[root@master docker-b47efc8e7d291be37292fdf8edb160947e2bfa413595f90d6d4960f7b22a3edf.scope]# cat cpu.cfs_quota_us 
20000
echo操作 

 /sys/fs/cgroup/cpu/container/cgroup.procs 和 /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us 这两个文件的行为是不同的,所以当我们进行echo操作的时候,写入cpu.cfs_quota_us 文件的行为是覆盖式的。当你使用 echo 写入一个新的值时,它会替换掉之前的值。cgroup.procs 是一个特殊的文件,它的目的是让用户通过写入进程 ID 来动态管理进程所属的控制组。因此它的行为不是像普通文件那样追加或覆盖内容,而是执行一个动作(将进程加入到该控制组)。

文件系统

如果不进行单的文件系统挂载,容器内的进程的文件系统视图就是整个物理主机的视图。所以在容器创建之前,docker通过重新挂载根目录,从而让容器进程看到的是一个独立的隔离环境。为了能够让容器的这个根目录看起来更“真实”,Docker会在这个容器的根目录下挂载一个完整操作系统的文件系统,比如 Ubuntu16.04 的 ISO。这样,在容器启动之后,我们在容器里通过执行 "ls /" 查看根目录下的内容,就是 Ubuntu 16.04 的所有目录和文件。而挂载在容器根目录上,用来为进程提供隔离后环境的文件的操作系统,就是所谓的容器镜像。它还有一个更为专业的名字,叫作:rootfs(根文件系统)。

值得注意的是,rootfs只是一个操作系统所包含的文件、配置和目录,并不包含操作系统的内核。Linux操作系统分为两部分,内核和用户态。

内核:这是操作系统的核心,负责与硬件交互、调度进程、管理内存、网络、文件系统等。无论是ubuntu、centos还是其他linux发行版的内核,他们的核心功能是相同的。

用户态:这是操作系统中用户可以直接接触的部分,比如程序、库、配置文件等等。不同的linux发行版(linux/ubuntu/debian)在用户态可能有很大不同,包括包管理、配置文件等。

对于容器来讲,操作系统就是宿主机的操作系统内核。所以说,当你拉取一个 CentOS 容器镜像时,实际上你只是拉取了 CentOS 的用户态部分(包括系统工具、库、配置文件等),而不包含 CentOS 的内核。容器中的进程依然使用的是宿主机的内核来运行。因此,无论宿主机运行的是 Ubuntu 还是其他发行版的内核,只要它是 Linux 内核,容器中的 CentOS 文件系统都可以正常工作。

Docker和VM对比

但是事实上,宿主机不可能光有一个内核态,他也是有用户态的。当你在一个 Ubuntu 宿主机上运行一个 CentOS 容器时,容器中的进程会使用 CentOS 的用户态工具和库。比如,容器中的 yum(CentOS 的包管理器)可以正常运行,而不会使用 Ubuntu 的 apt(Ubuntu 的包管理器)。因此,容器就像是一个独立的系统,拥有自己的文件系统、程序、配置等,不依赖宿主机的用户态。你可以把它想象为容器本身有一个“虚拟的用户态”,但它并不运行在宿主机的用户态环境中。

当你在一个 Ubuntu 宿主机上运行了一个 CentOS 虚拟机,虚拟机内的 CentOS 系统会像在物理机上一样启动,它将加载自己的 CentOS 内核,并启动 CentOS 的用户态环境。CentOS 虚拟机使用自己的内核来处理系统调用、管理进程、分配内存等。这个内核与宿主机的内核完全独立,因此 CentOS 虚拟机可以运行与宿主机不同版本的内核。

对 Docker 项目来说,它最核心的原理实际上就是为待创建的用户进程:启用 Linux Namespace 配置;设置指定的 Cgroups 参数;切换进程的根目录(Change Root)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2219795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot项目get请求遇到:Message Request header is too large报错。

一、错误日志 HTTP Status 400 – Bad Request Type Exception ReportMessage Request header is too largeDescription The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, inva…

Django学习-ORM_常用字段及字段选项

字段选项: 注意:当我们新增数据的时候,如果没有新增设置了default的字段,此时会使用default设置的默认值填充到新增的数据中

数字后端零基础入门系列 | Innovus零基础LAB学习Day2

今天开始更新数字IC后端设计实现中Innovus零基础Lab学习后续内容。 数字后端零基础入门系列 | Innovus零基础LAB学习Day1 ####LAB5-2 这个章节的目标也很明确——学习掌握工具的一些常用快捷键。 这里只需要掌握以下几个快捷键即可。其他小编我也不会,也用不着。…

【初识数据库】

目录 一、数据库简介 1.什么是数据库 2.数据库与数据结构有啥关系 3.为什么要使用数据库 二、数据库服务器、数据库和表的关系 三、客户端与服务器的通讯方式 1.C/S架构 2.B/S架构 3.命令提示符 4.MySQL架构 一、数据库简介 1.什么是数据库 组织和保存数据的应用程序…

【JavaEE初阶】深入理解网络编程—使用UDP协议API实现回显服务器

前言 🌟🌟本期讲解关于TCP/UDP协议的原理理解~~~ 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 🔥 你的点赞就是小编不断更新的最大动力 🎆那么废话不…

centors7安装docker启动ubuntu

在centors上升级glibc为2.18,使用yum最新源直接安装不行,使用源码安装还不行,因为必须使用2.18版本glic,采用先安装docker,在启动新的Ubuntu,在ubuntu里配置自己的环境 1. centors安装docker 查看docker的…

专业学习|马尔可夫链(概念、变体以及例题)

一、马尔可夫链的概念及组成 (一)学习资料分享 来源:024-一张图,但讲懂马尔可夫决策过程_哔哩哔哩_bilibili 马尔可夫链提供了一种建模随机过程的方法,具有广泛的应用。在实际问题中,通过转移概率矩阵及初…

NOIP2023题解

T1:词典 有一个好猜的结论:对于一个字符串,若它当中的最小字符大于等于某其他字符串中的最大字符,那么这个字符串一定不可行。 证明也很简单,若最小字符大于最大字符,显然一定不可行。若最小字符等于最大…

常用Python数据分析开源库:Numpy、Pandas、Matplotlib、Seaborn、Sklearn介绍

文章目录 1. 常用Python数据分析开源库介绍1.1 Numpy1.2 Pandas1.3 Matplotlib1.4 Seaborn1.5 Sklearn 1. 常用Python数据分析开源库介绍 1.1 Numpy Numpy(Numerical Python)是Python数据分析必不可少的第三方库,Numpy的出现一定程度上解决了Python运算性能不佳的…

解决VScode(Visual Studio Code)中的乱码问题. 2024-10-13

系统环境: win10 64bit , vscode 1.94.2 1.乱码原因 默认使用utf-8编码,导致非utf-8内容乱码 2.解决乱码问题 1)打开设置 点击左下角的齿轮,然后再点击设置 2)启用编码自动检测 在设置搜索框中输入 编码 ,然后启用 自动猜测编码选项 3.乱码问题解决 重新打开文件后,乱码问…

清空redo导致oracle故障恢复---惜分飞

客户由于空间不足,使用> redo命令清空了oracle的redo文件 数据库挂掉之后,启动报错 Fri Oct 04 10:32:57 2024 alter database open Beginning crash recovery of 1 threads parallel recovery started with 31 processes Started redo scan Errors in file /home/oracle…

各种查询sql介绍

1. 关联查询(JOIN) 关联查询用于从多个表中检索数据。它基于两个或多个表之间的共同字段(通常是主键和外键)来组合数据。 内连接(INNER JOIN): sql SELECT a.name, b.order_date FROM custome…

IO进程---day5

1、使用有名管道实现两个进程之间的相互通信 //管道文件 #include<myhead.h> int main(int argc, const char *argv[]) {//创建有名管道文件1if(mkfifo("./pipe1",0664)-1){perror("创建管道文件失败");return 0;}if(mkfifo("./pipe2",066…

upload-labs靶场Pass-03

upload-labs靶场Pass-03 分析源码 $is_upload false; $msg null; if (isset($_POST[submit])) {if (file_exists(UPLOAD_PATH)) {$deny_ext array(.asp,.aspx,.php,.jsp);$file_name trim($_FILES[upload_file][name]);$file_name deldot($file_name);//删除文件名末尾的…

Damn-Vulnerable-Drone:一款针对无人机安全研究与分析的靶机工具

关于Damn-Vulnerable-Drone Damn-Vulnerable-Drone是一款针对无人机安全研究与分析的靶机工具&#xff0c;广大研究人员可以利用该环境工具轻松学习、研究和分析针对无人机安全态势。 Damn Vulnerable Drone 基于流行的 ArduPilot/MAVLink 架构&#xff0c;其中故意留下了各种…

PDF 软件如何帮助您编辑、转换和保护文件

如何找到最好的 PDF 编辑器。 无论您是在为您的企业寻找更高效的 PDF 解决方案&#xff0c;还是尝试组织和编辑主文档&#xff0c;PDF 编辑器都可以在一个地方提供您需要的所有工具。市面上有很多 PDF 编辑器 — 在决定哪个最适合您时&#xff0c;请考虑这些因素。 1. 确定您的…

基于 Konva 实现Web PPT 编辑器(三)

完善公式 上一节我们简单讲述了公式的使用&#xff0c;并没有给出完整的样例&#xff0c;下面还是完善下相关步骤&#xff0c;我们是默认支持公式的编辑功能的哈&#xff0c;因此&#xff0c;我们只需要提供必要的符号即可&#xff1a; 符号所表达的含义是 mathlive 的command命…

从0开始深度学习(12)——多层感知机的逐步实现

依然以Fashion-MNIST图像分类数据集为例&#xff0c;手动实现多层感知机和激活函数的编写&#xff0c;大部分代码均在从0开始深度学习&#xff08;9&#xff09;——softmax回归的逐步实现中实现过 1 读取数据 import torch from torchvision import transforms import torchv…

JavaCove部署文档

1. 基础配置 1.1服务器&#xff1a; 2 核 2G 1.2. 一个域名 1.3. 项目地址&#xff1a; gitee:https://gitee.com/guo-_jun/JavaCove github:https://github.com/nansheng1212/JavaCove 2. CentOS 安装 Docker 官方网站上有各种环境下的 安装指南&#xff0c;这里主要介绍…

webpack自定义插件 ChangeScriptSrcPlugin

插件文件 class ChangeScriptSrcPlugin {apply(compiler) {const pluginName "ChangeScriptSrcPlugin";compiler.hooks.compilation.tap(pluginName, (compilation, callback) > {compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(pluginName,(html…