OS容器会打包整个应用程序栈的操作系统【示例LEMP技术栈,LEMP是指一组一起使用来运行动态网站或者服务器的开源软件,软件名称的首字母缩写:L代表Linux,E代表Nginx(Engine X),M代表MariaDB或MySQL,P代表PHP】。
应用容器通常每个容器会运行一个进程
PHP服务器(或者是PHP FPM)
Web服务器(Nginx)
MySQL
sudo apt install cgroup-tools
sudo apt install stress
此命令将创建一个新的执行上下文:
sudo unshare --fork --pid --mount-proc bash
unshare命令解除了进程的部分执行上下文的关联。unshare()允许进程(或线程)与当前和其他进程(或线程)共享的执行上下文解除关联。但是部分执行上下文(例如mount > namespace),当使用fork(2)或vfork(2)去创建新进程时,执行上下文,与此同时,其他部分(例如虚拟内存),可能在使用clone(2)创建进程或线程,通过显式请求共享虚拟内存。现在,使用cgcreate我们来创建一个控制组并定义两个控制器,一个在内存上,另一个在CPU上。
下一步是定义内存限制并使之生效:
echo 3000000 > /sys/fs/cgroup/memory/mygroup/memory.kmem.limit_in_bytes cgexec -g memory:mygroup bash
现在让我们压力测试一下我们创建的独立命名空间(包含内存限制)。
stress --vm 1 --vm-bytes 1G --timeout 10s
可以看到执行失败了,于是我们知道内存限制正常工作。如果我们在主机上做同样的事情(不要在16G RAM上模仿),测试永远不会失败,除非你真的没有足够的可用内存:
遵循这些步骤有利于你理解Linux工具(如CGroup和其他资源管理功能)是如何在Linux系统中创建和管理隔离的环境。libcontainer与这些工具交互以管理和运行Docker容器。
runC:在不使用Docker的情况下使用libcontainer2015年,Docker发布runC:一个轻量级,可移植的容器运行时。
runC实际上是一个直接利用libcontainer的命令行工具,无需通过Docker引擎。runC的目标是使标准容器随处可用。这个项目被捐赠给了Open Container Initiative,OCI。libcontainer存储库现已被存档。
实际上,libcontainer并没有被抛弃,而是被转移到了runC仓库。
让我们回到实践部分并使用runC创建一个容器。首先安装runC运行时:
让我们创建一个目录(/mycontainer),我们将导出镜像Busybox的内容。BusyBox[2]的大小介于1到5 Mb之间(取决于变体),在制作高效利用空间发行版的时候,是一个非常好的组成部分。BusyBox将许多常见UNIX实用程序的微小版本组合到一个小的可执行文件中。它提供了你通常在GNU fileutils,shellutils等中找到的大多数实用程序的替代工具。BusyBox中的工具程序通常比它们包含所有功能的GNU版本有更少的选项;但包含的选项提供了大部分你所需要的功能,与GNU的对应版本非常相似。BusyBox为任何小型或嵌入式系统提供了相当完善的环境。 来源:Docker Hub。
使用runC命令,我们可以用提取的镜像和spec文件(config.json)来运行BusyBox容器。runc spec命令一开始会创建以下JSON文件:
{
"ociVersion": "1.0.1-dev",
"process": {
"terminal": true,
"user": {
"uid": 0,
"gid": 0
},
"args": [
"sh"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TERM=xterm"
],
"cwd": "/",
"capabilities": {
"bounding": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"effective": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"inheritable": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"permitted": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
],
"ambient": [
"CAP_AUDIT_WRITE",
"CAP_KILL",
"CAP_NET_BIND_SERVICE"
]
},
"rlimits": [
{
"type": "RLIMIT_NOFILE",
"hard": 1024,
"soft": 1024
}
],
"noNewPrivileges": true
},
"root": {
"path": "rootfs",
"readonly": true
},
"hostname": "runc",
"mounts": [
{
"destination": "/proc",
"type": "proc",
"source": "proc"
},
{
"destination": "/dev",
"type": "tmpfs",
"source": "tmpfs",
"options": [
"nosuid",
"strictatime",
"mode=755",
"size=65536k"
]
},
{
"destination": "/dev/pts",
"type": "devpts",
"source": "devpts",
"options": [
"nosuid",
"noexec",
"newinstance",
"ptmxmode=0666",
"mode=0620",
"gid=5"
]
},
{
"destination": "/dev/shm",
"type": "tmpfs",
"source": "shm",
"options": [
"nosuid",
"noexec",
"nodev",
"mode=1777",
"size=65536k"
]
},
{
"destination": "/dev/mqueue",
"type": "mqueue",
"source": "mqueue",
"options": [
"nosuid",
"noexec",
"nodev"
]
},
{
"destination": "/sys",
"type": "sysfs",
"source": "sysfs",
"options": [
"nosuid",
"noexec",
"nodev",
"ro"
]
},
{
"destination": "/sys/fs/cgroup",
"type": "cgroup",
"source": "cgroup",
"options": [
"nosuid",
"noexec",
"nodev",
"relatime",
"ro"
]
}
],
"linux": {
"resources": {
"devices": [
{
"allow": false,
"access": "rwm"
}
]
},
"namespaces": [
{
"type": "pid"
},
{
"type": "network"
},
{
"type": "ipc"
},
{
"type": "uts"
},
{
"type": "mount"
}
],
"maskedPaths": [
"/proc/kcore",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/sys/firmware",
"/proc/scsi"
],
"readonlyPaths": [
"/proc/asound",
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
}
}
另一个替代方案是使用“oci-runtime-tool”的子命令“oci-runtime-tool generate”,它包含很多选项帮助你做更多自定义配置。更多信息,请参阅runtime-tools[3]。使用生成的规范JSON文件,您可以自定义容器的运行时。例如,我们可以更改要执行的应用程序的参数。
让我们来看看原始config.json文件和新文件之间的差别:
现在让我们再次运行容器并观察到它在退出前休眠了10秒。行业标准的容器运行时
鉴于容器逐渐成为主流,容器生态系统中的不同参与者一直致力于标准化。标准化是自动化和总结最佳实践的关键。在将runC项目提供给OCI的同时,Docker在2016年开始使用containerd作为容器运行时,containerd可以与更底层运行时runC进行交互。
Cotnainerd完全支持启动OCI下的软件并管理这些软件的生命周期。 Containerd(以及其他像cri-o这样的运行时)都是使用runC来运行容器,但Containerd实现了其他更高级功能,如镜像管理和更高级API。
containerd与Docker和OCI运行时集成Containerd,Shim和RunC,这一切是如何一起工作的
runC建立在libcontainer之上,libcontainer是以前为Docker引擎提供动力的容器库。在1.11版之前,Docker引擎被用于管理卷,网络,容器,图像等。 现在,Docker架构被拆分成四个部分:
Docker引擎
containerd运行时
containerd-shim
和runC运行时。
Docker引擎创建容器(来自镜像)并将其传递给containerd
Containerd调用containerd-shim
Containerd-shim使用runC来运行容器
Containerd-shim可以让运行时(此处为runC)在启动容器后退出
runC可以在启动容器后退出,我们不必运行整个运行时进程。
即使Docker和/或容器死亡,containerd-shim也会保证stdin,stdout和stderr这些文件描述符为打开状态。
镜像传输和存储
容器运行和监控,
底层存储
网络附件
等等
sudo dockerd --add-runtime==
示例:
sudo apt-get install nvidia-container-runtime
sudo dockerd --add-runtime=nvidia=/usr/bin/nvidia-container-runtime
容器运行时接口
Kubernetes是当下最流行的容器编排系统之一。随着容器运行时数量的不断增加,Kubernetes目标是变得更加灵活,并且与更多的容器运行时(不仅仅是Docker)进行交互。最初,Kubernetes使用Docker运行时来运行容器,并且现在它仍然是默认的运行时。但是,CoreOS希望将Kubernetes与RKT运行时一起使用,并为Kubernetes提供补丁,以便将来此运行时可以用来替代Docker运行时。在添加新的容器运行时,Kubernetes不希望改变自己的代码库,于是它决定创建容器运行时接口(CRI或Container Runtime Interface),这是一组API和库,允许在Kubernetes中运行不同的容器运行时。Kubernetes通过CRI API与它支持的运行时进行交互。
以下是一些CRI插件:CRI-O:是为Kubernetes CRI接口创建的第一个容器运行时。 cri-o不是为了取代Docker,而是可以在Kubernetes的特定上下文中使用它而不是Docker运行时。
Containerd CRI:使用cri-containerd,用户可以使用containerd作为底层运行时运行Kubernetes集群,而无需安装Docker。
gVisor CRI:gVisor是由Google开发的项目,它在用户空间中实现了大约200个Linux系统调用,与直接在Linux内核上运行的Docker容器(使用命名空间隔离)相比,具有更高的安全性。Google Cloud App Engine使用gVisor CRI实现客户之间的隔离。
gVisro运行时与Docker和Kubernetes集成,使得运行沙盒容器变得简单。CRI-O Kata容器:Kata Containers是一个开源项目,用于构建轻量级虚拟机,可插入容器生态系统。 CRI-O Kata容器允许在Kubernetes上运行Kata Containers来替代默认的Docker运行时。
Moby项目
建立一个单体的Docker平台的项目在某种程度上已被抛弃,并催生了Moby项目,在这个项目中,Docker被拆分成多个组件,例如RunC。
来源:Solomon Hykes TwitterMoby是一个将Docker开发进行组织和模块化的项目。它是一个开发和生产的生态系统。 Docker的常规用户很难意识到变化。
资料来源:Solomon Hykes TwitterMoby帮助开发和运行Docker CE和EE(Moby是Docker上游)以及为其他运行时和平台创建开发和生产环境。开放容器计划(The Open Containers Initiative)
正如我们所看到的,Docker将RunC捐赠给Open Container Initiative(OCI),但这项计划是什么?OCI是一个轻量级,开放型治理架构的组织,由Docker,CoreOS和容器行业的其他领导者于2015年发起。开放容器计划(OCI)旨在建立软件容器的通用标准,以避免容器生态系统内部可能出现的分裂和分化。
它包含两个规范:
runtime-spec:运行时规范
image-spec:镜像规范
https://github.com/moby/moby/commit/0db56e6c519b19ec16c6fbd12e3cee7dfa6018c5
http://www.busybox.net/
https://github.com/opencontainers/runtime-tools