kubernetes
容器的本质是进程,容器镜像就是这个系统里的“.exe”安装包,那么这个操作系统就是Kubernetes。
为什么要使用Kubernetes?
运行在大规模集群中的各种任务之间,实际上存在着各种各样的关系。这些关系的处理,才是作业编排和管理系统最困难的地方。
这种任务与任务之间的关系,在我们平常的各种技术场景中随处可见。比如,一个 Web 应用与数据库之间的访问关系,一个负载均衡器和它的后端服务之间的代理关系,一个门户应用与授权组件之间的调用关系。
如果使用虚拟机,经常会发现很多功能并不相关的应用被一股脑儿地部署在同一台虚拟机中,只是因为它们之间偶尔会互相发起几个 HTTP 请求。还得手动维护很多跟它协作的守护进程(Daemon),用来处理它的日志搜集、灾难恢复、数据备份等辅助工作。
由于容器的本质,只是一个进程而已,那些原先拥挤在同一个虚拟机里的各个应用、组件、守护进程,都可以被分别做成镜像,然后运行在一个个专属的容器中。它们之间互不干涉,拥有各自的资源配额,可以被调度在整个集群里的任何一台机器上。而这,正是一个 PaaS 系统最理想的工作状态,也是所谓“微服务”思想得以落地的先决条件。
Kubernetes 可扩展性极强,基于“声明式API与控制器模式”的插件体系。声明式API理论上可以对一切应用基础设施“能力”进行建模,而且开发插件的门槛极低,即自定义API资源与自定义控制器的编写。
Kubernetes 项目为用户提供的不仅限于一个容器编排工具,它真正的价值,乃在于提供了一套基于容器构建分布式系统的基础依赖。
Kubernetes核心思想
声明式API与控制器模式 - Infrastructure as Data
将任何一个底层基础设施的"能力"都建模为一份"数据",即 yaml 文件
"数据"中的内容是对该基础设施期望状态的描述
对"数据"的增删改查会触发控制器(Controller)执行对应的运维逻辑,以此来驱动底层基础设施向"数据"所定义的期望状态逼近
Kubernetes项目的本质
Kubernetes 项目其实只有2个部分:
对底层基础设施各种能力的声明式API定义
上述声明式API对应的控制器
Kubernetes架构
Kubernetes 项目的架构,由 Master 和 Node 两种节点组成,而这两种角色分别对应着控制节点和计算节点。
控制节点,即 Master 节点,由三个紧密协作的独立组件组合而成,它们分别是负责 API 服务的 kube-apiserver、负责调度的 kube-scheduler,以及负责容器编排的 kube-controller-manager。整个集群的持久化数据,则由 kube-apiserver 处理后保存在 Etcd 中。
计算节点上最核心的部分是 kubelet 的组件。kubelet 主要负责同容器运行时(比如 Docker 项目)打交道。而这个交互所依赖的,是一个称作 CRI(Container Runtime Interface)的远程调用接口,这个接口定义了容器运行时的各项核心操作,比如:启动一个容器需要的所有参数。kubelet 还通过 gRPC 协议同一个叫作 Device Plugin 的插件进行交互。这个插件,是 Kubernetes 项目用来管理 GPU 等宿主机物理设备的主要组件,也是基于 Kubernetes 项目进行机器学习训练、高性能作业支持等工作必须关注的功能。kubelet 的另一个重要功能,则是调用网络插件和存储插件为容器配置网络和持久化存储。这两个插件与 kubelet 进行交互的接口,分别是 CNI(Container Networking Interface)和 CSI(Container Storage Interface)。
功能
从容器这个最基础的概念出发,首先遇到了容器间“紧密协作”关系的难题,于是就扩展到了 Pod;有了 Pod 之后,我们希望能一次启动多个应用的实例,这样就需要 Deployment 这个 Pod 的多实例管理器;而有了这样一组相同的 Pod 后,我们又需要通过一个固定的 IP 地址和端口以负载均衡的方式访问它,于是就有了 Service。
如果现在两个不同 Pod 之间不仅有“访问关系”,还要求在发起时加上授权信息。Kubernetes 项目提供了一种叫作 Secret 的对象,它其实是一个保存在 Etcd 里的键值对数据。这样,你把 Credential 信息以 Secret 的方式存在 Etcd 里,Kubernetes 就会在你指定的 Pod(比如,Web 应用的 Pod)启动时,自动把 Secret 里的数据以 Volume 的方式挂载到容器里。这样,这个 Web 应用就可以访问数据库了。
Kubernetes还提供了基于 Pod 改进后的对象,比如 Job,用来描述一次性运行的 Pod(比如,大数据任务);再比如 DaemonSet,用来描述每个宿主机上必须且只能运行一个副本的守护进程服务;又比如 CronJob,则用于描述定时任务等等。
Q:对于一个容器来说,它的 IP 地址等信息不是固定的,那么 Web 应用又怎么找到数据库容器的 Pod 呢?
A:Kubernetes 项目的做法是给 Pod 绑定一个 Service 服务,而 Service 服务声明的 IP 地址等信息是“终生不变”的。这个Service 服务的主要作用,就是作为 Pod 的代理入口(Portal),从而代替 Pod 对外暴露一个固定的网络地址。
为什么我们需要Pod?
不是容器,Pod才是 Kubernetes 项目中的最小编排单位
可以这么理解 Pod 的本质:Pod 提供的是一种编排思想,Pod实际上是在扮演传统基础设施里“虚拟机”的角色;而容器,则是这个虚拟机里运行的用户程序。
假设有A、B、C具有“超亲密关系”的三个进程,它们之间基于 Socket 的通信和文件交换,这三个进程一定要运行在同一台机器上。由于受限于容器的“单进程模型”,这三个模块必须被分别制作成三个不同的容器。如果接下来用 Docker Swarm 对这三个容器往同一台服务器进行调度,可能会发生运行完2个容器后,第3个容器要运行时,这台服务器资源不够了。这就是一个典型的成组调度(gang scheduling)没有被妥善处理的例子。Swarm 这种单容器的工作方式,难以描述真实世界里复杂的应用架构,这也是 Swarm 项目无法成长起来的重要原因之一。
Pod
Pod 就是 Kubernetes 世界里的“应用”;而一个应用,可以由多个容器组成。
Pod 是一组容器的集合,是 k8s 最小部署单元,一个 Pod 内的容器是共享网络的。
Pod 的生命周期是短暂的,重启之后就是一个新的 Pod 实例了。
Controller
确保预期的 Pod 副本数量,无状态和有状态的应用部署,执行一次性和定时任务。
Service
定义一组 Pod 的访问规则。
由 Controller 创建 Pod 进行部署,通过 Service 对外提供访问服务。
使用kubeadm搭建k8s集群
Last updated
Was this helpful?