docker 容器原理分析笔记(下)

news2025/1/19 8:03:33

目录

chroot

rootfs

Volume(数据卷)

打包一个go镜像

总结


chroot

当一个容器被创建的时候,我们希望容器中进程看到的文件是一个独立的隔离环境,我们可以在容器进程重启之前挂载整个根目录 /,由于 Mount Namespace 的存在,这个挂载对宿主机不可见,所以容器进程就可以在里面随便折腾了。

在 Linux 中可以使用 chroot 来改变某进程的根目录。

来看下 chroot

chroot 主要是用来改换根目录的,在新设定的虚拟根目录中运行指定的命令或交互 Shell。一个运行在这个环境下,经由 chroot 设置根目录的程序,它不能够对这个指定根目录之外的文件进行访问动作,不能读取,也不能更改它的内容。

rootfs

为了让容器这个根目录看起来更'真实',一般会在容器的根目录下面挂载一个完整的操作系统的文件系统,比如 Ubuntu16.04 的 ISO。这样,在容器启动之后,我们在容器里通过执行 ls / 查看根目录下的内容,就是 Ubuntu 16.04 的所有目录和文件。

这个挂载到容器根目录,用来给容器提供隔离后的执行环境的文件系统,称为为'容器镜像',或者 rootfs(根文件系统)。

对于 Docker 来讲,最核心的原理就是为待创建的用户进程执行下面三个操作:

1、启用 Linux Namespace 配置;

2、设置指定的 Cgroups 参数;

3、切换进程的根目录(Change Root)。

第三步,进程根目录的切换,Docker 会优先使用 pivot_root 系统调用,如果系统不支持,才会使用 chroot。

rootfs 是一个操作系统包含的所有的文件、配置和目录,并不包括操作系统内核。同一宿主机中的容器都共享主机操作系统的内核。

正是由于 rootfs 的存在,容器中的一个很重要的特性才能实现,一致性。

因为 rootfs 中打包的不止是应用,还包括整个操作系统的文件和目录,应用和应用运行的所有依赖都会被封装在一起。这样无在任何一台机器中,只需要解压打包好的镜像,直接运行即可,因为镜像里面已经包含了应用运行的所有环境。

对于基础 rootfs 的制作,如果后续有更改的需求,一个很简单的操作就是,新 fork 一个然后修改,这样的缺点就是有很多碎片化的版本。

rootfs 的制作,也是支持增量的方式进行操作的,Docker 在镜像的设计中,引入了层(layer)的概念。也就是说,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量 rootfs。

 

上面的读写层也称为容器层,下面的只读称为镜像层,所有的增删查改都只会作用在容器层,相同的文件上层会覆盖下层。

上面的读写层,在没有文件写入之前里面是空的,如果在容器里面做了修改,修改的内容就会以增量的方式出现在这个层中。

例如进行文件的修改,首先会从上到下查找有没有这个文件,找到,就复制到容器层中,修改,对容器来讲可以看到容器层中的这个文件,看不到镜像层中的这个文件。

进行删除的时候,也是在读写层做个标记,当这两个层被联合挂载之后,读写层的文件删除标记,会把容器中对应的文件“遮挡”起,对外面展示的效果就是该文件找不到了,被删除了。

最上面的可读可写层,就是专门存放修改后 rootfs 后产生的增量,修改,新增,删除产生的文件都会被记录到这里。这就是 rootfs 制作能支持增量模式的最主要实现。

这些增量的 rootfs,还可以使用 docker commit 和 push 指令,保存这个被修改过的可读写层,并上传到 Docker Hub 上。同时,原先只读层中的内容不会发生任何变化。当然这些读写层的增量 rootfs 在 commit 之后就会变成一个新的只读层了。

Volume(数据卷)

Volume 机制,允许将宿主机中指定的目录或者文件,挂载到容器中进行取和修改操作。

Volume 有两种挂载方式

$ docker run -v /test ...
$ docker run -v /home:/test ...

两种挂载方式实质上是一样的,第一种,没有指定挂载的宿主机的目录,docker 就会默认在宿主机上创建一个临时目录 /var/lib/docker/volumes/[VOLUME_ID]/_data,然后把它挂载到容器的 /test 目录上。

第二种,指定了宿主机中的目录,docker 就会把指定的宿主机中的 /home 目录挂载到容器的 /test 目录上。

docker 中使用了 rootfs 机制和 Mount Namespace,构建出了一个同宿主机完全隔离开的文件系统环境。对于 Volume 挂载又是如何实现的呢?这里来具体的分析下。

当容器进程被创建之后,尽管开启了 Mount Namespace,但是在它执行 chroot(或者 pivot_root)之前,容器进程一直可以看到宿主机上的整个文件系统。

所以只需要在 rootfs 准备好之后,在执行 chroot 之前,把 Volume 指定的宿主机目录挂载到容器中的目录上即可,这样 Volume 挂载工作就完成了。

在执行这个挂载操作时,“容器进程”已经创建了,也就意味着此时 Mount Namespace 已经开启了。所以,这个挂载事件只在这个容器里可见。你在宿主机上,是看不见容器内部的这个挂载点的。这就保证了容器的隔离性不会被 Volume 打破。

这里用到了 Linux 的绑定挂载(bind mount)机制,它的主要作用就是,允许你将一个目录或者文件,而不是整个设备,挂载到一个指定的目录上。并且,这时你在该挂载点上进行的任何操作,只是发生在被挂载的目录或者文件上,而原挂载点的内容则会被隐藏起来且不受影响。

绑定挂载实际上是一个 inode 替换的过程,在 Linux 操作系统中,inode 可以理解为存放文件内容的"对象",dentry 也叫目录项,就是访问 inode 所有的指针。

 

上面图片的栗子

mount --bind /home /test,会将 /home 挂载到 /test 上。其实相当于将 /test 的 dentry,重定向到了 /home 的 inode。这样当我们修改 /test 目录时,实际修改的是 /home 目录的 inode。

如果执行 umount 命令,解除绑定,/test 文件中的内容就会恢复,因为修改发生的目录是在 /home 中。

同样如果对这个镜像执行 commit 操作,docker 容器 Volume 里的信息也是不会被提交的,但是这个挂载点的 /test 空目录会被提交。

打包一个go镜像

了解了 docker 的基本原理,这里来构建一个简单的 docker 镜像

首先一个简单的 go 服务

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/hello", sayHello)

	log.Println("【默认项目】服务启动成功 监听端口 80")
	er := http.ListenAndServe("0.0.0.0:80", nil)
	if er != nil {
		log.Fatal("ListenAndServe: ", er)
	}
}

func sayHello(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	log.Println("request hello")
	data := map[string]interface{}{
		"status":  "ok",
		"message": "hello",
	}

	json.NewEncoder(w).Encode(&data)
}

交叉编译

export CGO_ENABLED=0
export GOOS=linux
export GOARCH=amd64

go build  -o go-server .

编写 Dockerfile 文件

# 基础镜像
FROM alpine

# Dockerfile 后面的操作都以这一句指定的 /app 目录作为当前目录
WORKDIR /app

# 将编译好的go程序,复制到 app 目录下  
COPY ./go-server ./app

# 允许外接访问的端口
EXPOSE 80

CMD  ["/app/go-server"]

Dockerfile 中的命令都是按照顺序执行的。

最后使用 CMD 来启动 go 应用,在 Dockerfile 中除了 CMD 还可以使用 ENTRYPOINT 来执行一些容器中的命令操作。

默认情况下,Docker 会为你提供一个隐含的 ENTRYPOINT,即:/bin/sh -c。所以,在不指定 ENTRYPOINT 时,比如在我们这个例子里,实际上运行在容器里的完整进程是:/bin/sh -c “/app/go-server”,即 CMD 的内容就是 ENTRYPOINT 的参数。

总结

1、对于 Docker 来讲,最核心的原理就是为待创建的用户进程执行下面三个操作:

  • 1、启用 Linux Namespace 配置;

  • 2、设置指定的 Cgroups 参数;

  • 3、切换进程的根目录(Change Root)。

2、Docker 容器启动的进程还是在宿主机中运行的,和宿主机中其他运行的进程是没有区别的,只是 docker 容器会给这些进程,添加各种各样的 Namespace 参数,使这些进程和宿主机中的其它进程隔离开来,感知不到有其它进程的存在;

3、Docker 通过 Namespace 可以这些进程只能看到自己 Namespace 的相关资源,这样和其它 Namespace 的进程起到了隔离的作用,使得这些在容器中运行的进程像是运行在一个独立的环境中一样;

4、Docker 使用 Linux cgroups 来限制容器中的进程允许使用的系统资源,防止这些进程可能会占用很多的系统资源,影响到其他的进程;

5、Mount namespace 为进程提供独立的文件系统视图。简单点说就是,mount namespace 用来隔离文件系统的挂载点,这样进程就只能看到自己的 mount namespace 中的文件系统挂载点;

6、当一个容器被创建的时候,我们希望容器中进程看到的文件是一个独立的隔离环境,为了让容器这个根目录看起来更'真实',一般会在容器的根目录下面挂载一个完整的操作系统的文件系统,比如 Ubuntu16.04 的 ISO。这样,在容器启动之后,我们在容器里通过执行 ls / 查看根目录下的内容,就是 Ubuntu 16.04 的所有目录和文件;

7、rootfs 是一个操作系统包含的所有的文件、配置和目录,并不包括操作系统内核。同一宿主机中的容器都共享主机操作系统的内核;

8、正是由于 rootfs 的存在,容器中的一个很重要的特性才能实现,一致性;

9、对于基础 rootfs 的制作,如果后续有更改的需求,一个很简单的操作就是,新 fork 一个然后修改,这样的缺点就是有很多碎片化的版本。rootfs 的制作,也是支持增量的方式进行操作的,Docker 在镜像的设计中,引入了层(layer)的概念。也就是说,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量 rootfs。

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

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

相关文章

发布 .NET MAUI / MAUI Blazor 应用 (1) - Windows

发布用于Windows的 .NET MAUI 应用 打开 PowerShell 终端 , 命令行进入工程目录,以我的例子工程为例, cd BlazorMaui BlazorMaui 替换为你自己工程名字 New-SelfSignedCertificate -Type Custom -Subject "CNBlazorMaui" -KeyUsage DigitalSignature -FriendlyName &…

python如何将日期字符串格式化年月日

今天用Python的DataFrame处理数据时,相对一波数据按日期分组处理,但是原始数据包含时间分秒,无法按日期分组,因此需要先将数据转成只包含年月日的数据格式。但是写代码处理过程中发现有点绕,不熟悉的同学容易绕晕。这种…

编程语言如何推动DeFi成为主流?

随着DeFi的快速增长,提供DeFi服务的平台和产品也如雨后春笋般纷纷冒头。作为衡量DeFi协议管理资金规模的标准之一,DeFi“总锁仓量”在过去两年一路从100亿美元增长到超400亿美元,期间更是一度冲上1800亿美元的巅峰。但直到今天,智…

Python爬虫request模块的get、post方法应用

目录 post方法使用 一、确定爬取网站的数据 二、分析数据类型和相应类型 三、使用requetst模块方法进行爬取 四、源代码分享 get的方法使用 一、分析抓取网站操作 二、参数的分析和组成 三、使用get模块方法进行爬取结果 四、源代码分享 思考和总结 参考网站 爬虫是…

MySQL---触发器详解

目录 一、触发器的介绍 二、触发器的语法 (1)insert触发器 (2)update触发器 (3)delete触发器 一、触发器的介绍 触发器是与表有关的数据库对象,指在insert/update/delete 之前或之后&…

4-UI自动化-selenium三大等待操作

4-UI自动化-selenium三大等待方式selenium三大等待方式强制等待timd.sleep隐式等待implicitly_wait显式等待WebDriverWait显式等待和隐式等待的区别上篇介绍了3-UI自动化-八大元素定位,xpath定位方式和相关的常问面试题 本篇来学习三大等待方式 ♡\color{red}{\hear…

如何用蓝牙实现无线定位(一)--系统原理

1. 简介 本项目将利用多个BLE4.0蓝牙模块,配合主控板、OLED显示屏等,构建一个无线定位系统。 本项目的系统构成为:3个信号塔,1个中控台,2个被定位的目标。 无线定位的用途有很多。比如,我们可以把固定的目…

zabbix拓扑图和聚合图形

目录 一、环境准备 1、搭建zabbix基础环境 2、创建被监控主机 二、拓扑图 1、拓扑图作用 2、拓扑图绘制步骤 三、聚合图形 1、聚合图形的作用 2、创建聚合图形 一、环境准备 1、搭建zabbix基础环境 zabbix基础环境部署参照:zabbix基础环境部署_桂安俊kyli…

方格取数 (两条路径,使得取得的数字和为最大)

设有 NN 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字0。如下图所示: 某人从图中的左上角 A 出发,可以向下行走,也可以向右行走,直到到达右下角的 B 点。 在走过的路上&#xff0…

Vue中的组件生命周期

一个组件从创建到销毁的过程 成为生命周期。 在我们使用Vue3 组合式API 是没有 beforeCreate 和 created 这两个生命周期的 组件生命周期如下: onBeforeMount() 在组件DOM实际渲染安装之前调用。在这一步中,根元素还不存在。onMounted() 在组件的第一次…

【手把手】教你玩转SpringCloud Alibaba之Sentinel整合GateWay

1、网关流控介绍 在微服务系统中,网关提供了微服务系统的统一入口,所以在做限流的时候,肯定是要在网关层面做一个流量的控制,Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。 Sentinel 1.6.0 引入…

R语言隐马尔可夫模型HMM识别不断变化的市场条件

了解不同的市场状况如何影响您的策略表现可能会对您的收益产生巨大的影响。最近我们被客户要求撰写关于隐马尔可夫模型的研究报告,包括一些图形和统计输出。 某些策略在波动剧烈的市场中表现良好,而其他策略则需要强劲而平稳的趋势,否则将面…

【PdgCntEditor】解决PDF的目录页码和PDF实际页码不一致的问题,书签页码偏移页面偏移功能,PDF页面标签的添加

一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码,两者之间存在一定的偏移值;导致我们看目录后面的页码,并不能直接借此数字索引到对应页面,非常麻烦。 二、改变页码标签 这是第一种方法&…

电脑技巧:Win10粘贴文件到C盘提示没有权限的解决方法

❤️作者主页:IT技术分享社区 ❤️作者简介:大家好,我是IT技术分享社区的博主,从事C#、Java开发九年,对数据库、C#、Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉: 数据库领域优质创作者🏆&#x…

VMware升级手册

1. 概述 1.1 实施范围 本次实施涉及上海SMVIC虚拟化平台的7台物理服务器、7台ESXI节点、一台VC(6.7升级到7.0),以及广德、如皋两个集群迁移到7.0VC。 1.2 实施内容 本项目中需要实施内容包括: 2. 前置准备 升级确认: 3. WBS 4. 实施过程 4.1 VC部署 运行安装包,点击…

R语言生存分析数据分析可视化案例

目标 本文的目的是对如何在R中进行生存分析进行简短而全面的评估。关于该主题的文献很广泛,仅涉及有限数量的(常见)问题。最近我们被客户要求撰写关于生存分析的研究报告,包括一些图形和统计输出。 可用的R包数量反映了对该主题的…

SpringBoot 配置文件这样加密,才足够安全!

1. 前景 在使用Springboot时,通常很多信息都是在application.yml中直接明文配置的,比如数据库链接信息,redis链接信息等等。但是这样是不安全的。 所以需要对敏感数据进行加密,这样防止密码泄露 Jasypt这个库为我们解决了这个问…

[附源码]计算机毕业设计springboot-大学生健康档案管理

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

初识Pytest自动化测试框架,我彻底懂了

初识Pytest Pytest是Python实现的一个测试工具,可以用于所有类型和级别的软件测试。 Pytest是一个可以自动查找到你编写的用例并运行后输出结果的测试框架。 Pytest的特点: 是一个命令行工具,编写用例简单,可读性强非常容易上手…

2023年高企申报准备工作,明光市企业可以提前做这些准备

为了帮助企业提前准备和更好地开展2023年高新技术企业认定申报工作,安徽省大力鼓励企业申报高新技术企业,相应出台了相关政策,同时对于高企申报也有很多奖补,下面小编汇总了滁州市2023年申报,企业提前准备工作有哪些。…