浅谈Kubernetes
Kubernetes,简称k8s,是云原生生态的基石,是CNCF技术栈的核心。
注: CNCF即为云原生计算基金会,是一个开源的软件基金会,致力于云原生技术的普及及可持续发展。许多有名的项目都托管在这个社区当中,包括Docker、Kubernetes。
Kubernetes脱骨于Google的Borg系统,而Borg承载了Google公司整个基础设施的核心依赖,k8s在Borg体系的指导之下,在众多容器编排工具中脱颖而出。
为什么需要容器编排
一个Docker容器本质上是一个进程,当然处理不了太多的事情,在一个大型项目当中,可能会有成千上万个容器共同工作,如何处理容器之间复杂的关系让它们协同起来,是一个很棘手的问题。
于是类似于k8s这样的容器编排工具就应运而生。
用户的期望
作为用户,我们已经有了应用的容器镜像,我们希望k8s这样的工具,给我们: 在一个给定的集群上运行这个应用,并且提供路由网关、水平扩展、监控、备份、灾难恢复等一系列运维能力。
Kubernetes架构
图源自[1],展现了Kubernetes的全局架构。
k8s由Master和Node两种节点组成,分别是控制节点和计算节点。Master节点中有三个独立组件,分别是负责API服务的kube-apiserver、负责调度的kube-scheduler,以及负责容器编排的kube-controller-manager。整个集群的持久化数据,由kube-apiserver处理后保存在etcd中。
其中etcd是一个分布式的、高可用的、一致的KV存储数据库,基于raft共识算法实现,主要用于共享配置和服务发现。
计算节点上最核心的地方,是一个名为kubelet的组件,主要负责同容器运行时交互。这种交互依赖一个称作CRI(container runtime interface)的远程调用接口,这个接口定义了容器运行时的各项核心操作,比如启动一个容器需要的所有参数。
而容器运行时则通过OCI这个容器运行时规范同底层Linux系统进行交互,即把CRI请求翻译成对Linux系统的调用。
kubelet还通过gRPC协议同一个叫做Device Plugin的插件进行交互,这个插件是管理GPU等宿主机物理设备的主要组件。
kubelet还通过CNI(container networking interface)和CSI(container storage interface)接口调用网络插件和存储插件为容器配置网络和持久化存储。
Kubernetes核心能力与项目定位
在大规模集群中的各种任务之间运行,实际上存在各种各样的关系。这些关系的处理才是作业编排和管理系统最困难的地方。
这句话道出了Kubernetes核心能力和项目定位,来自于Borg论文中。
任务与任务之间的关系,诸如Web应用与数据库之间的访问关系,负载均衡器和后端服务之间的代理关系等等。
在容器之前,使用虚拟机来处理这种关系,将可能发生通信的任务部署在同一台虚拟机中,是”粗粒度”的,不仅如此,还需要手动维护守护进程。
而有了容器技术,可以将服务放在独立的容器中,容器可以被调度到集群中的任何一台机器上,它是”细粒度”的。
如何编排 & 调度呢?
Kubernetes以统一的方式抽象底层基础设施能力(比如计算、存储、网络),定义任务编排的各种关系(比如亲密关系、访问关系、代理关系),将这些抽象以声明式API的方式对外暴露,从而允许平台构建者基于这些抽象进一步构建自己的PaaS乃至任何上层平台。
Kubernetes对容器间的访问进行了抽象和分类,它总结出了一类常见的紧密交互的关系,即这些任务之间需要非常频繁地交互和访问,或者它们会直接通过本地文件交换信息。
在常规环境中,这些应用会被部署在同一台机器上,通过localhost进行通信,通过本地磁盘目录交换文件。
而在Kubernetes中,这些容器会被划分为一个Pod,Pod中的容器共享同一个Network Namespace、同一组Volumn,从而实现高效交换信息。Pod是Kubernetes中最基础的一个对象。
但是。对于容器来说,它的IP地址是不固定的,一个应用如何找到另一个应用的Pod呢?
Kubernetes的做法是给Pod绑定一个Service服务,而Service服务声明的IP地址等信息是固定不变的。Service服务作为Pod的代理入口,代替Pod对外暴露一个固定的网络地址。Service负责相应Pod的IP地址、端口等信息的自动更新、维护。
如果我们希望一次启动多个应用的实例,需要使用Deployment这个Pod的多实例管理器。
Secret是保存在etcd中的键值对数据,可以将授权信息(比如Web访问数据库时需要用户名和密码)存放在Secret对象中,Kubernetes就会在Web应用的Pod启动时,自动把Secret里的数据以Volumn的方式挂载到容器里。
声明式API
如何使用Kubernetes?
首先,通过一个任务编排对象,比如Pod、Job、CronJob等,描述你试图管理的应用;
然后,为它定义一些运维能力对象,比如Service、Ingress、Horizontal Pod Autoscaler(自动水平扩展器)等,这些对象会负责具体的运维能力侧功能。
这种使用方法就是”声明式API”。这种API对应的编排对象和服务对象,都是Kubernetes项目中的API对象。
题外话:
命令式API告诉系统它需要做什么,需要怎么做;而声明式API告诉系统我们想要什么,系统如何去完成是系统的事。声明式API及其优势可以查看参考文献[3].
声明式API是Kubernetes最核心的设计理念,正因为有了它,我们基于Kubernetes构建的上层平台才有了一致的编程范式和交互编程界面,才使得今天整个云原生生态中诞生了如此多的Kubernetes插件能力和扩展。
Kubernetes的使用
首先按照格式编写YAML文件,随后执行:
kubectl create -f xxx.yaml |
这样对应的容器就启动了。
参考文献
[1] 张磊. 深入剖析Kubernetes[M]. 第1版. 人民邮电出版社, 2021.3.
[2] Hu先生的Linux. ETCD介绍—etcd概念及原理方面分析[EB/OL]. [2023-08-29]. https://zhuanlan.zhihu.com/p/405811320.
[3] Docker_. 为什么说声明式API比命令式API更优雅?[EB/OL]. [2023-08-29]. https://blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/122890922.