容器虚拟化原理

容器简介

容器是一种打包应用及其运行环境的方式,为应用打包所有软件及其所依赖的环境,并且可以实现跨平台部署,它是一系列内核特性的统称。

容器技术优缺点

相比先前的各种技术,容器技术具有以下优点。

轻量化: 相比虚拟机,容器提供了更小的镜像,因此可以更快速地对容器进行构建和启动。容器更适合需要批量快速上线和快速弹性伸缩的应用。

细粒度(资源管控): 容器是一个沙箱运行进程,这个沙箱起到了细粒度管控资源的作用。在创建容器时,可以指定CPU、内存及I/O资源。在运行容器时强制执行这些资源限制,可防止容器占用其他资源。

高性能(资源利用率高): 容器使用更轻量级的运行机制,它是一种操作系统级别的虚拟化机制。由于容器是以进程形态运行的,因此其性能更接近裸机的性能。对于对性能有较高要求的应用,如高性能计算等,容器更为合适。

环境一致性: 容器实现了操作系统的解耦,它打包了整个操作系统,保证应用运行的本地环境和远端环境的高度一致性,从而保证一次容器打包可以到处运行,对跨平台、不同环境的应用部署有显著的帮助。

管理便捷性: 使生命周期管理,包括迁移、扩展、运维等更加便捷。

但不可否认,安全隔离一直是容器技术的一大弊端。容器只是运行在宿主机上的一种特殊进程,因此多个容器之间共享的还是同一台宿主机的操作系统内核,从而大大增加了安全攻击面。

容器的组成

容器=cgroup+namespace+rootfs+容器引擎(用户态工具)

  • cgroup:资源控制
  • namespace:访问隔离
  • rootfs:文件系统隔离
  • 容器引擎:生命周期控制

基本技术

一个应用程序的运行环境的总和(内存中的数据、寄存器里的值、堆栈中的指令、被打开的文件,以及各种设备的状态信息的集合)被称为一个进程。容器技术的核心就是通过约束和修改进程的动态表现,从而为其创造出一个逻辑的“边界”。

容器技术本质上为应用解决了两个核心问题:应用的资源隔离限制和应用的可移植性(即在新的环境中可以直接运行)。容器将替代进程,成为今后主流的应用运行形态。

namespace

namespace是Linux用来隔离系统资源的方式,它使得PID、IPC、network等系统资源不再是全局性的,而是属于特定namespace 的,其中的进程好像拥有独立的“全局”系统资源。每个namespace里面的资源对其他namespace都是透明的、互不干扰的,改变一个namespace中的系统资源只会影响当前namespace中的进程,对其他namespace中的进程没有影响。

本质上,namespace建立了系统的不同视图,此前的每一项全局资源都必须被包装到namespace数据结构中。

创建namespace的三种方法
  • 在用fork或clone系统调用创建新进程时,可通过特定的选项控制,是与父进程共享命名空间,还是建立新的命名空间。
  • setns系统调用让进程加入已经存在的namespace中,Docker exec就采取了该方法。
  • unshare系统调用让进程离开当前的namespace,加入新的namespace中。
PID namespace

如果在调用clone时设定了CLONR_NEWPID,就会创建一个新的PID namespace,创建的新进程将会成为该namespace里的第一个进程,在当前PID namespace中这个进程的PID从1开始,该namespace内的进程都将以该进程为父进程,当该进程结束时,其中所有的进程都会结束。

PID namespace 是有层次的,新创建的 namespace 将会是创建该 namespace 的进程所属的namespace的子namespace。子namespace中的进程对父namespace是可见的,一个进程将拥有不止一个PID,其所在的namespace及所有直系祖先namespace中都将有一个PID。系统启动时,内核将创建一个默认的PID namespace,该namespace是所有以后创建的namespace的祖先,因此系统的所有进程在该namespace内都是可见的。

IPC namespace

在一个IPC(Inter-Process Communication 进程间通信) namespace中创建的IPC object对该 namespace 内的所有进程可见,但是对其他 namespace 中的进程不可见,这就使得不同namespace之间的进程不能直接通信。

PID namespace 和 IPC namespace 可以组合使用,只需在调用 clone 系统时同时指定CLONE_NEWPID和CLONE_NEWIPC,这样新创建的namespace就既是一个独立的PID命名空间,又是一个独立的IPC命名空间。不同namespace中的进程彼此不可见,也不能互相通信,这样就实现了进程间的隔离。

mount namespace

每个进程都存在于一个mount namespace中,mount namespace为进程提供了一个文件层次视图,用于让被隔离的进程只看到当前namespace里的挂载点信息。只有在“挂载”这个操作发生之后,进程的视图才会被改变,而在此之前新创建的容器会直接继承宿主机的各个挂载点。

如果不设定这个flag,子进程和父进程将共享一个mount namespace,其后子进程调用mount或umount将会对该namespace内的所有进程可见。如果子进程在一个独立的mount namespace中,就可以调用mount或umount建立一个新的文件层次视图,mount、unmount只对该namespace内的进程可见。该flag配合chroot、pivot_root系统调用,可以为进程创建一个独立的目录空间,chroot实现目录独享,mount namespace实现挂载点独享。

network namespace

如果在调用 clone 时设定了 CLONE_NEWNET,就会创建一个新的 network namespace。network namespace为进程提供了一个完全独立的网络协议栈视图,其包括网络设备接口、IPv4和IPv6协议栈、IP地址路由表、防火墙规则、Socket等。一个network namespace提供了一个独立的网络环境,就跟一个独立的系统一样。**一个物理设备只能存在于一个network namespace中,但它可以从一个 namespace 移动到另一个namespace 中。虚拟网络设备(Virtual Network Device)提供了一种类似于管道的抽象,可以在不同的 namespace 之间建立隧道。利用虚拟网络设备,我们可以建立某个 namepace 与其他 namespace 中物理设备的桥接。**当一个 network namespace 被销毁时,物理设备会被自动移回初始的 network namespace,即系统最开始的namespace中。

UTC namespace

如果在调用clone时设定了CLONE_NEWUTS,就会创建一个新的UTS namespace。一个 UTS namespace 就是一组被 uname 返回的标识符。新的 UTS namespace中的标识符通过复制调用进程所属的namespace的标识符来初始化,clone出来的进程可以通过相关系统调用改变这些标识符,比如调用sethostname来改变该namespace的主机名。

总结来说,Linux中的每个进程都包含以上多种namespace。

一个容器就是一个虚拟的运行环境,它对容器里的进程是透明的,进程会以为自己是直接在一个系统上运行的。实际上,容器在创建容器进程时,指定了这个进程所需启用的一组namespace参数,这样容器进程就只能“看到”当前namespace所限定的资源、文件、设备、状态或配置,而对于宿主机及其他不相关的应用,它就完全看不到了。这时,容器进程就会觉得自己是各自PID namespace里的第1号进程,只能看到各自mount namespace里挂载的目录和文件,只能访问各自network namespace里的网络设备,就好像运行在一个“容器”里面。

Linux namespace机制本身就是为实现容器虚拟化而开发的,它实际上修改了应用进程看待整个系统资源的“视角”,即它的“视线”被namespace做了限制,只能看到某些指定的内容。但对于宿主机来说,这些被隔离的进程与其他进程并没有太大的区别,所以 namespace 提供了一套轻量级、高效率的系统资源隔离方案,其远比传统的虚拟化技术开销小。不过,它也不是完美的,它为内核的开发带来了更大的复杂性,在隔离性和容错性上与传统的虚拟化技术相比也有差距。

cgroup(control group)

cgroup是Linux内核中的一项功能,它可以对进程进行分组,并在分组的基础上限制进程组能够使用的资源上限(如 CPU 时间、系统内存、网络带宽等)。cgroup的作用和namespace不一样,namespace是为了隔离进程之间的资源,而cgroup是为了对一组进程进行统一的资源监控和限制。

cgroup实现了一个通用的进程分组框架,而不同资源的具体管理则是由各个cgroup子系统实现的:

子系统描述
devices设备权限控制
cpuset分配指定的cpu和内存节点
cpu控制cpu占用率
cpuacct统计cpu使用情况
memory限制内存的使用上限
freezer暂停cgroup中的进程
net_cls配置(tc)限制网络带宽
net_prio设置进程的网络流量优先级
huge_tlb限制HugeTLB的使用
pref_event允许perf工具基于cgroup分组做性能检测

cgroup和进程的关系?

Cgroup和进程之间的关系是,Cgroup可以将一组进程组绑定到一个特定的Cgroup中,并对这些进程组的资源使用进行限制和控制。这样,Cgroup实际上是对一组进程进行资源管理的工具。

当一个进程被创建时,它可以被分配到特定的Cgroup中,这样就可以受到该Cgroup所施加的资源限制和控制。这样就实现了对进程的资源隔离和管理。

rootfs

为了实现应用运行环境的一致性,容器使用了 rootfs 技术,这使得容器镜像中打包的内容不只有应用本身,还包括整个操作系统的文件和目录,即应用及其所需的依赖都被封装在一起,实现了应用环境的强一致性。

容器就是一个进程,所以可以通过chroot为容器进程提供一个新的根目录及新的文件系统。为了能够让容器的根目录看起来更像是一个真实的操作系统的根目录,一般会在容器启动时在其根目录下挂载一个完整的操作系统的文件系统,比如Ubuntu 16.04的ISO。这样在容器启动之后,在容器内执行“ls/”命令就可以查看整个根目录下的内容,也就是Ubuntu系统的所有目录和文件。

在Linux中有一个chroot命令,它的作用就是将进程的根目录变更到指定的位置(change root file system)

这个被挂载在容器根目录下,用来为容器进程提供隔离后运行环境的文件系统,就是容器镜像,被称为rootfs(根文件系统)。rootfs只是一个操作系统的文件系统,其中包括文件、配置和目录等,但并不包括操作系统内核。

同一台宿主机上的所有容器,都共享宿主机操作系统的内核。这就意味着,如果容器中的应用程序需要配置内核参数、加载额外的内核模块,以及与内核进行直接的交互等,那么这些都是对宿主机操作系统内核的操作,其对于该宿主机上的所有容器来说是全局操作。

镜像分层

Docker镜像的制作并没有沿用以前制作rootfs的标准流程,而是在镜像的设计过程中引入了层(layer)的概念。用户制作镜像的每一步操作都会生成一个层,整个文件系统的增量机制是基于UnionFS的。UnionFS是Linux内核中的一项技术,它将多个处于不同位置的目录联合挂载到同一个目录下。而Docker就是利用这种联合挂载的能力,将容器镜像里的多层内容呈现为统一的rootfs的。在Docker中使用的UnionFS是通过aufs来实现的,虽然aufs还未进入Linux内核主干,但是它在Ubuntu、Debain等发行版本中均有使用。

以Docker为例,其镜像主要分为三层:

  • 只读层:同期的rootfs最下面五层,以增量的方式分别包含整个文件系统;
  • 可读/写层:容器的rootfs最上面的一层,在没有写入文件之前,这个层是空的。一旦在容器里进行了写操作,由此产生的内容就会以增量的方式出现在这一层中。可读/写层就是专门用来存放修改 rootfs 后产生的增量内容的——无论是增加、删除还是修改产生的增量内容。当使用完这个被修改过的容器之后,还可以使用“docker commit”和“push”命令保存这个被修改过的可读/写层,而只读层里的内容不会有任何变化,这就是增量rootfs的好处。
  • init层:这是 Docker/Kubernetes 单独生成的一个内部层,专门用来存放/etc/hosts、/etc/resolv.conf等配置信息。这些文件本来属于只读层,但是在启动容器时每次都会自动写入一些指定的参数,比如hostname,所以理论上需要在可读/写层对它们进行修改。但这些修改往往只对当前的容器有效,并不希望执行“docker commit”命令时,需将这些信息连同可读/写层一起提交,所以设置了额外的 init 层,init 层的内容在执行“docker commit”命令时会被忽略。

容器创建原理

pid = clone(fun, stack, flags, clone_arg);
(flags: CLONE_NEWPID  | CLONE_NEWNS  |
    CLONE_NEWUSER | CLONE_NEWNET |
    CLONE_NEWIPC  | CLONE_NEWUTS |)

通过clone系统调用,并传入各个Namespace对应的clone flag,创建了一个新的子进程,该进程拥有自己的Namespace。根据以上代码可知,该进程拥有自己的pid、mount、user、net、ipc、uts namespace。

echo $pid > /sys/fs/cgroup/cpu/tasks
echo $pid > /sys/fs/cgroup/cpuset/tasks
echo $pid > /sys/fs/cgroup/blkio/tasks
echo $pid > /sys/fs/cgroup/memory/tasks
echo $pid > /sys/fs/cgroup/devices/tasks
echo $pid > /sys/fs/cgroup/freezer/tasks

将代码一中产生的进程pid写入各个Cgroup子系统中,这样该进程就可以受到相应Cgroup子系统的控制。

fun()
{pivot_root("path_of_rootfs/", path);exec("/bin/bash");}

该fun函数由上面生成的新进程执行,在fun函数中,通过pivot_root系统调用,使进程进入一个新的rootfs,之后通过exec系统调用,在新的Namespace、Cgroup、rootfs中执行“/bin/bash”程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
网盘文件永久链接 目录: 1虚拟化技术回顾_mp4 2主机虚拟化容器虚拟化区别及优缺点_mp4 3云平台技术实现方式mp4 4容器涉及的内核技术 Name Space. mp4 5容器涉及的内核技术 GRoups_mp4 6 egroup九大子系统介绍,mp4 7 Cgroup限制进程对CPU使用案例mp4 8 Cgroup限制进程对mem。n使用案例mp4 9容器技术发展历史及容器管理具 10 docker版本介绍mp4 11docker部署YUM源获取mp4 12 docker安装及服务启动,mp4 13容器镜像获取mp4 14运行个容器mp4 15 dockerdaemon配置远程及本地管理mp4 16 dockel命令行命令介绍.mp4 17docker获取镜像mp4 18 docker容器镜像传输_mp4 19 docker容器运行bash命令mp4 20 docker容器运行htpd服务mp4 21把正在运行的客器打包后导入为容器镜像,mp4 22查看容器P地址方法mp4 23停止一个或多个正在运行的容器mp4 24后动个已停止的容器及删除个止容器mp4 25容器端目映射mp4 26数据持久化存储mp4 27容器时间同步,mp4 28在容器外执行容器内命令,mp4 29容器之间使用nk连接mp4 30容器镜像介个绍mp4 31基像制作mp4 32应用镜像制作 commrt-mp4 33dockerbuild使用 Dockerfilef创建应用镜像介绍mp4 34 dockerbuildt使用 Dockerfile创建应用镜像过程分析:mp4 35 dockerbuild使用 Dockerfilet创建应用镜像案例mp4 36 dockerbuild使用 Dockerfile创建应用镜像案例替代原网站内容,mp4 37 dockerbuild使用 Dockerfilet创建 nginx应用镜像案例mp4 38容器镜像容器本身存储数据的位置及方法mp 39 overlay,及 overlay2工作原理mp4 40 overlay及 overlay2工作原理mp4 41 overlay2存储容器数据方法验证:r 42容器公有仓库注册及登录mp4 43公有仓库容器镜像上传及下载mp4 44 ocker中国镜像加速器介绍及应用mp4 45阿里云镜像加速器个绍及应用mp4 46创建本地非安全镜像仓库mp4 47创建本地样安全镜像仓库其它主机中验证是否可用mp4 48备 pipdockercomposeharbor_, mp4 49 harbor部及镜像上传,mp4 50下载 harbor仓库中容器镜像并应用mp 51 docker网络个绍四种网络mp4 52 docker主机容器间通信网络介绍mp4 53 dockers主机客器间通信网络环境佳备mp4 54 docker跨主机容器间通信网络配置etcd及 el mp 55 docker跨主机容器间通信网络node验证,mp4 56 docker跨主机容器间通信网络node2验证mp4 57容器编排部署介绍_mp4 58容器编排部署工具介个绍_,mp4 59 dockercompose编排工具介绍mp4 60dockercompose编排应用案例 haproxy. mp4 61 dockercompose编排应用案例 flaskredis mp4 62 dockercompose编排应用案例 wordpress.mp4 63 dockerswarm是什么mp4 64 dockerswarm架构,mp4 .........................

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值