当前位置: 首页 > Linux

快速理解容器技术的实现原理

时间:2023-04-06 05:47:12 Linux

PhotobyElaineCasaponUnsplash本文核心内容整理自BrianHolt的workshop《Complete-Intro-Containers》。类似于Docker的容器技术并不是操作系统固有的能力,而是结合Linux的一些特性实现进程组隔离的技术。本文将从容器技术的发展介绍入手,然后阐述哪些Linux特性构成了容器技术的核心部分。希望大家通过阅读本文,对Docker等容器技术有更深入的了解。一、为什么需要容器容器技术并不是凭空出现的。它源于时代发展中人们对如何更有效地利用计算机资源的思考和工程实践。在本章中,我将穿越容器技术出现之前的时代,帮助大家理解容器技术解决了什么样的问题。1.1在早期的裸机时代互联网服务中,如果要架设web服务器,需要在某处租用服务器设备来运行程序代码。只要由足够的合格人员维护,服务器性能就可以最大化。裸机时代的问题是扩容服务极其不灵活:如果要增加设备,需要找服务器供应商(Dell或IBM)购买新的物理设备,并指派专业人员安装、调试、维护。开始。两个月。并且,部署服务器集群时,升级操作系统和驱动程序、硬件更换和维修、网络问题修复、布线、机房管理权限设置、数据中心温度控制、支付电费和IPS费用。..等等,这些都需要专业的团队来处理。1.2虚拟机时代于是我们进入了虚拟机时代,虚拟机是用户和硬件设备之间的一层抽象。与当初裸机时代相比,一台计算机服务于单个用户代理,而现在一台计算机允许多个用户代理登录并使用计算资源来运行彼此的服务。只要设备性能足够,用户可以在需要时快速添加新服务。这使我们能够在服务扩展方面获得一些灵活性。但是,这种模式存在一些问题:任何用户都有权获取其他用户服务存储的数据;用户可以通过启动ForkBomb来掠夺服务器资源(见下文);物理设备上的任何租户为了解决这个问题,出现了虚拟机技术:即当用户创建服务时,在计算机的主操作系统上安装一个新的操作系统来调度硬件资源以达到目的的数据隔离。而当一个服务崩溃时,至多是该服务所属的操作系统崩溃,服务器设备上的其他租户不会受到影响。虚拟机技术的缺点是在主操作系统中运行其他操作系统带来的性能损失。但只要计算机有足够的计算能力和内存,这些性能损失是可以接受的。ForkBomb是一种不断产生子进程占用大量系统资源,导致系统无法正常工作甚至停止响应的攻击方式。它通常会在操作系统中创建大量进程,消耗系统内存和处理器资源,导致系统崩溃。1.3公有云时代有了MicrosoftAzure、AmazonWebServices、阿里云等公有云服务商提供的虚拟机服务,用户不再需要管理昂贵复杂的数据中心,只需要管理自己的应用。虽然云服务提供商不会帮助用户更新操作系统,但他们会定期更新服务器设备。但在这种模式下,虚拟机提供商提供给用户的本质上是计算机的硬件设备(CPU和内存),用户仍然需要为整个操作系统的调度和维护付费(如网管)、安装和更新)。软件等),又需要专业的技术人员负责。如果能帮助用户省去维护操作系统的开销,让应用程序直接运行起来,那就太好了。这种需要催生了下一个时代。1.4容器时代容器技术为用户提供了许多虚拟机安全和资源管理功能,同时节省了运行整个操作系统的成本。它通过以下三个Linux命令成功地将进程组相互隔离:chroot:实现目录级别的资源隔离;unshare:实现进程级的资源隔离;cgroup:限制在隔离环境中可以调度的资源大小;介绍这三个命令。2.实现容器技术的三个关键Linux命令2.1chroot命令chroot是一个Linux命令,允许为新进程创建根目录。当为容器设置新的目录时,容器内的进程将无法访问根目录外的任何数据,消除了数据泄露的安全风险。运行以下命令开始:dockerrun-it--namedocker-host--rm--privilegedubuntu:bionic命令分析:dockerrun:在容器中运行一些命令;-it:保持shell交互;创建一个新目录并输入:mkdir/my-new-root&&cd$_;创建一些秘密文件:echo"mysupersecretthing">>/my-new-root/secret.txt;运行命令:chroot/my-new-rootbash;此时程序会报错:chroot:failedtoruncommand'bash':Nosuchfileordirectory这是因为新的根目录/my-new-root中不包含bash程序,执行以下命令修复:mkdir/my-new-root/bin;cp/bin/bash/bin/ls/my-new-root/bin/;chroot/我的新根庆典;这个时候程序还是会报错,因为我们还没有安装bash依赖。(通过ldd命令可见):linux-vdso.so.1(0x00007ffe5705a000)libtinfo.so.5=>/lib/x86_64-linux-gnu/libtinfo.so.5(0x00007fb89f047000)libdl.so.2=>/lib/x86_64-linux-gnu/libdl.so.2(0x00007fb89ee43000)libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007fb89ea52000)/lib64/ld-linux-x86-64.so.2(0x00007fb89f58b000)然后运行以下命令:mkdir/my-new-root/lib{,64};将bash依赖项复制到新创建的根目录:cp/lib/x86_64-linux-gnu/libtinfo。so.5/lib/x86_64-linux-gnu/libdl.so.2/lib/x86_64-linux-gnu/libc.so.6/my-new-root/lib;cp/lib64/ld-linux-x86-64.so.2/my-new-root/lib64;同样的方法安装ls的依赖:cp/lib/x86_64-linux-gnu/libselinux.so.1/lib/x86_64-linux-gnu/libpcre.so.3/lib/x86_64-linux-gnu/libpthread。so.0/my-new-root/lib此时运行chroot/my-new-rootbash命令就可以成功运行了。在bashshell中使用pwd命令查看当前根目录为/。至此,我们就完成了目录级别的资源隔离。2.2unshare命令chroot命令可以使操作系统阻止用户访问目录下的文件,但用户仍然可以通过查看系统进程了解计算机的运行状态。通过杀进程、卸载文件系统等方式,恶意用户仍然会对计算机的安全造成威胁。2.2.1chroot命令的问题打开一个新的终端,运行dockerexec-itdocker-hostbash命令进入操作系统;运行tail-f/my-new-root/secret.txt&命令持久化一个后台进程;运行ps命令查看进程ID(PID);在原终端执行kill命令,可以看到终端2的持久化进程已经被kill掉;可见文件系统的隔离是不够的,所以需要使用unshare命令来隐藏进程,让进程之间互相不透明。2.2.2unshare命令unshare命令会创建一个独立于父进程的命名空间。代码操作如下:如果您仍在运行它,请从我们的chroot环境中退出,如果没有,请跳过此#installdebootstrapapt-getupdate-yapt-getinstalldebootstrap-ydebootstrap--variant=minbasebionic/better-root#进入新的命名空间、chroot环境unshare--mount--uts--ipc--net--pid--fork--user--map-root-userchroot/better-rootbash#这也是usmount-tprocnone/proc#processnamespacemount-tsysfsnone/sys#filesystemmount-ttmpfsnone/tmp#filesystem再次重复我们之前的实验,我们会发现终端#1不再可访问并终止终端#2的持久化过程。2.3cgroups命令即使通过chroot命令隔离了文件系统,通过unshare隔离了进程,每个隔离的环境仍然可以访问服务器的所有物理资源。将是不可持续的。这时候就需要用到cgroups(控制组)命令。它使每个隔离单元仅使用有限的系统资源。具体操作如下:#在取消共享的环境之外获取我们在这里需要的工具apt-getinstall-ycgroup-toolshtop#创建新的cgroupscgcreate-gcpu,memory,blkio,devices,freezer:/sandbox#添加我们的取消共享'denvtoourcgrouppsaux#抓取bashPID就在unshareonecgclassify-gcpu,memory,blkio,devices,freezer:sandbox#listtasksassociatedtothesandboxcpugroup,我们应该看到上面的PIDcat/sys/fs/cgroup/cpu/sandbox/tasks#showthecpushareofthesandboxcpugroup,这个是决定竞争资源之间优先级的数字,越高优先级越高cat/sys/fs/cgroup/cpu/sandbox/cpu.shares#如果需要,杀死沙箱的所有进程#kill-9$(cat/sys/fs/cgroup/cpu/sandbox/tasks)#将多核系统的使用限制在5%cgset-rcpu.cfs_period_us=100000-rcpu.cfs_quota_us=$[5000*$(getconf_NPROCESSORS_ONLN)]sandbox#设置80Mcgset的限制-rmemory.limit_in_bytes=80Msandbox#获取备忘录cgroupcgget-rmemory.stat沙箱#在终端会话#2中使用的ry统计数据,在unshare'denvhtop之外#将允许我们在终端会话#1中,在unshared'd内看到资源被一个很好的可视化工具使用envyes>/dev/null#这将立即消耗一个核心的CPU功率#注意它只占用5%的CPU,就像我们设置的那样#如果你愿意,从上面运行dockerexec以获得第三个会话来查看上面的命令占用100%的可用资源#CTRL+C随时停止上面的操作#在终端会话#1中,在unshare'denvyes|tr\nx|头-c1048576000|grepn#这将消耗~1GB的RAM#注意在htop中,由于我们的cgroup#如上所述,它将使内存接近80MB,连接第三个终端以查看它在cgroup3之外的工作。总结通过综合使用chroot、unshare和cgroups命令,我们能够有效地创建一个基于操作系统的隔离单元,隔离文件系统、进程,设置计算机资源的使用上限是容器技术的核心。它可以帮助用户节省维护操作系统的开销,让用户专注于应用程序的开发和部署。希望各位读者有所收获,后面有期:)