《Docker进阶与实战》——3.4节Docker image扩展知识

简介:

本节书摘来自华章社区《Docker进阶与实战》一书中的第3章,第3.4节Docker image扩展知识,作者华为Docker实践小组,更多章节内容可以访问云栖社区“华章社区”公众号查看

3.4 Docker image扩展知识
Cgroup和Namespace等容器相关技术已经存在很久,在VPS、PaaS等领域也有很广泛的应用,但是直到Docker的出现才真正把这些技术带入到大众的视野。同样,Docker的出现才让我们发现原来可以这样管理镜像,可以这样糅合老技术以适应新的需求。Docker引入联合挂载技术(Union mount)使镜像分层成为可能;而Git式的管理方式,使基础镜像的重用成为可能。现在就了解一下相关的技术吧。

3.4.1 联合挂载
联合文件系统这种思想由来已久,这类文件系统会把多个目录(可能对应不同的文件系统)挂载到同一个目录,对外呈现这些目录的联合。1993年Werner Almsberger实现的“Inheriting File System”可以看作是一个开端。但是该项目最终废弃了,而后其他开发者又为Linux社区贡献了unionfs(2003年)、 aufs(2006年) 和Union mounts(2004年),但都因种种原因未合入社区。直到OverlayFS在2014年合入Linux主线,才结束了Linux主线中无联合文件系统的历史。
这种联合文件系统早期是用在LiveCD领域。在一些发行版中我们可以使用LiveCD快速地引导一个系统去初始化或检测磁盘等硬件资源。之所以速度很快,是因为我们不需要把CD中的信息拷贝到磁盘或内存等可读可写的介质中。而只需把CD只读挂载到特定目录,然后在其上附加一层可读可写的文件层,任何导致文件变动的修改都会被添加到新的文件层内。这就是写时复制(copy-on-write)的概念。

3.4.2 写时复制
写时复制是Docker image之所以如此强大的一个重要原因。写时复制在操作系统领域有很广泛的应用,fork就是一个经典的例子。当父进程fork子进程时,内核并没有为子进程分配内存(当然基本的进程控制块、堆栈还是需要的),而是让父子进程共享内存。当两者之一修改共享内存时,会触发一次缺页异常导致真正的内存分配。这样做既加速了子进程的创建速度,又减少了内存的消耗(如图3-4所示)。


1c37934e48f55bf5ebf896a4d10e3ff2da4fc56a

Docker image使用写时复制也是为了达到相同目的:快和节省空间。我们以内核主线中的OverlayFS作为例子介绍一下写时复制。
OverlayFS会把一个“上层”的目录和“下层”的目录组合在一起:“上层”目录和“下层”目录或者组合,或者覆盖,或者一块呈现。当然“下层”目录也可以是联合文件系统的挂载点。
首先你需要有支持OverlayFS 的Linux环境(内核3.18以上)。Ubuntu用户可以从Ubuntu维护的kernel版本中下载最新的内核安装包(比如vivid版本)。当然也可以手工编译新版的kernel,但这不是本文的重点,所以暂不细说。下面的测试为了突出变化,删除了无用的文件。

$ cat /proc/filesystems  | grep overlay
nodev  overlay
利用上述命令可确定内核支持OverlayFS。下面以建楼的形式来描述联合文件系统的工作方式,首先需要有混凝土和钢筋等基础原料作为最底层依赖。示例如下:
$ mkdir material
$ echo "bad concrete" > material/concrete
$ echo  "rebar" > material/rebar
但是在建设之前,发现混凝土的质量有问题,所以运来了新的混凝土,同时运来了大理石用作地板砖。示例如下:
$ mkdir material2
$ echo "good concrete" > material2/concrete
$ echo  "marble" > material2/marble
现在已经准备好了建筑所需要的所有材料,下面创建build目录作为具体施工的层。另外每个OverlayFS挂载点还依赖一些必要的目录,包括merge(工作目录)、work(OverlayFS所必须的一个空目录)等,如下:
$ mkdir merge work build 
$ ls 
build  material  material2  merge  work
然后挂载OverlayFS,下面的命令指定了material目录为最底层,material2目录为次底层,build目录为上层。至此已经完成了建楼所需要的所有依赖。
# mount -t overlay overlay -olowerdir= material: material2,upperdir= build,workdir=work  merge

1.覆盖
现在,在merge目录中可以看到混凝土、钢筋和大理石了。并且混凝土是合格的,也就是说material2目录中的concrete覆盖了material目录的对应文件。所以目录所处的层级是很重要的,上层的文件会覆盖同名的下层文件;另外现在的文件系统中会保存两份混凝土数据,所以不合理地修改一个大文件会使image的size大增。示例如下:

$ ls -l */*
-rw-r--r-- 1 root root   19 Aug 31 15:19 material/concrete
-rw-r--r-- 1 root root   12 Aug 31 15:19 material/rebar
-rw-r--r-- 1 root root   20 Aug 31 15:19 material2/concrete
-rw-r--r-- 1 root root   13 Aug 31 16:03 material2/marble
-rw-r--r-- 1 root root   12 Aug 31 15:19 material2/rebar
-rw-r--r-- 1 root root   20 Aug 31 15:19 merge/concrete
-rw-r--r-- 1 root root   13 Aug 31 16:03 merge/marble
-rw-r--r-- 1 root root   12 Aug 31 15:19 merge/rebar 
$ cat merge/concrete
good concrete

2.新增
接下来要在merge目录下建立我们的建筑框架,此时可以看到frame文件出现在了build目录中。示例如下:

# echo "main structure" >merge/frame
$ ls  */* -l 
-rw-r--r-- 1 root root   15 Aug 31 17:48 build/frame    
-rw-r--r-- 1 root root   19 Aug 31 15:19 material/concrete
-rw-r--r-- 1 root root   12 Aug 31 15:19 material/rebar
-rw-r--r-- 1 root root   20 Aug 31 15:19 material2/concrete
-rw-r--r-- 1 root root   13 Aug 31 16:03 material2/marble
-rw-r--r-- 1 root root   12 Aug 31 15:19 material2/rebar
-rw-r--r-- 1 root root   19 Aug 31 15:19 merge/concrete
-rw-r--r-- 1 root root   15 Aug 31 17:48 merge/frame
-rw-r--r-- 1 root root   13 Aug 31 16:03 merge/marble

3.删除
如果此时客户又提出了新的需求,他们不希望使用大理石地板了,那么我们就得在merge目录删掉大理石。可以看到删除底层文件系统中的文件或目录时,会在上层建立一个同名的主次设备号都为0的字符设备,但并没有直接删掉marble文件。所以删除并不一定能减小image的大小,并且要注意的是,如果制作image时使用到了一些关键的信息(用户名、密码等),则需要在同层删除,不然这些信息依然会存在于image中。

$ rm merge/marble 
$ ls -l
c--------- 1 root root 0, 0 Aug 31 18:00 build/marble
-rw-r--r-- 1 root root   19 Aug 31 15:19 merge/concrete
-rw-r--r-- 1 root root   15 Aug 31 17:48 merge/frame

联合文件系统是实现写时复制的基础。现在社区和操作系统厂家都维护着几种该类文件系统,比如Ubuntu系统自带aufs的支持,Redhat和Suse则采用的是devicemapper方案等。一些文件系统比如btrfs也具有写时复制的能力,故也可以作为Docker的存储驱动。这些存储驱动的存储结构和性能都有显著的差异,所以我们需要根据实际情况选用合理的后端存储驱动。

3.4.3 Git式管理
Git是由Linux之父Linus Torvalds创立的一个开源项目,是一种代码的分布式版本控制工具。因其具有强大的分支能力、便于协作开发等优点而取得了空前的成功,github.com作为托管代码的仓库也变得越来越流行。两者的合力直接变革了传统的软件托管方案。
Docker作为新的开源项目,充分借鉴了Git的优点(利用分层)来管理镜像,使image layer的复用变成了可能,并且类比Github提出了Dockerhub的概念,一定程度上变革了软件发布流程。

相关文章
|
4月前
|
人工智能 前端开发 Docker
从本地到云端:用 Docker Compose 与 Offload 构建可扩展 AI 智能体
在 AI 智能体开发中,开发者常面临本地调试与云端部署的矛盾。本文介绍如何通过 Docker Compose 与 Docker Offload 解决这一难题,实现从本地快速迭代到云端高效扩容的全流程。内容涵盖多服务协同、容器化配置、GPU 支持及实战案例,助你构建高效、一致的 AI 智能体开发环境。
471 2
从本地到云端:用 Docker Compose 与 Offload 构建可扩展 AI 智能体
|
3月前
|
监控 Kubernetes 安全
还没搞懂Docker? Docker容器技术实战指南 ! 从入门到企业级应用 !
蒋星熠Jaxonic,技术探索者,以代码为笔,在二进制星河中书写极客诗篇。专注Docker与容器化实践,分享从入门到企业级应用的深度经验,助力开发者乘风破浪,驶向云原生新世界。
还没搞懂Docker? Docker容器技术实战指南 ! 从入门到企业级应用 !
|
7月前
|
运维 监控 数据可视化
容器化部署革命:Docker实战指南
容器化部署革命:Docker实战指南
|
6月前
|
供应链 测试技术 开发者
用 Docker 轻松部署 ERPNext 15:多场景实战指南
ERPNext 15 是一款功能全面的开源企业资源规划系统,结合 Docker 容器化部署,具备高效、灵活、低成本等优势。适用于小微企业数字化起步、多分支机构协同办公、开发者测试环境搭建、短期项目管理及企业内部培训等多种场景。模块化设计支持按需扩展,满足不同规模企业需求,是实现高效企业管理的理想选择。
用 Docker 轻松部署 ERPNext 15:多场景实战指南
|
7月前
|
安全 Java Docker
Docker 部署 Java 应用实战指南与长尾优化方案
本文详细介绍了Docker容器化部署Java应用的最佳实践。首先阐述了采用多阶段构建和精简JRE的镜像优化技术,可将镜像体积减少60%。其次讲解了资源配置、健康检查、启动优化等容器化关键配置,并演示了Spring Boot微服务的多模块构建与Docker Compose编排方案。最后深入探讨了Kubernetes生产部署、监控日志集成、灰度发布策略以及性能调优和安全加固措施,为Java应用的容器化部署提供了完整的解决方案指南。文章还包含大量可落地的代码示例,涵盖从基础到高级的生产环境实践。
421 3
|
8月前
|
关系型数据库 MySQL 数据库
Docker Compose-实战
Docker Compose-实战
275 5
|
9月前
|
Ubuntu Linux Docker
Docker容器的实战讲解
这只是Docker的冰山一角,但是我希望这个简单的例子能帮助你理解Docker的基本概念和使用方法。Docker是一个强大的工具,它可以帮助你更有效地开发、部署和运行应用。
230 27
|
11月前
|
存储 运维 应用服务中间件
Docker Image即Docker镜像
Docker 镜像是 Docker 容器的基础,包含了运行应用程序所需的一切。通过 Dockerfile 可以方便地创建自定义镜像,并且利用 Docker 提供的命令可以轻松管理和使用这些镜像。掌握 Docker 镜像的创建、管理和使用,是进行容器化应用开发和部署的基础技能。希望本文能帮助读者更好地理解 Docker 镜像的概念和操作,提高开发和运维效率。
1380 13
|
关系型数据库 应用服务中间件 PHP
实战~如何组织一个多容器项目docker-compose
本文介绍了如何使用Docker搭建Nginx、PHP和MySQL的环境。首先启动Nginx容器并查看IP地址,接着启动Alpine容器并安装curl测试连通性。通过`--link`方式或`docker-compose`配置文件实现服务间的通信。最后展示了Nginx配置文件和PHP代码示例,验证了各服务的正常运行。
346 3
实战~如何组织一个多容器项目docker-compose