乐趣区

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

Photo by Elaine Casap on Unsplash

本文核心内容整顿自 Brian Holt 的 workshop《Complete-Intro-Containers》。

与 Docker 相似的容器技术并不是操作系统与生俱来的能力,而是通过组合一些 Linux 个性,实现 过程组隔离 的一种技术。

本篇文章将从介绍容器技术的倒退开始,进而阐明哪些 Linux 个性组成了容器技术的外围局部。心愿您可能借由浏览本篇文章,对 Docker 等容器技术有更粗浅的意识。

1. 为什么咱们须要容器

容器技术并不是凭空出现的,它起源自时代倒退中人们对于如何更高效地利用计算机资源的思考和工程实际,在本章中,我将遍历容器技术呈现之前的各时代,帮忙您了解容器技术到底解决了什么样的问题。

1.1 裸机时代

互联网服务晚期,想要架设 Web 服务器,就须要租用某个中央的服务器设施,运行程序代码。只有有短缺且称职的人员保护,就能最大限度的施展服务器性能。

裸机时代的问题在于扩大服务极度 不足灵活性:如果想要增加设施,就须要找服务器供应商(Dell 或 IBM)购买新的物理设施,并指派业余人员进行装置,调试,启动,这大略须要一两个月的工夫。

并且,当部署好一个服务器集群,操作系统与驱动的降级,硬件的替换与培修,网络问题的修复,线材的整顿,机房管理权限的设置,数据中心温度的管制以及电费与 IPS 费用的领取 … 等等这些都须要业余的团队去解决。

1.2 虚拟机时代

于是咱们进入了虚拟机时代,虚拟机是介于用户与硬件设施之间的一层形象。一开始,相较于裸机时代,一台计算机服务于繁多的用户主体,当初一台计算机容许多个用户主体登录,应用计算资源运行彼此的服务。只有设施性能短缺,用户便能够在须要时疾速增加新服务。这使得咱们取得了一些服务扩大的灵活性。

但在这种模式下存在着一些问题:

  1. 任何用户都有权限获取其余用户服务存储的数据;
  2. 用户能够通过投放 Fork Bomb(见下方阐明) 的形式,掠夺服务器资源;
  3. 一台物理设施上的任何租户都可能无意间使整个服务器解体;

为了解决这一问题,呈现了虚拟机技术:即 当用户创立服务时,在计算机的主操作系统上装置新的操作系统调度硬件资源以达成数据隔离的指标。并且当一个服务解体时,最多导致服务所属的操作系统解体,服务器设施上的其余租户将不受影响。

虚拟机技术的弊病在于在主操作系统中运行其余操作系统所带来的性能损耗。但只有计算机领有短缺的算力和内存,这些性能损耗都能够被承受。

Fork Bomb 是一种通过一直生成子过程,以达到占用大量系统资源的目标,从而导致系统无奈失常工作,甚至进行响应的攻打伎俩。它通常通过在操作系统中创立大量过程,以耗费零碎内存和处理器资源,并导致系统解体。

1.3 私有云时代

通过 Microsoft Azure,Amazon Web Services 或阿里云等私有云服务提供商提供的虚拟机服务,用户不再须要治理低廉且简单的数据中心,只须要治理本人的应用程序。云服务厂商尽管不会帮忙用户更新操作系统,然而会定期更新服务器设施。

但在这种模式下,虚拟机提供商向用户提供的,实质上依然是计算机的硬件设施(CPU 和内存),用户依然须要领取调度,保护整个操作系统的开销(例如网络管理,装置与更新软件等),这又须要业余的技术人员负责。

如果可能帮忙用户节俭掉保护操作系统的开销,让应用程序间接运行,那就太棒了。这种需要催生了下个时代的到来。

1.4 容器时代

容器技术为用户提供了许多虚拟机平安和资源管理的性能,但节俭掉了运行整个操作系统的老本。它通过以下三个 Linux 命令胜利将过程组之间彼此隔离:

  • chroot:实现目录级别的资源隔离;
  • unshare:实现过程级别的资源隔离;
  • cgroup:限度隔离环境中可调度的资源大小;

上面咱们将具体介绍这三个命令。

2. 实现容器技术的三个要害 Linux 命令

2.1 chroot命令

chroot 是一个 Linux 命令,容许为一个新过程创立根目录。当为一个容器设置一个新目录后,容器内的过程将无法访问到任何根目录外的数据,这就打消了数据泄露的安全隐患。

运行以下命令开始实际:

  1. docker run -it --name docker-host --rm --privileged ubuntu:bionic

命令解析:

  • docker run:在容器中运行一些命令;
  • -it:令 shell 放弃可交互状态;
  1. 创立新目录并进入:mkdir /my-new-root && cd $_
  2. 创立一些秘密文件:echo "my super secret thing" >> /my-new-root/secret.txt
  3. 运行命令:chroot /my-new-root bash

此时,程序会报错:

chroot: failed to run command 'bash': No such file or directory

这是因为新的根目录 /my-new-root 内并未蕴含 bash程序,执行以下命令修复:

  1. mkdir /my-new-root/bin
  2. cp /bin/bash /bin/ls /my-new-root/bin/
  3. chroot /my-new-root bash

此时程序仍然会报错,因为咱们尚未装置 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)

接着运行以下命令:

  1. mkdir /my-new-root/lib{,64}
  2. 将 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
  3. 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-root bash命令将胜利运行。在 bash shell 中应用 pwd命令可见,以后根目录为 /。至此,咱们实现了目录级别的资源隔离。

2.2 unshare命令

chroot命令使操作系统能够使用户彼此无法访问目录下的文件,但用户仍然能够通过查看零碎过程理解计算机的运行状况。通过杀死过程,卸载文件系统等伎俩,歹意用户仍然会对计算机的平安造成威逼。

2.2.1 chroot 命令的问题

  1. 开启一个新的终端,并运行 docker exec -it docker-host bash 命令进入操作系统;
  2. 运行 tail -f /my-new-root/secret.txt & 命令,长久化一个后盾过程;
  3. 运行 ps 命令查看过程 ID(PID);
  4. 在原先的终端中执行 kill <PID> 命令,可见终端 2 的长久化过程曾经被杀死了;

由此可见,仅仅做到文件系统的隔离是不够的,因而须要通过 unshare命令,暗藏过程,让过程之间彼此不通明。

2.2.2 unshare 命令

unshare命令将从父过程中创立一个独立的命名空间。代码操作如下:

exit # from our chroot'd environment if you're still running it, if not skip this

# install debootstrap
apt-get update -y
apt-get install debootstrap -y
debootstrap --variant=minbase bionic /better-root

# head into the new namespace'd, chroot'd environment
unshare --mount --uts --ipc --net --pid --fork --user --map-root-user chroot /better-root bash # this also chroot's for us
mount -t proc none /proc # process namespace
mount -t sysfs none /sys # filesystem
mount -t tmpfs none /tmp # filesystem

再反复一次咱们方才的试验会发现,此时终端 #1 曾经无奈再拜访和杀死终端 #2 的长久化过程了。

2.3 cgroups命令

即便通过 chroot 命令隔离文件系统,通过 unshare隔离过程,每个隔离环境仍然能够拜访服务器的所有物理资源,这使得当服务器中的一个租户运行大量计算占满计算资源时,其余租户的服务将无以为继。

这时候就须要用到 cgroups(control groups)命令。它使得每个隔离单元只可能无限地应用系统资源。

具体操作如下:

# outside of unshare'd environment get the tools we'll need here
apt-get install -y cgroup-tools htop

# create new cgroups
cgcreate -g cpu,memory,blkio,devices,freezer:/sandbox

# add our unshare'd env to our cgroup
ps aux # grab the bash PID that's right after the unshare one
cgclassify -g cpu,memory,blkio,devices,freezer:sandbox <PID>

# list tasks associated to the sandbox cpu group, we should see the above PID
cat /sys/fs/cgroup/cpu/sandbox/tasks

# show the cpu share of the sandbox cpu group, this is the number that determines priority between competing resources, higher is is higher priority
cat /sys/fs/cgroup/cpu/sandbox/cpu.shares

# kill all of sandbox's processes if you need it
# kill -9 $(cat /sys/fs/cgroup/cpu/sandbox/tasks)

# Limit usage at 5% for a multi core system
cgset -r cpu.cfs_period_us=100000 -r cpu.cfs_quota_us=$[5000 * $(getconf _NPROCESSORS_ONLN) ] sandbox

# Set a limit of 80M
cgset -r memory.limit_in_bytes=80M sandbox
# Get memory stats used by the cgroup
cgget -r memory.stat sandbox

# in terminal session #2, outside of the unshare'd env
htop # will allow us to see resources being used with a nice visualizer

# in terminal session #1, inside unshared'd env
yes > /dev/null # this will instantly consume one core's worth of CPU power
# notice it's only taking 5% of the CPU, like we set
# if you want, run the docker exec from above to get a third session to see the above command take 100% of the available resources
# CTRL+C stops the above any time

# in terminal session #1, inside unshare'd env
yes | tr \n x | head -c 1048576000 | grep n # this will ramp up to consume ~1GB of RAM
# notice in htop it'll keep the memory closer to 80MB due to our cgroup
# as above, connect with a third terminal to see it work outside of a cgroup

3. 小结

通过综合应用 chrootunsharecgroups 命令,咱们可能基于操作系统,无效地创立一个隔离单元,隔离文件系统,过程并设置计算机资源的应用下限。这就是容器技术的外围。它帮忙用户节俭掉了保护操作系统的开销,能够使用户专一于应用程序的开发和部署。

心愿各位读者有所播种,后会有期:)

退出移动版