kubernetes简介

1. 概述

目前,越来越多的企业和个人热衷于容器技术,因而如何对容器进行编排显得越来越重要。目前最具代表性的容器编排工具,当属 Docker 公司的 Compose+Swarm 组合和Google和Redhat公司共同主导的Kubernetes项目。
  Kubernetes 项目的理论基础来源于Google 于2015年4月发表的Borg论文,Borg 承载了 Google 公司整个基础设施的核心依赖。正因为Kubernetes 是在 Borg 体系的指导下进行的设计,相对于Swarm 的“稚嫩”和 Mesos 社区的“老迈”,它体现出了一种独有的“先进性”与“完备性”。

2. 架构

kubernetes简介-LMLPHP
  kubernetes与它的原型项目brog类似,都有Master和Node两种节点组成,这两种角色分别对应着控制节点和计算节点。

  1. 控制节点
      控制节点,即Master节点,由三个紧密协作的独立组件组成。它们分别是负责 API 服务的 kube-apiserver、负责调度的 kube-scheduler,以及负责容器编排的 kube-controller-manager。整个集群的持久化数据,则由 kube-apiserver 处理后保存在 Ectd 中。
  2. 计算节点
      计算节点上最核心的部分是kubelet组件,它主要负责同容器运行时(比如 Docker 项目)打交道。它与容器运行时的交互是通过 CRI(Container Runtime Interface)这个远程调用接口来实现的,这个接口定义了容器运行时的各项核心操作,比如:启动一个容器需要的所有参数。
      具体的容器运行时,比如 Docker 项目,则一般通过 OCI 这个容器运行时规范同底层的 Linux 操作系统进行交互,即把 CRI 请求翻译成对 Linux 操作系统的调用(操作Linux Namespace 和 Cgroups 等)。
      kubelet 还通过 gRPC 协议同一个叫作 Device Plugin 的插件进行交互。这个插件,是 Kubernetes 项目用来管理 GPU等宿主机物理设备的主要组件,也是基于Kubernetes 项目进行机器学习训练、高性能作业支持等工作必须关注的功能。
      kubelet 的另一个重要功能,则是调用网络插件和存储插件为容器配置网络和持久化存储。这两个插件与 kubelet 进行交互的接口,分别是 CNI(Container Networking Interface和CSI(Container Storage Interface)。

3. 应用间关系的描述

容器之间的关系,在我们平常的各种技术场景中到处可见。比如,一个 Web 应用与数据库之间的访问关系,一个负载均衡器和它的后端服务之间的代理关系,一个门户应用与授权组件之间的调用关系。更进一步地说,同属于一个服务单位的不同功能之间,也完全可能存在这样的关系。比如,一个 Web 应用与日志搜集组件之间的文件交换关系。
  在容器技术普及之前,传统虚拟机环境对这种关系的处理方法都是比较“粗粒度”的。你会经常发现很多功能并不相关的应用被一股脑儿地部署在同一台虚拟机中,只是因为它们之间偶尔会互相发起几个 HTTP 请求。
  而Kubernetes 从更宏观的角度,以统一的方式来定义任务之间的各种关系,并且为将来支持更多种类的关系留有余地。比如下边两个场景:

  • kubernetes 项目对容器间的“访问”进行了分类,首先总结出了一类非常常见的“紧密交互”的关系,在 Kubernetes 项目中,这些容器则会被划分为一个“Pod”,Pod 里的容器共享同一个 Network Namespace、同一组数据卷,从而达到高效率交换信息的目的。
  • 还有一种常见的需求,比如 Web 应用与数据库之间的访问关系,Kubernetes 则提供了一种叫作“Service”的服务。Kubernetes给Pod 绑定一个 Service 服务,而 Service 服务声明的 IP 地址等信息是“终生不变”的。这个Service 服务的主要作用,就是作为 Pod 的代理(Portal),从而代替 Pod 对外暴露一个固定的网络地址。对于 Web 应用的 Pod 来说,它需要关心的就是数据库Pod 的 Service 信息,而不必去维护代理Pod的地址、端口等信息,这交给Kubernetes来完成。

围绕着容器和 Pod 不断的扩展,我们能得出如下所示的一幅Kubernetes 核心功能的“全景图”。
kubernetes简介-LMLPHP
  根据这幅图,我们从容器这个最基础的概念出发,首先遇到了容器间“紧密协作”关系的难题,于是就扩展到了 Pod;有了 Pod 之后,我们希望能一次启动多个应用的实例,这样就需要 Deployment 这个 Pod 的多实例管理器;而有了这样一组相同的 Pod 后,我们又需要通过一个固定的 IP 地址和端口以负载均衡的方式访问它,于是就有了 Service。

4. 容器启动过程

在 Kubernetes 项目中,一般是通过“声明式API”来部署应用,具体如下所示:

  • 首先,通过一个“编排对象”,比如Pod、Job、CronJob 等,来描述你试图管理的应用;
  • 然后,再为它定义一些“服务对象”,比如Service、Secret等。这些对象,会负责具体的平台级功能。
      以上的“编排对象”和“服务对象”,都是 Kubernetes 项目中的 API 对象。
      现在以运行一个Nginx服务为例(需要运行两个完全相同的 Nginx 副本,以负载均衡的方式共同对外提供服务),来说明Kubernetes 是如何启动一个容器化任务的。
    首先需要编写一个如下所示的yaml文件(比如名为nginx-deployment.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
	name: nginx-deployment
	labels:
		app: nginx
spec:
	replicas: 2
	selector:
		matchLabels:
			app: nginx
	template:
		metadata:
			labels:
				app: nginx
		spec:
			containers:
				name: nginx
				image: nginx:1.7.9
				ports:
					containerPort: 80

在上面这个 YAML 文件中,我们定义了一个 Deployment 对象,它的主体部分(spec.template )是一个使用 Nginx 镜像的 Pod,而这个 Pod 的副本数是 2(replicas=2)。
然后执行:

kubectl create -f nginx-deployment.yaml

根据以上几部分的论述可以看出,Kubernetes 的本质,是为一个为用户提供具有普遍意义的容器编排工具。但是它不仅仅是一个工具,它真正的价值,还在于提供了一套基于容器构建分布式系统的基础依赖。

10-07 18:29