1.2 | Kubernetes:容器技术
此文是一篇大杂烩,记录一些对我很有用处的新知识。主要包括容器相关概念、实现原理、相关标准等。最大的感触就是 Golang 才是云时代的语言,很多容器相关软件的开发语言是用的 Golang。
Let’s go!
什么是容器
容器就是将软件打包成标准化单元,以用于开发、交付和部署。简单说就是:容器可以被当做一个盒子,盒子里面装了软件运行所需环境、软件包,我们拿到这个盒子就能把所需软件跑起来。
容器的实现原理
https://segmentfault.com/a/1190000009732550
Namespace
Cgroup
容器与虚拟机对比
- 容器是一个应用层抽象,用于将代码和依赖资源打包在一起。 多个容器可以在同一台机器上运行,共享操作系统内核,但各自作为独立的进程在用户空间中运行 。与虚拟机相比, 容器占用的空间较少(容器镜像大小通常只有几十兆),瞬间就能完成启动 。
- 虚拟机 (VM) 是一个物理硬件层抽象,用于将一台服务器变成多台服务器。 管理程序允许多个 VM 在一台机器上运行。每个VM都包含一整套操作系统、一个或多个应用、必要的二进制文件和库资源,因此 占用大量空间 。而且 VM 启动也十分缓慢 。
虚拟机更擅长于彻底隔离整个运行环境。例如,云服务提供商通常采用虚拟机技术隔离不同的用户。而 Docker通常用于隔离不同的应用 ,例如前端,后端以及数据库。
容器与虚拟机 (VM) 总结
换言之,容器具有如下优势:
- 极其轻量:只打包了必要的Bin/Lib;
- 秒级部署:根据镜像的不同,容器的部署大概在毫秒与秒之间(比虚拟机强很多);
- 易于移植:一次构建,随处部署;
- 弹性伸缩:Kubernetes、Swam、Mesos这类开源、方便、好使的容器管理平台有着非常强大的弹性管理能力。
容器的标准化
2015年,由Google,Docker、CoreOS等厂商联合发起的OCI(Open Container Initiative)组织成立了,并于2016年4月推出了第一个开放容器标准。标准主要包括runtime运行时标准和image镜像标准。
标准的推出,有助于替成长中市场带来稳定性,让企业能放心采用容器技术,用户在打包、部署应用程序后,可以自由选择不同的容器Runtime;同时,镜像打包、建立、认证、部署、命名也都能按照统一的规范来做。
两种标准主要包含以下内容:
容器运行时标准 (runtime spec)
- creating:使用 create 命令创建容器,这个过程称为创建中
- created:容器创建出来,但是还没有运行,表示镜像和配置没有错误,容器能够运行在当前平台
- running:容器的运行状态,里面的进程处于 up 状态,正在执行用户设定的任务
- stopped:容器运行完成,或者运行出错,或者 stop 命令之后,容器处于暂停状态。这个状态,容器还有很多信息保存在平台中,并没有完全被删除
容器镜像标准(image spec)
- 文件系统:以 layer 保存的文件系统,每个 layer 保存了和上层之间变化的部分,layer 应该保存哪些文件,怎么表示增加、修改和删除的文件等;
- config 文件:保存了文件系统的层级信息(每个层级的 hash 值,以及历史信息),以及容器运行时需要的一些信息(比如环境变量、工作目录、命令参数、mount 列表),指定了镜像在某个特定平台和系统的配置。比较接近我们使用 docker inspect
看到的内容; - manifest 文件:镜像的 config 文件索引,有哪些 layer,额外的 annotation 信息,manifest 文件中保存了很多和当前平台有关的信息;
- index 文件:可选的文件,指向不同平台的 manifest 文件,这个文件能保证一个镜像可以跨平台使用,每个平台拥有不同的 manifest 文件,使用 index 作为索引。
容器与Docker
容器就是 Docker,Docker 就是容器吗?
答案很明显是否,还有很多其他的容器运行时。
以下3个容器引擎基本上基于 Go 语言开发
它们 2019 年的市场分额如下:
什么是 podman
之前总是听有文章说,docker 快要被替代了,替代品是 podman。那 podman 又是一个什么东西呢?
What is Podman?
Podman is a daemonless container engine for developing, managing, and running OCI Containers on your Linux System. Containers can either be run as root or in rootless mode. Simply put: alias docker=podman.
podman 与 docker 的区别
- docker 需要在我们的系统上运行一个守护进程(docker daemon),而podman 不需要
- 启动容器的方式不同:
docker cli 命令通过API跟 Docker Engine(引擎)交互告诉它我想创建一个container,然后docker Engine才会调用OCI container runtime(runc)来启动一个container。这代表container的process(进程)不会是Docker CLI的child process(子进程),而是Docker Engine的child process。Podman是直接给OCI containner runtime(runc)进行交互来创建container的,所以container process直接是podman的child process。 - 因为docke有docker daemon,所以docker启动的容器支持–restart策略,但是podman不支持,如果在k8s中就不存在这个问题,我们可以设置pod的重启策略,在系统中我们可以采用编写systemd服务来完成自启动
- docker需要使用root用户来创建容器,但是podman不需要
为什么不使用 docker daemon 模式?
在Docker实践中,很多人应该都遇到过开机重启时,由于Docker守护程序在占用多核CPU使用100%C使用的情况,此时所有容器都无法正常工作,所有服务都不能用。很悲催的是这事儿虫虫也遇到了,之前虫虫利用Docker重构WP博客的新架构( http://ijz.me )。由于VPS机器不是很稳定,时常会重启,重启时候就会遇到这个事情,VPS负载很高,容器都没有起来,网站就无法访问了。解决唯一方法只能杀掉所有容器并重启守护进程,才能恢复。经过了解该问题是由于Docker守护进程引起,而且Docker守护进程是以root特权权限启动的,是一个安全问题。
为什么会有 podman
podman是OCI计划下的工具。还有另外两个工具,它们三者各司其职,配合完成Docker所有的功能和新扩展功能,并且对docker的问题进行了改良:
- 包括不需要守护程序或访问有root权限的组;
- 容器架构基于fork/exec模型创建容器,更加安全可靠;
- 所以是更先进、高效和安全的下一代容器容器工具。
Buildah
Buildah是套件中的Build工具,用来构建OCI镜像。虽然Podman也可以用户构建Docker镜像,但是构建速度超慢,并且默认情况下使用vfs存储驱动程序会消耗大量磁盘空间。 而buildah bud(使用Dockerfile构建)非常快,并使用覆盖存储驱动程序,可以节约大量的空间。
Skopeo
Skopeo是套件中镜像管理工具,允许我们通过推,拉和复制镜像来处理Docker和OC镜像。
Buildah构建容器,Podman运行容器,Skopeo传输容器镜像。这些通过在Github容器组织维护和开源。套件下的工具都无需运行守护进程,并且大多数情况下也不需要root访问权限。
Podman和Buildah之间的一个主要区别是他们的容器概念。 Podman可允许用户创建”传统容器”。Buildah容器作用是给容器添加一些特有的内容而构建容器,Buildah容器是过程容器,编译完成就消失,不能用来跑服务 。简而言之,buildah run命令模拟Dockerfile中的RUN命令,而podman run命令则模拟功能中的docker run命令。
总之,Buildah是创建OCI镜像的有效方式,而Podman允许我们使用熟悉的容器cli命令在生产环境中管理和维护这些镜像和容器。
CRI与OCI的区别
Open Container Initiative,也就是常说的OCI,是由多家公司共同成立的项目,并由linux基金会进行管理,致力于container runtime的标准的制定和runc的开发等工作。所谓container runtime,主要负责的是容器的生命周期的管理。oci的runtime spec标准中对于容器的状态描述,以及对于容器的创建、删除、查看等操作进行了定义。
在k8s 1.5版本之后,kubernetes推出了自己的运行时接口api–CRI(container runtime interface)。cri接口的推出,隔离了各个容器引擎之间的差异,而通过统一的接口与各个容器引擎之间进行互动。
与oci不同,cri与kubernetes的概念更加贴合,并紧密绑定。cri不仅定义了容器的生命周期的管理,还引入了k8s中pod的概念,并定义了管理pod的生命周期。在kubernetes中,pod是由一组进行了资源限制的,在隔离环境中的容器组成。而这个隔离环境,称之为PodSandbox。在cri开始之初,主要是支持docker和rkt两种。其中kubelet是通过cri接口,调用docker-shim,并进一步调用docker api实现的。
后来,docker独立出来了containerd,kubernetes也顺应潮流,孵化了cri-containerd项目,用以将containerd接入到cri的标准中。
为了进一步与oci进行兼容,kubernetes还孵化了cri-o,成为了架设在cri和oci之间的一座桥梁。通过这种方式,可以方便更多符合oci标准的容器运行时,接入kubernetes进行集成使用。可以预见到,通过cri-o,kubernetes在使用的兼容性和广泛性上将会得到进一步加强
Reference
1.2 | Kubernetes:容器技术