初识Kubernetes

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

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

从一个开发者和单一的容器镜像,到无数开发者和庞大的容器集群,容器技术实现了从“容器”到“容器云”的飞跃,标志着它真正得到了市场和生态的认可。

而能够定义容器组织和管理规范的“容器编排”技术,则当仁不让地坐上了容器技术领域的“头把交椅”。而Kubernetes则是坐上了头把交椅的老大。

Kubernetes的技术起源

Kubernete技术理论基础得益于谷歌的Borg系统。Borg 系统,一直以来都被誉为 Google 公司内部最强大的“秘密武器”。虽然略显夸张,但这个说法倒不算是吹牛。

因为,Borg 要承担的责任,是承载 Google 公司整个基础设施的核心依赖。在 Google 公司已经公开发表的基础设施体系论文中,Borg 项目当仁不让地位居整个基础设施技术栈的最底层。

所以,Kubernetes 项目从一开始就比较幸运地站上了一个他人难以企及的高度。

Kubernetes的全局架构

控制节点(Master)

即Master 节点,由三个紧密协作的独立组件组合而成。

  • kube-apiserver:负责 API 服务;
  • kube-scheduler:负责调度;
  • kube-controller-manager:负责容器编排。
    而整个集群的持久化数据,则由 kube-apiserver 处理后保存在 Etcd 中。

计算节点(note)

计算节点上最核心的组件,就是kubelet。kubelet通过接口和规划跟其他组件打交道。

(1) kubelet 同容器运行时打交道。交互所依赖的,是一个称作 CRI(Container Runtime Interface)的远程调用接口,这个接口定义了容器运行时的各项核心操作,比如:启动一个容器需要的所有参数。也就是说,只要这个容器运行时能够运行标准的容器镜像,它就可以通过实现CRI接入到Kubernetes项目当中。

Container Runtime容器运行时,则通过 OCI 这个容器运行时规范同底层的 Linux 操作系统进行交互,即:把 CRI 请求翻译成对 Linux 操作系统的调用(操作 Linux Namespace 和 Cgroups 等)。

(2) kubelet 通过 gRPC 协议和 Device Plugin 的插件进行交互。这个插件,是 Kubernetes 项目用来管理 GPU 等宿主机物理设备的主要组件,也是基于 Kubernetes 项目进行机器学习训练、高性能作业支持等工作必须关注的功能。

(3) 调用网络插件Networking和存储插件Device Plugin为容器配置网络和持久化存储。这两个插件与 kubelet 进行交互的接口,分别是 CNI(Container Networking Interface)和 CSI(Container Storage Interface)。

Kubernetes核心功能全景

Kubernetes要解决的是什么问题?
实际上,这个问题到目前为止都没有固定的答案。因为在不同的发展阶段,Kubernetes 需要着重解决的问题是不同的。

可以从两个方面来回答:

  • 处理集群中的各种任务之间存在着各种各样的关系。
  • 处理应用运行形态的问题。

我们可以通过下面这幅图,按照这幅图的线索,来探索下Kubernetes的功能演进路线。

处理应用之间的关系

  • 首先遇到了容器间“紧密协作”关系的难题,于是就扩展到了 Pod;Pod之间可共享网络和存储等资源。
  • 有了 Pod 之后,我们希望能一次启动多个应用的实例,这样就需要 Deployment 这个 Pod 的多实例管理器;
  • 而有了这样一组相同的 Pod 后,我们又需要通过一个固定的 IP 地址和端口以负载均衡的方式访问它,于是就有了 Service。
  • 不同 Pod 之间不仅有“访问关系”,还要求在发起时加上授权信息。于是有了Secret。它其实是一个保存在 Etcd 里的键值对数据。这样,你把 Credential 信息以 Secret 的方式存在 Etcd 里,Kubernetes 就会在你指定的 Pod(比如,Web 应用的 Pod)启动时,自动把 Secret 里的数据以 Volume 的方式挂载到容器里。

处理应用的运行形态

  • 除了应用与应用之间的关系外,应用运行的形态是影响“如何容器化这个应用”的重要因素。为此,Kubernetes 定义了新的、基于 Pod 改进后的对象,这些称为编排对象。比如 Job,用来描述一次性运行的 Pod(比如,大数据任务);再比如 DaemonSet,用来描述每个宿主机上必须且只能运行一个副本的守护进程服务;又比如 CronJob,则用于描述定时任务等等。
  • 有了编排对象之后,还需要为这些编排对象提供一些服务,于是就有了服务对象。比如 Service、Secret、Horizontal Pod Autoscaler(自动水平扩展器)等。这些对象,会负责具体的平台级功能。

这种使用方法,就是所谓的“声明式 API”。这种 API 对应的“编排对象”和“服务对象”,都是 Kubernetes 项目中的 API 对象(API Object)。