更多互联网精彩资讯、工作效率提升关注【飞鱼在浪屿】(日更新)
对容器最初的理解是它们只是具有亚秒级启动时间的轻量级虚拟机。从互联网上很容易学习如何将 Python 或 Node.js 应用程序放入容器中的教程。但将容器视为虚拟机是一种过度简化,因为无法判断:
- 容器可以做什么,不能做什么
- 什么是容器的惯用用法,什么不是
- 在容器中运行什么是安全的,什么不是。
docker是最初学者的起点。但是 Docker 是一个做各种各样事情的庞然大物,docker run nginx表面上很简单性,具有欺骗性。网上的大多数Docker资料:
- 要么是浅的介绍性教程
- 或者对于新手来说难以消化的硬读物。
容器学习路径
以下学习顺序特别有用:
- Linux Containers - 学习低级实现细节。
- 容器镜像- 了解什么是镜像以及为什么需要它们。
- 容器管理器- 了解 Docker 如何帮助容器在单个主机上共存。
- Container Orchestrators - 了解 Kubernetes 如何协调集群中的容器。
- 非 Linux 容器- 了解替代实现来结束学习路线。
容器不是虚拟机
容器是一个隔离的(通过命名空间)和受限的(cgroups、capabilities、seccomp)进程。
上面的解释对理解容器有很大帮助。当然,它不是非常准确,但刚开始,它非常适合描述学习目标。
Linux 上启动进程,需要 fork/exec。但是要启动容器化进程,首先需要创建命名空间、配置 cgroups 等。或者,换句话说,为进程在里面运行准备一个盒子。一个容器运行时是一种特殊的(而较低级别)软件来创建这样的盒子。典型的容器运行时知道如何准备盒子,然后如何在其中启动容器化进程。并且由于大多数运行时都遵循通用规范,因此容器成为工作任务的标准单位。
最广泛使用的容器运行时是runc,(https://github.com/opencontainers/runc)。runc是一种常规的命令行工具,无需 Docker 或任何其他更高级别的容器化软件即可直接使用它!
containerd-shim是一种驻留在容器运行时(如runc和更高级别的容器管理器如containerd)下级的软件。
运行容器不需要镜像
...但是需要用容器来构建镜像。镜像和容器并不相等。要运行容器,运行时需要一个所谓的bundle,包括:
- config.json保存容器参数的文件(可执行文件的路径、环境变量等)
- 包含上述可执行文件和支持文件(如果有)的文件夹。
通常,bundle 文件夹包含类似于Linux 文件结构(/var, /usr, /lib, /etc, ...)。当 runc 启动一个带有这样一个包的容器时,里面的进程会得到一个根文件系统,它看起来很像 Linux 风格,Debian、CentOS 还是 Alpine。
但是这样的文件结构不是强制性的!所谓的scratch或distroless容器如今越来越流行,特别是因为更简单的容器让潜入安全漏洞的机会更少。
那么,如果不需要容器镜像来运行容器,为什么还需要容器镜像呢?
当每个容器获得根文件系统的副本时,空间需求会急剧增加。因此,可以有效地解决存储和分发问题。
你有没有想过是如何创建的?
Docker 推广的工作流让你以为是主要的,容器是次要的。docker run <image> 你所需要的图像运行的容器。但是,我们已经知道从技术上讲这是不正确的。实际上,您必须运行(临时的)容器来构建映像!
单主机容器管理器
发明真正的容器是为了增加一艘典型船舶可以装载的货物数量一样,容器为了服务器的资源利用率。
现在的服务器运行数十或数百个容器。因此,它们需要共存。如果容器运行时专注于单个容器生命周期,那么容器管理器则是专注于使多个容器在单个主机上愉快地共存。
容器管理器的主要职责包括拉取镜像、解包bundle、配置容器间网络、存储容器日志等。
你可能认为 Docker 就是这样一个管理器。但是,containerd更具代表性。与 runc 非常相似,containerd开始时是 Docker 的一个组件,但随后被提取到一个独立的项目中。在后台,containerd可以使用runc或任何其他实现containerd-shim接口的运行时。最酷的部分是,使用containerd,可以像使用 Docker 本身一样轻松地运行容器。
容器与 docker
最后,我们准备好了解 Docker!如果省略(现已弃用)Swarm,Docker 可以被视为如下:
- dockerd- 坐在containerd守护进程前面的更高级别的守护进程
- docker- 一个著名的命令行客户端与dockerd.
Docker 目前的主要任务是使容器工作流对开发人员友好。为了使开发人员更轻松,Docker 将所有主要容器用例组合在一个软件中:
- 构建/拉/推/扫描image
- 启动/暂停/检查/终止容器
- 创建网络/转发端口
- 挂载/卸载/删除卷
- 等等。
...但到 2021 年,几乎每个用例都编写了一个定制的软件(podman、buildah、skopeo、kaniko等),以提供替代的、通常是更好的解决方案。
多主机容器编排器
协调在单个主机上运行的容器很困难。但是跨多个主机协调容器的难度呈指数级增长。添加多主机容器编排,Docker 已经非常可怕
忽略臃肿守护进程的问题,Docker Swarm 看起来不错。但是另一个协调器Kubernetes更胜一筹!
Kubernetes 将多个服务器(节点)加入到一个协调的集群中,每个这样的节点都有一个名为kubelet的本地代理。kubelet负载启动Pods (容器的组合)。但kubelet不会自行完成。从历史上看,dockerd是做这个事情,但现在已被弃用,取而代之的是更通用的容器运行时接口 (CRI)。
容器编排器有很多任务。
- 如何将容器分组为更高级别的原语(Pod、ReplicaSet 等)?
- 如何将运行容器的节点互连到一个公共网络中?
- 如何提供服务发现?
- 等等等等……
Kubernetes 以及 Nomad 或 AWS ECS 等其他协调器使团队能够更轻松地创建隔离的服务。它帮助解决了许多管理问题,尤其是对大公司而言。但是它产生了许多在传统的基于 VM 的设置中不存在的新技术问题!事实证明,管理大量分布式服务非常具有挑战性。这就是 Cloud Native 项目诞生原因。
容器是虚拟机
现在,当了解了容器实现和使用,是时候告诉真相。容器不是 Linux 进程!
Linux 容器在技术上也不是进程。它们是在相对孤立和受限的环境,可以在其中运行一个或多个进程。
按照上述定义,使用命名空间和 cgroup 以外的机制来实现某些容器。而且确实有像 Kata 容器这样的项目,使用真正的虚拟机作为容器!对于 OCI 运行时规范、OCI 图像规范或 Kubernetes CRI 等开放标准,基于 VM 的容器可以被更高级的工具(如containerd和 Kubernetes)使用,而无需进行重大调整。
结论
仅使用 Docker 或 Kubernetes 等高级工具来学习容器是不够的。容器宇宙世界是复杂的,只从一端接近它会留下太多的灰色区域。
有用的方法是从更广泛的角度看待生态系统,将其分解为层,然后从底层开始一个一个地处理它们,并利用在每一步中获得的知识:
- 容器运行时 - Linux 命名空间和 cgroup。
- 容器镜像 - 为什么以及如何。
- 容器管理器 - 使容器在单个主机上共存。
- Container Orchestrators - 将多个主机组合成一个集群。
- 容器标准 - 概括容器的知识。
本文暂时没有评论,来添加一个吧(●'◡'●)