浅谈日常使用的 Docker 底层原理-三大底座

适合的读者,对Docker有过简单了解的朋友,想要进一步了解Docker容器的朋友。

前言

回想我这两年,一直都是在使用 Docker,看过的视频、拜读过的博客,大都是在介绍 Docker 的由来、使用、优点和发展趋势,但对于 Docker 底层到底是如何实现,却是没有提起太多,当然也是我太菜啦,哈哈哈~

便想借本次技术专题的机会,一方面希望能满足自己心底的那份好奇心,另外也想编写一篇关于 Docker 实现原理的文章来让更多的小伙伴知道和了解自己所使用 Docker 底层到底是怎么样的

本文更偏向科普,能不能写好,坦白说,我心里也没底,希望大佬们给点建议,我加油改改

本文大纲:
在这里插入图片描述

那么接下来就进入正文吧。

一、Docker 基本架构图

在这里插入图片描述

图片来源:Docker 官方文档

Docker 采用了 C/S 架构,包括客户端和服务端。Docker 守护进程 (Daemon)作为服务端接受来自客户端的请求,并处理这些请求(创建、运行、分发容器)。

客户端和服务端既可以运行在一个机器上,也可通过 socket 或者 RESTful API 来进行通信。

Docker 守护进程一般在宿主主机后台运行,等待接收来自客户端的消息。

Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker 守护进程交互。

另外这一点,也可以在执行 docker info 时看出来。

关于这个更详细的内容,官网说的更加详细,我就没多写啦。

二、Docker Client 和 Docker Server 如何连接?

docker 底层是通过套接字的方式去连接的。

Docker 守护进程可以通过三种不同类型的 Socket 侦听Docker Engine API :unix, tcp, and fd.

默认情况下,unix域套接字(或 IPC 套接字)在 处创建 /var/run/docker.sock,需要root权限或docker组成员身份。

在这里插入图片描述

  • 补充:linux sock文件是指通过 shell 编程后形成的套接口文件;socket 是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口;在设计模式中,Socket 其实就是一个门面模式,它把复杂的TCP/IP 协议族隐藏在 Socket 接口后面。

如果需要远程访问Docker守护进程,则需要启用tcp Socket。这也是我们实现远程操作Docker的实现方式。

下面我们借助 socat 来直观的感受一下,本机中的 client 和 server 如何连接的吧

sudo apt install socat

补充:什么是socat

socat是一个用于数据转发的命令行工具,它可以在两个端口之间建立虚拟通道,将数据从一个端口转发到另一个端口,同时支持很多网络协议,如常见的 TCP、UDP、HTTP、HTTPS等等。

在此我们就是借助它来进行tcp报文的转发。

socat -v UNIX-LISTEN:/tmp/dockerapi.sock UNIX-CONNECT:/var/run/docker.sock &

1)-v 参数的作用是表示在执行过程中输出详细信息。 -v 选项会让 socat 输出更多的信息,方便调试和监控。

2)UNIX-LISTEN:/tmp/dockerapi.sock: 这部分指定了 socat 要监听的 Unix 域套接字路径。它告诉 socat/tmp/dockerapi.sock 这个路径上监听传入的连接请求。

3)UNIX-CONNECT:/var/run/docker.sock: 这部分指定了 socat 要连接的目标 Unix 域套接字路径。它告诉 socat 要将传入的数据流连接到 /var/run/docker.sock 这个路径上。

4) & : 这个符号将命令放入后台运行.

简单点说就是将从 /tmp/dockerapi.sock 接收到的数据流连接到 /var/run/docker.sock 上。

我们来查看一下是否成功启动监听啦。

    ps -e | grep socat

在这里插入图片描述

docker client 可以通过指定 -H 来指定需要连接的服务端。下面是我们指定为本机的 Server 来进行测试。上面我们已经使用 socat 监听来自unix://tmp/dockerapi.sock 数据输入啦,它会帮我们连接到 /var/run/docker.sock 上去。看结果吧

    docker -H unix://tmp/dockerapi.sock ps

在这里插入图片描述
在这里插入图片描述

不过这个数据没有格式化,有点难看,但还是可以看出它将我本地在运行的容器显示出来啦。

我也尝试了使用 docker client 来管理其他机器的 docker 服务。(需要修改其他机器上的docker服务配置文件,并重启)

在这里插入图片描述

可参考:Docker开放2375端口,实现远程访问

注意:这并不是一个安全的操作,因为并没有加密和验证之类,云服务器请谨慎操作或及时关闭,我是本地虚拟机测试。

开胃小菜结束了,下面的才是有意思的,但是我想通过上面两节小小案例的演示,大家对于 Docker 的客户端和服务端之间的交互应该了解了一些了吧~

三、Docker 核心原理的三大底座

  1. 在容器进程启动之前重新挂载它的整个根目录“/”,用来为容器提供隔离后的执行环境文件系统(rootfs)。
  2. 通过 Liunx Namespace 创建隔离,决定进程能够看到和使用哪些东西。
  3. 通过 control groups 技术来约束进程对资源的使用。

四、Rootfs

详细的请阅读这篇文章:Docker 原理剖析(三)rootfs,这一小节主要内容均来自于此篇文章,作者写的太好啦。

这是我在看这方面博客写的最好的一篇啦,真心建议阅读,文章深度和内容都足够好。


4.1、rootfs 介绍

rootfs 是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在 Linux 操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像。

实际上,同一台机器上的所有容器,都共享宿主机操作系统的内核。所以宿主机操作系统的内核,它对于该机器上的所有容器来说是一个全局变量,牵一发而动全身。

由于 rootfs 的存在,容器才有了一个被反复宣传至今的重要特性:一致性。由于 rootfs 里打包的不只是应用,而是整个操作系统的文件和目录,也就意味着,应用以及它运行所需要的所有依赖,都被封装在了一起。

有了容器镜像“打包操作系统”的能力,这个最基础的依赖环境也终于变成了应用沙盒的一部分。这就赋予了容器所谓的一致性:无论在本地、云端,还是在一台任何地方的机器上,用户只需要解压打包好的容器镜像,那么这个应用运行所需要的完整执行环境就被重现出来了。

在 Docker 架构中,当 Docker daemon 为 Docker 容器挂载 rootfs 时,沿用的 liunx 内核启动时的方法,即将 rootfs 设为只读模式。在挂载完毕之后,利用联合挂载(union mount )技术在已有的只读 rootfs 上再挂载一个读写层。这样,可读写层处于Docker容器文件系统的最顶层,其下可能联合挂载了多个只读层,只有在Docker容器运行过程中文件系统发生变化时,才会把变化的文件内容写到可读写层,并且隐藏只读层的老版本文件

我们可以看一个 Ubuntu 镜像,实际上它是 Ubuntu 操作系统的 rootfs,包含了 Ubuntu 操作系统的所有文件和目录。不过这个 rootfs,由多个层组成,每一个层都是一个增量 rootfs,每一层都是 Ubuntu 操作系统文件与目录的一部分。在使用镜像时,Docker 会把这些增量联合挂载在一个统一的挂载点上,这个挂载点就是 /var/lib/docker/aufs/mnt/。(镜像的层都放置在 /var/lib/docker/aufs/diff 目录下)

4.2、rootfs 组成

rootfs 由三部分组成,由上往下分别是:可读写层,init 层,只读层。

我们以之前使用的 Ubuntu 镜像为例。

在这里插入图片描述

只读层是容器的 rootfs 的下五层,它们的挂载方式都是只读的,可见这些层都以增量的方式分别包含了 Ubuntu 操作系统的一部分。

可读写层是容器的 rootfs 的最上面一层,在没有写入文件之前,这个目录是空的。而一旦在容器里做了写操作,你修改产生的内容就会以增量的方式出现在这个层中。

但是,如果我现在要做的,是删除只读层里的一个文件呢?为了实现这样的删除操作,会在可读写层创建一个 whiteout 文件,把只读层里的文件遮挡起来。比如,你要删除只读层里一个名叫 foo 的文件,那么这个删除操作实际上是在可读写层创建了一个名叫.wh.foo 的文件。

这样,当这两个层被联合挂载之后,foo 文件就会被.wh.foo 文件遮挡起来,消失了。综上所述,最上面这个可读写层的作用,就是专门用来存放你修改 rootfs 后产生的增量,无论是增、删、改,都发生在这里,而原先的只读层里的内容则不会有任何变化。

相当于你做的所有操作都只会影响到读写层,并不会影响到在此之前的只读层,这一层的可读写层也就是我们的容器啦。

Init 层在只读层与可读写层的中间,是 Docker 项目单独生成的一个内部层,专门用来存放 /etc/hosts、/etc/resolv.conf 等信息。

需要这样一层的原因是,这些文件本来属于只读的 Ubuntu 镜像的一部分,但是用户往往需要在启动容器时写入一些指定的值比如 hostname,所以就需要在可读写层对它们进行修改。可是,这些修改往往只对当前的容器有效,我们并不希望执行 docker commit 时,把这些信息连同可读写层一起提交掉。所以,Docker 做法是,在修改了这些文件之后,以一个单独的层挂载了出来。而用户执行 docker commit 只会提交可读写层,所以是不包含这些内容的。

4.3、文件联合系统(UnionFS)

UnionFS 是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。

在这里插入图片描述

Union文件系统是Docker镜像的基础

Unios FS 在 Docker 中的使用大致如下图:
在这里插入图片描述

镜像可以通过分层来进行继承,基于基础镜像。可以制作各种具体的应用镜像。 分层最大的一个优点是共享资源;多个镜像都从相同的base镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像即可;同时内存中也只需要加载一份base镜像,就可以为所有容器服务,而且镜像的每一层都可以被共享。

4.4、Docker 镜像原理

在这里插入图片描述

所以当我们使用用docker run命令启动某个容器时,实际上在镜像的顶部添加了一个新的可写层,而这个新的可写层,被我们称为了容器

容器启动后,其内的应用所有对容器的改动,文件的增删改操作都只会发生在容器层中,对容器层下面的所有只读镜像层没有影响。

这也就是写时复制

五、Linux Namespace

5.1、namespace 是什么?

Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,对其他 namespace 中的进程没有影响。

5.2、namespace 解决了什么问题?

Linux 内核出现 namespace 的一个主要目的就是实现轻量级虚拟化(容器)服务。在同一个 namespace 下的进程可以感知彼此的变化,而对外界的进程一无所知,从而达到隔离的目的。

其实换个说法,Linux 内核所提供的 namespace 技术为 docker 等容器技术的出现和发展提供了基础条件。没有 linux 内核中的 namespace 的出现,可能 docker 容器化技术还不会那么快出现。

5.3、namespace 具体有哪些呢?

1.Mount Namespace 文件系统隔离。隔离了一组进程所看到的文件系统挂载点的集合,在不同的Mount Namespace 的进程所看到的文件是不同的。

2.UTS Namespace 隔离主机和域名信息。隔离了 uname() 系统调用返回的两个系统标识符 nodename 和 domainname. 在容器的上下文中,UTS namespace 允许每个容器拥有自己的hostname 和 UNIX domainname,这对于初始化和配置脚本是十分有用的,这些脚本根据这些名称来定制他们的操作。

3.IPC Namespace 隔离进程间通信。隔离了某些IPC资源(interprocess community,进程间通信)使划分到不同IPC Namespace 的进程组通信上隔离,无法通过消息队列、共享内存、信号量方式通信,这样,只有在同一个Namespace下的进程才能相互通信。如果你熟悉IPC的原理的话,你会知道,IPC需要有一个全局的ID,即然是全局的,那么就意味着我们的Namespace需要对这个ID隔离,不能让别的Namespace的进程看到。 要启动IPC隔离,我们只需要在调用clone时加上CLONE_NEWIPC参数就可以了。 int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWIPC | SIGCHLD, NULL);

4.PID Namespace 进程隔离。隔离了进程ID空间,不同的 PID Namespace 中的进程可以拥有相同的 PID。PID Namespace 的好处之一是,容器可以在主机之间迁移,同时容器内的进程保持相同的进程ID。PID Namespace 空间还允许每个容器拥有自己的 init (PID 1),它是“所有进程的祖先”,负责管理各种系统初始化任务,并在子进程终止时收割孤儿进程。

5.Network Namespace 网络资源隔离。每个 Network Namespace 都有自己的网络设备、IP地址、IP路由表、/proc/net目录、端口号等。

6.User Namespace 用户和用户组隔离。一个进程的用户和组ID在 User Namespace 空间外可以是不同的,一个进程可以在用户命名空间外拥有一个正常的无权限用户 ID,同时在命名空间内拥有一个(root 权限) 的用户ID。

上面说到了一句,要启动IPC隔离,我们只需要在调用clone时加上CLONE_NEWIPC参数就可以了

这主要是因为 Linux 的 namespace 主要是利用下面三个系统调用:

  • clone() – 实现线程的系统调用,用来创建一个新的进程,并可以通过设计上述参数达到隔离。
  • unshare() – 使某进程脱离某个namespace
  • setns() – 把某进程加入到某个namespace

深处我也不会~

参考文章来自于:https://coolshell.cn/articles/17010.html

也是在这里,我才知道 Docker 流行的真的好早好早,而我真的知道 Docker 的时候已经在2020年啦

5.4、通过实践来证明

理论结合实践才能更好的理解这些到底在说什么,我用一个简单的例子来简单阐述一下吧。

    docker run -it busybox /bin/sh

1、我们以交互式的方式进入容器,执行 ls 命令,可以看到常规的 unix 系统目录结构,但这并非是宿主机的文件系统。
在这里插入图片描述

有了文件系统隔离,我们在当前容器内对文件所做的操作并不会影响到外部宿主机的文件,另外我们启动不同的容器,我们所看到的文件系统也是隔离的。

2、隔离主机和域名信息。这点其实很好验证,当执行 hostname 命令时,控制台会返回当前主机名称给我们。

在这里插入图片描述

前者是在容器内部执行,返回的是容器ID,后者是在宿主机的控制台执行,输出的是ubuntu。

3、当我们执行 ifconfig 命令,我们会看到和我们宿主机不同的网卡和网关信息等

在这里插入图片描述

除了上面的方式,我们也可以通过 docker inspect <容器名|容器ID> 来看容器的相关信息,其中也包含了容器网络相关信息。

在这里插入图片描述

在这里插入图片描述

4、进程隔离也是同样如此,我们在宿主机和容器中分别执行 ps -ef | grep sh 命令,看看结果就知道啦

在这里插入图片描述

在容器内明显看不到宿主机其他进程情况,并且容器内的 /bin/sh PID 为1,PID =1 的进程是系统启动时的第一个进程,也称 init 进程。其他的进程,都是由它管理产生的。而此时,PID=1 却是 /bin/sh 进程。

而它在宿主机上所展示时,它的PID变成了 2456。

这一点也可以换成下面这条命令来准确定位

    docker inspect -f '{{.State.Pid}}' <容器名称或ID> # 查看容器的PID

这个结论就非常好说了,在容器中,它确确实实是完成了 PID 的隔离,明明宿主机上是 2456 的进程,变成了容器内的 1 号进程,同时在容器中还看不到宿主机其他进程。

5.5、Docker 中的 User Namespace 详解

Docker 中引入的 user namespace 可以让容器中有一个 “假”的 root 用户,它在容器内是 root,在容器外是一个非 root 用户。也就是 user namespace 实现了 host user 和 container user 之间的映射。

我们拿一个简单的例子来说明:

    docker run -it -v /bin:/host/bin busybox /bin/sh

先来解释下这条命令,现在是 dj(uid=1000,gid=1000)的用户,将本机上的 /bin 目录,挂载到容器中 /host/bin 目录下啦,并以交互式的方式启动了容器 busybox ,进入到容器内部。

那么现在有个问题:我在容器中的 /host/bin 目录下可以修改文件或者增加文件吗? 见下图。

在这里插入图片描述

答案是可以的。为什么呢?我一个非root用户,为什么可以操作root权限的文件呢?

原因:Docker容器运行的时候,如果没有专门指定user, 默认以root用户运行。它并不是说按照你现在的登录的用户去分配权限的,而是没有指定就默认使用root用户运行。

另外有没有觉得这是非常恐怖的一件事情,我明明没有 root 权限,却突然之间通过 docker 给容器挂载一个文件目录,虽然我一下没想起来可以做什么,但还是有点恐怖的哈。


你看到这里也许会觉得有些疑惑,为什么和此小节说的第一段话是自相矛盾的呢?

因为在 Docker中默认并没有开启 user namespace,这并不是说 Linux 机器没有支持 user namespace ,而是 docker 中没有开启。

在说如何让 Docker 启用 user namespace 之前,我们先用另一种方式来曲线救国一下。

我之前使用 id 命令, 看到了我当前用户 dj 的(uid=1001),我们在执行 docker run 记得指定一下即可。

上面的命令改为:

    docker run -it  -u 1001:1001 -v /bin:/host/bin busybox /bin/sh

我们使用了 -u 1001:1001 来指定了容器内所使用的用户。我们再重复一下上面的操作。

在这里插入图片描述

显示权限不足啦。

5.6、如何让 Docker启用 User namespace 呢?

1、备份 docker 配置文件

在这里插入图片描述

因为我之前没有配置文件,所以我直接新建了一个文件

2、修改 docker 配置文件

添加 User Namespace 配置: 在配置文件中添加以下内容以启用 User Namespace。这将告诉 Docker 守护进程使用 User Namespace 功能。

    {"userns-remap": "default"}

3、保存文件,重启启动 Docker 服务,以使配置文件生效

    sudo systemctl restart docker

4、验证配置

    cat /etc/subuidcat /etc/subgid

在这里插入图片描述

dockermap 是默认的映射名称。

补充/etc/subuid 是一个系统配置文件,用于管理用户命名空间中用户的子用户标识(sub-IDs)。不多占篇幅介绍了,/etc/subgid 相应就是用户组的标识。具体感兴趣可以去了解。

现在我们再执行上面之前测试的命令。

    docker run -it -v /bin:/host/bin busybox /bin/sh

在这里插入图片描述

我们还是使用 dj 这个用户,但是它已经没有权限修改从宿主机 /bin 映射到容器中的/host/bin

的目录了。

并且使用 id 命令,可以看到容器内部是 root 用户,但实际上它在容器外并不是root 用户。

另外还可以查找容器的PID(进程号),通过容器的进程号,来查看它的命名空间。

    docker inspect -f '{{.State.Pid}}' <容器名称或ID> # 查看容器的PID

在这里插入图片描述

查看进程命名空间:

    cat /proc/${容器PID}/uid_map

在这里插入图片描述

/proc/5517/uid_map 它表示了容器内外用户的映射关系即将host 上的 231072 用户映射为容器内的 0 即 root 用户。

这说明通过使用 user namespace 使得容器内的进程运行在非 root 用户上,我们成功地限制了容器内进程的权限

5.7、Docker 为什么不默认启用 User namespace呢?

编写这一小章节的时候,我原打算去找资料啦,因为我已经猜测到一些原因,但需要验证一下,但是看到还没关闭的 GPT窗口,就打算拿它试一下。答案如下:

在这里插入图片描述

结论也很容易得出,Docker 希望降低复杂性,获取更强的兼容性,降低故障排查难度,也希望降低普通开发人员的使用门槛,更好的推广。

5.8、Namespace 存在的问题

我们都知道 Namespace 的隔离是轻量化的,比起虚拟化的隔离,它的缺陷也很明显,就是无法进行彻底的隔离

因为不管如何隔离,它都是依赖于同一个内核的,那么此时内核就成了所有容器的共享变量,改动了一次,就会影响到全部。

5.9、检查 linux 操作系统是否启用了 namespace

运行下面的命令即可检查是否启用了:

    root@ubuntu:/home# uname -aLinux ubuntu 5.15.0-78-generic #85~20.04.1-Ubuntu SMP Mon Jul 17 09:42:39 UTC 2023 x86_64 x86_64 x86_64 GNU/Linuxroot@ubuntu:/home# cat /boot/config-5.15.0-7config-5.15.0-76-generic  config-5.15.0-78-generic  root@ubuntu:/home# cat /boot/config-5.15.0-78-generic | grep CONFIG_USER_NSCONFIG_USER_NS=yroot@ubuntu:/home#

如果是 「y」,则启用了,否则未启用。同样地,可以查看其它 namespace:

    CONFIG_UTS_NS=yCONFIG_IPC_NS=yCONFIG_USER_NS=yCONFIG_PID_NS=yCONFIG_NET_NS=y

六、Linux Control Cgroups

无论 Docker 如何进行隔离,无法否认的是我们在当前宿主机中运行的所有容器,它依赖的硬件资源都只是当前机器。

另外在上文中我们也谈到,其实启动的每一个容器进程,它本身其实就是当前宿主机的进程之一,那么本质上来说,它也会和宿主机中的其他进程进行资源的竞争。

6.1、Control Cgroups

所以我们就要针对Docker运行的容器进行资源的限制,Cgroups 就是 Linux 内核中用来为进程设置资源的一个技术。

Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。

还可以对进程进行优先级设置,审计,挂起和恢复等操作。

Linxu中为了方便用户使用cgroups,已经把其实现成了文件系统,其目录在/sys/fs/cgroup下,在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是我这台机器当前可以被 Cgroups 进行限制的资源种类。Cgroups 的每一个子系统都有其独有的资源限制能力,比如:

cpu:限制进程在一段时间内能够分配到的 CPU 时间 blkio:为块设备设定 I/O 限制,一般用于磁盘等设备 cpuset:为进程分配单独的 CPU 核和对应的内存节点 memory:为进程设定内存使用的限制

完整子系统如下图:

在这里插入图片描述

补充:当然这里面还牵扯到许多其他的问题,比如是如何实现的,资源如何分配等等,我也不会啦。

我们可以把 Linux Cgroups 理解成一个子系统目录加上一组资源限制文件的组合。而对于 Docker 等 Linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的 PID 填写到对应控制组的 tasks 文件中就可以了。而至于在这些控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定了。

6.2、Cgroups 存在的问题

跟 Namespace 的情况类似,Cgroups 对资源的限制能力也有很多不完善的地方,被提及最多的自然是 /proc 文件系统的问题。

我们知道,Linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。

在这里插入图片描述

但是,你如果在容器里执行 top 指令,就会发现,它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据。

在这里插入图片描述

我在容器中执行 free 命令,展示的是我宿主机的相关信息。

造成这个问题的原因就是,/proc 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,即: /proc 文件系统不了解 Cgroups 限制的存在

最后

写到这里的时候,看着好像是写完了,但其实还只是浅浅的开了个端罢了,很多想写,能力上知识面上都有所欠缺,还在加油学,希望能一起交流和学习~

在写相关内容的时候,拜读了许多大佬写的文章,同时也借鉴和整合多位大佬的文章内容,真的是知道的越多,也就是知道的越少。

以往认为对 Linux 已经有所了解,但到要一探究竟的时候,就纯纯一小白了,也是因为这次偶然的对 Docker 的好奇,让我对 Linux 有了更深刻的了解。

好奇永远都是探究式学习的动力之一

~

参考文章

https://moelove.info/2021/11/17/一篇搞懂容器技术的基石-cgroup/#contents:cgroup-的核心文件—张晋涛

https://www.cnblogs.com/rexcheny/p/11017146.html 重点参考

https://developer.aliyun.com/article/377862 Linux user namespace 重点参考

https://developer.aliyun.com/article/377862 非常优秀,给了很多思路。

https://www.cnblogs.com/michael9/p/13039700.html#容器的文件系统容器镜像—rootfs

https://zhuanlan.zhihu.com/p/445258335

https://www.liaoxuefeng.com/article/1481991528644643

https://blog.csdn.net/Yosigo_/article/details/119124013

https://blog.csdn.net/qq_43380180/article/details/125953218

https://www.bilibili.com/video/BV163411G7vb/?spm_id_from=333.999.0.0&vd_source=f9d1f15d0ed8efc261af664b960ef668

https://zhuanlan.zhihu.com/p/392508816 rootfs 文件系统

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

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

相关文章

VMWare Workstation 17 Pro 网络设置 桥接模式 网络地址转换(NAT)模式 仅主机模式

文章目录 网络模式配网要求CentOSDHCP虚拟网络桥接模式默认配置测试手动配置测试 网络地址转发模式 (NAT)还原配置虚拟网络配置默认配置测试手动配置测试 仅主机模式 网络模式 桥接模式: 主机与虚拟机对等, 虚拟机注册到主机所在的局域网, 会占用该网络的IP该局域网内的所有机…

简单认识镜像底层原理详解和基于Docker file创建镜像

文章目录 一、镜像底层原理1.联合文件系统(UnionFS)2.镜像加载原理3.为什么Docker里的centos的大小才200M? 二、Dockerfile1.简介2.Dockerfile操作常用命令 三、创建Docker镜像1.基于已有镜像创建2.基于本地模板创建3.基于Dockerfile创建4.Dockerfile多阶段构建镜像 一、镜像底…

产品经理如何提高用户画像效果?SIKT模型

产品经理做用户画像&#xff0c;最担心被业务方反馈&#xff1a;没效果。这往往是由用户画像与业务场景脱节造成的。那么我们该如何从业务场景出发&#xff0c;让用户画像更有效&#xff1f;一般来说&#xff0c;我们可以采用SIKT模型解决这个问题。 用户画像 ​ 1、SIK…

【操作系统】虚拟内存相关分段分页页面置换算法

虚拟内存是什么&#xff1f; 【进程地址空间虚拟地址空间C/C程序地址空间就是那个4G的空间】 虚拟内存是操作系统内核为了对进程地址空间进行管理&#xff0c;而设计的一个逻辑意义上的内存空间概念。在程序运行过程中&#xff0c;虚拟内存中需要被访问的部分会被映射到物理内…

漏洞指北-VluFocus靶场专栏-工具篇

漏洞指北-VluFocus靶场专栏-番外篇奇技淫巧 &#x1f338;1、burp suite 、中国蚁剑工具、Strut2扫描软件地址&#x1f338;&#x1f338;2、burp suite使用&#x1f338;step1 浏览器开启代理&#xff0c;**推荐使用&#xff1a;SwitchyOmega** step2 确认浏览器端口和burp su…

nginx反向代理、负载均衡

修改nginx.conf的配置 upstream nginx_boot{# 30s内检查心跳发送两次包&#xff0c;未回复就代表该机器宕机&#xff0c;请求分发权重比为1:2server 192.168.87.143 weight100 max_fails2 fail_timeout30s; server 192.168.87.1 weight200 max_fails2 fail_timeout30s;# 这里的…

LVS负载均衡群集部署(LVS-NAT模型实例)

一、集群 1.1集群的含义 Cluster&#xff0c;集群、群集,为解决某个特定问题将多台计算机组合起来形成的单个系统。 由多台主机构成&#xff0c;但对外只表现为一个整体。 1.2群集的三种类型 1.2.1负载均衡群集 LB&#xff1a; Load Balancing&#xff0c;负载均衡&#x…

Linux 虚拟机Ubuntu22.04版本通过远程连接连接不上,输入ifconfig只能看到127.0.0.1的解决办法

之前给虚拟机配置静态IP之后&#xff0c;可以直接通过主机Vscode远程连接。但是前一段时间把主机的TCP/IPV4静态IP设置了一下之后&#xff0c;再连接虚拟机就连不上了&#xff0c;于是参考解决虚拟机不能上网ifconfig只显示127.0.0.1的问题&#xff0c;又可以连接上了&#xff…

Linux系统下消息中间件RocketMQ下载、安装、搭建、配置、控制台rocketmq-dashboard的安装保姆级教程 rocketmq ui

这里给出我使用的 RocketMQ 版本&#xff08;5.1.3&#xff09;、RocketMQ-Dashboard 版本的百度网盘链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1HaKBBDGWZ0WKLGgVwIG9pw 提取码&#xff1a;1234 文章目录 一. 官网下载安装二、启动NameServer三、启动Broker四…

Qt项目报错:Cannot run compiler ‘clang++‘. /bin/sh: 1: clang++: not found

在一台旧电脑上装了深度系统&#xff0c;装了Qt&#xff0c;导入项目&#xff0c; build提示 clang找不到&#xff1a; Project ERROR: Cannot run compiler clang. Output: /bin/sh: 1: clang: not found Maybe you forgot to setup the environment? Error while parsing …

Jenkins+Jmeter集成自动化接口测试并通过邮件发送测试报告

一、Jenkins的配置 1、新增一个自由风格的项目 2、构建->选择Excute Windows batch command&#xff08;因为我是在本地尝试的&#xff0c;因此选择的windows&#xff09; 3、输入步骤&#xff1a; 1. 由于不能拥有相同的jtl文件&#xff0c;因此在每次构建前都需要删除jtl…

VS2022远程Linux使用cmake开发c++工程配置方法

文章目录 远程连接CMakePresets.json的配置Task.vs.json配置launch.vs.json配置最近使用别人在VS2015上使用visualgdb搭建的linux开发环境,各种不顺手,一会代码不能调转了,一会行号没了,调试的时候断不到正确的位置,取消的断点仍然会进。因此重新摸索了一套使用vs的远程开…

基于Python的高校学生成绩分析系统

随着计算机技术发展&#xff0c;计算机系统的应用已延伸到社会的各个领域&#xff0c;大量基于网络的广泛应用给生活带来了十分的便利。所以把高校成绩分析与现在网络相结合&#xff0c;利用计算机搭建高校成绩分析系统&#xff0c;实现高校成绩分析的信息化。则对于进一步提高…

深入理解 Flutter 图片加载原理 | 京东云技术团队

前言 随着Flutter稳定版本逐步迭代更新&#xff0c;京东APP内部的Flutter业务也日益增多&#xff0c;Flutter开发为我们提供了高效的开发环境、优秀的跨平台适配、丰富的功能组件及动画、接近原生的交互体验&#xff0c;但随之也带来了一些OOM问题&#xff0c;通过线上监控信息…

ubuntu 编译安装nginx及安装nginx_upstream_check_module模块

如果有帮助到你&#xff0c;麻烦点个赞呗&#xff5e; 一、下载安装包 # 下载nginx_upstream_check_module模块 wget https://codeload.github.com/yaoweibin/nginx_upstream_check_module/zip/master# 解压 unzip master# 下载nginx 1.21.6 wget https://github.com/nginx/…

【C++奇遇记】构造函数 | 初始化列表

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 数据库专栏 初阶数据结构 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如…

操作系统练习:在Linux上创建进程,及查看进程状态

说明 进程在执行过程中可以创建多个新的进程。创建进程称为“父进程”&#xff0c;新的进程称为“子进程”。每个新的进程可以再创建其他进程&#xff0c;从而形成进程树。 每个进程都有一个唯一的进程标识符&#xff08;process identifier&#xff0c;pid&#xff09;。在L…

Java之接口

作者简介&#xff1a; zoro-1&#xff0c;目前大一&#xff0c;正在学习Java&#xff0c;数据结构等 作者主页&#xff1a; zoro-1的主页 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f496; Java之接口 接口的概念语法规则接口特性接口使用案…

数据结构<树和二叉树>顺序表存储二叉树实现堆排

✨Blog&#xff1a;&#x1f970;不会敲代码的小张:)&#x1f970; &#x1f251;推荐专栏&#xff1a;C语言&#x1f92a;、Cpp&#x1f636;‍&#x1f32b;️、数据结构初阶&#x1f480; &#x1f4bd;座右铭&#xff1a;“記住&#xff0c;每一天都是一個新的開始&#x1…

stable diffusion基础

整合包下载&#xff1a;秋叶大佬 【AI绘画8月最新】Stable Diffusion整合包v4.2发布&#xff01; 参照&#xff1a;基础04】目前全网最贴心的Lora基础知识教程&#xff01; VAE 作用&#xff1a;滤镜微调 VAE下载地址&#xff1a;C站&#xff08;https://civitai.com/models…