1.先谈容器。

一个“容器”,实践上是一个由Linux Namespace、Linux Cgroups 和 rootfs 三种技术构建出来的进程的隔离环境。

一个正在运行的linux容器,其实可以被“一分为二”地看待:

  1. 一组联合挂载在/var/lib/docker/overlay2下的rootfs,这部分我们称为“容器镜像”(Container Images),是容器的静态视图;
  2. 一个由Namespace+Cgroups构建的隔离环境,这一部分我们称为”容器运行时“(Container Runtime),是容器的动态视图。

rootfs(根文件系统)为挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的”容器镜像“

rootfs由如下s三个部分组成的。 

容器 命令权限 容器rootfs_linux

 2.浅谈kubernetes

容器就从一个开发者手里的小工具,一跃成为了云计算领域的绝对主角;而能够定义容器组织和管理规范的“容器编排”技术,则当仁不让地坐上了容器技术领域的“头把交椅”。

容器 命令权限 容器rootfs_Pod_02

kubernetes是由master节点和node节点组成,也就是控制节点和计算节点。

其中。控制节点(Master)由三个紧密协作的独立组件组合而成,它们分别是负责API服务的kube-apiserver、负责调度的kube-scheduler,以及负责容器编排的kube-controller-manager。整个集群的持久化数据则由kube-apiserver处理后保存在Etcd中。

而计算节点最核心的部分,则是一个叫作kubelet的组件。

在kubernetes项目中,kubelet通过一个称作CRI(Container Runtime Interface)的远程调用接口来进行交互的,这个接口定义了容器运行时的各项核心操作,这说明kubernetes并不需要知道,你用的是什么容器进行时,比如docker项目,新出来的container项目等等,或者你用的什么技术。只要你可以运行一个标准的容器镜像,他就可以通过实现CRI接入到你的容器中,并得到你所启动的容器的所有参数。

而 kubelet 的另一个重要功能,则是调用网络插件和存储插件为容器配置网络和持久化存储。这两个插件与 kubelet 进行交互的接口,分别是 CNI(Container Networking Interface)和 CSI(Container Storage Interface)。

到这里我们就可以看出kubernetes项目从一开始就没有把docker项目当成他的核心项目,而是巧妙的设置了很多的接口用来连接容器,这样的话,就算几十年后docker遗弃了 。只要新的容器运行时项目编写的是标准的容器镜像,他们也可以通过接口服务来进行编排。而同时期的其他”容器云项目“基本都是把当时最火的docker项目作为了自己最核心的项目,只要docker项目没办法满足新时代的技术要求时,那他们的产品也就没有用了。

3.kubernetes作业编排和管理系统的实现

其实对于一个容器编排工具,最困难的地方并不是连接到容器中去,真正困难的是:运行在大规模集群中的各种任务之间,实际上存在着各种各样的关系。这些关系的处理,才是作业编排和管理系统最困难的地方。

这种任务与任务之间的关系,在我们平常的各种技术场景中随处可见。比如,一个 Web 应用与数据库之间的访问关系,一个负载均衡器和它的后端服务之间的代理关系,一个门户应用与授权组件之间的调用关系。

更进一步地说,同属于一个服务单位的不同功能之间,也完全可能存在这样的关系。比如,一个 Web 应用与日志搜集组件之间的文件交换关系。

而docker compose和swarm也是可以通过”link“解决的。

DB_NAME=/web/db
    DB_PORT=tcp://172.17.0.5:5432
    DB_PORT_5432_TCP=tcp://172.17.0.5:5432
    DB_PORT_5432_TCP_PROTO=tcp
    DB_PORT_5432_TCP_PORT=5432
    DB_PORT_5432_TCP_ADDR=172.17.0.5

但是只有一个”link“ 想要满足我们上面的所有类型的关系,而不仅仅是web和db之间的联系,就显得太过于简单了,而且还要满足未来的各种类型的联系,这样看的话,docker得compose和swarm就有些不合适了。

所以,Kubernetes 项目最主要的设计思想是,从更宏观的角度,以统一的方式来定义任务之间的各种关系,并且为将来支持更多种类的关系留有余地。

容器 命令权限 容器rootfs_java_03

 按照这幅图的线索,我们从容器这个最基础的概念出发,首先遇到了容器间“紧密协作”关系的难题,于是就扩展到了 Pod;有了 Pod 之后,我们希望能一次启动多个应用的实例,这样就需要 Deployment 这个 Pod 的多实例管理器;而有了这样一组相同的 Pod 后,我们又需要通过一个固定的 IP 地址和端口以负载均衡的方式访问它,于是就有了 Service。

可是,如果现在两个不同 Pod 之间不仅有“访问关系”,还要求在发起时加上授权信息。最典型的例子就是 Web 应用对数据库访问时需要 Credential(数据库的用户名和密码)信息。那么,在 Kubernetes 中这样的关系又如何处理呢?

Kubernetes 项目提供了一种叫作 Secret 的对象,它其实是一个保存在 Etcd 里的键值对数据。这样,你把 Credential 信息以 Secret 的方式存在 Etcd 里,Kubernetes 就会在你指定的 Pod(比如,Web 应用的 Pod)启动时,自动把 Secret 里的数据以 Volume 的方式挂载到容器里。这样,这个 Web 应用就可以访问数据库了。

除了应用与应用之间的关系外,应用运行的形态是影响“如何容器化这个应用”的第二个重要因素。

为此,Kubernetes 定义了新的、基于 Pod 改进后的对象。比如 Job,用来描述一次性运行的 Pod(比如,大数据任务);再比如 DaemonSet,用来描述每个宿主机上必须且只能运行一个副本的守护进程服务;又比如 CronJob,则用于描述定时任务等等。

参看文献:

《深入解剖Kubernetes》张磊注