来自第一性原理的容器

2020-06-05 13:48:46

你可能听过办公室里或网上的每个人都宣称“K8吃了每个人的午餐!”或者“所有的东西都应该放在码头集装箱里!”

虽然以上方法都有优势,但很容易被大众接受,尤其是对于Kubernetes(K8)。然而,我发现最大的问题是从根本上缺乏所谓的*容器。

网上有1000个其他的帖子解释容器,我正在向池中添加我自己的帖子。也许这个第1001个解释会以一种让人摸不着头脑的方式来解释。

编写的任何命令都是在Linux环境中完成的;如果您尝试在OSX中执行,可能会更具挑战性,因为Docker运行在虚拟机管理程序或虚拟机中。

让我们首先来看一下周围最简单的Docker图像之一,Alpine Linux。

Alpine Linux是一个基于MUSL和BusyBox的Linux发行版,旨在实现安全性、简单性和资源效率。

#本地下载镜像docker Pull alpine:3.12.03.12.0:正在从库中拉取/alpineDigest:sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321Status:为alpine下载了更新的镜像:3.12.0#save the imagedocker save alpine:3.12.0>;alpine-3.12.0.tar。

事实上,当我们看到layer.tar中的内容时,它是一个完整的Linux文件系统布局。

您可以随意深入研究覆盖文件系统的概念;但是,这些层至少代表了在Dockerfile过程中执行的各个步骤。

如果一个图像多于1个图像,则将它们的内容叠加以创建最终的文件系统视图。

许多人可能认为“容器”这个词在Linux内核中有特定的含义;然而,内核没有“容器”的概念。这个词已经成为各种Linux工具的同义词,当应用这些工具时,它们与我们期望的容器相似。

简单地说,容器应该有点类似于单独的机器(或虚拟机),尽管它们中的许多都运行在单个内核上。

Linux通过名称空间实现这些隔离。让我们使用简单的bash命令一起重新构建隔离。

gcloud计算实例创建容器--解密--镜像-家族debian-10--镜像-项目debian-cloud--zone us-west1-agcloud计算ssh容器-解密后的#内核版本无名-r4.19.0-9-cloud-amd64#install docker sudo apt-get install apt-Transport-https ca-certified curl gnupg2 Software-properties-commoncurl-fsSL https://download.docker.com/linux/debian/gpg|sudo apt-key add sudo add-apt。deb[ch=amd64]https://download.docker.com/linux/debian buster稳定";sudo apt-get update sudo apt-get install docker-ce docker-ce-cli tainer.io sudo groupadd docker sudo usermod-ag docker$user。

sudo unshare--fork--mount bash#我们需要绑定装载本身--#这只是PIVOT_ROOT的先决条件,而PIVOT_ROOT是下一步装载--绑定容器/容器/#创建存储文件透视的位置ystemPivot_ROOT容器/容器/_old#检查是否已透视ls-l/_old/|headTotal 128drwxr-xr-x 1 root 4096 May 28 01:21 bindrwxr-xr。1 00:31 devdrwxr-xr-x 1根4096 Jun 1 00:31 etcdrwxr-xr-x 1根4096 5月28 00 00:11 googledrwxr-xr-x 4根4096 Jun 1 00:31 home#Great now unmount it;出于安全原因,这样进程就不能逃脱监狱CD/umount-l/_old。

PIVOT_ROOT将调用进程的根文件系统移到第二个参数所在的目录,并使第一个参数成为调用进程的新根文件系统。

太棒了!看起来我们处于单独的文件系统环境中。让我们重新添加proc文件系统。

mount-t proc/proc/procps aux|headPID用户时间命令1根0:00/bin/bash/google/scripts/onrun.sh睡眠无限8根0:00/usr/sbin/rsyslogd573root 0:00/usr/sbin/sshd-p22-o AuthorizedKeysFile=/etc/ssh/keys/authorized_keys 647root 0:20/usr/bin/dockerd-p/var/run/docker.pid-mtu=1460-注册表镜像=https://us-mirror.gcr.io。var/run/docker/tainerd/tainerd.toml--日志级信息。

#添加一个`--pid`nowsudo unshare--fork--pid--mount bash#执行与上述命令相同的所有命令--bind tainer/tainer/vot_root容器/tainer/_olduount-l/_oldmount-t proc/proc/procps aux PID用户时间命令1 root 0:00 bash 104 root 0:00 ps aux。

IP链路列表1:LO:<;Loopback,Up,Low_Up>;mtu 65536 qdisk noqueue qlen 1000 link/loopback 00:00:00:00:00:00:00:00:002:docker0:<;no-载波,广播,多播,up>;mtu 1500 qdisk noqueue link/Ethernet 02:42:C2:8A:54:22 brd ff:ff12:eth0@if。MTU 1500 qdisk无队列链路/以太网02:42:AC:11:00:04 brd ff:ff。

看起来我们仍然可以访问物理以太网设备;这不是隔离的…。让我们把它修好!

#我们在后台sudo unshare--fork--pid--mount--uts--net bash#在单独的窗口(主机名称空间)中运行以下命令#获取unshare cpid=$(Pidof Unshare)的PID#这将使用进程的PID挑选正确的netns sudo IP链路add h$cpid type veth对等名称c$cpid netns$cpid#打开设备&;将其附加到原始窗口(新命名空间)中的docker0桥sudo IP链路集h$cpid up master docker0##filesystemmount--bind tainer/tainer/vot_root tainer/tainer/_olduount-l/_oldmount-t proc/proc/proc#network#let';s change hostname hostname tainer#启动环回地址链接set lo up#启动veth设备的IP链路集c$cpid#let为veth提供IP地址地址add 172.17.42.3/16 dev c$cpid#将veth设置为默认网关ip路由通过172.17.0.1添加默认值#这应该可以工作!#注意:DNS由于/etc/Resolution v.conf丢失8.8.8.8而无法工作。

上述类型的作弊是通过使用码头桥设置来实现的。之所以这样做,是因为在云实例上设置网桥不是一件容易的事;移动物理以太网设备会使实例暂时无法路由。Docker使用大量的iptables规则来设置NAT。

上面的内容非常接近Docker所做的事情,缺少的一大部分是启动覆盖文件系统上的“容器”,以便新PIVOT_ROOT中的更改不会影响基本映像。