大家好,我是比特桃!随着微服务架构越来越流行,大规模的微服务容器编排成了一件具有挑战的事情。在这次容器化云原生的发展中,Docker 成了容器化的赢家,而 Kubernetes 则成为了容器编排的赢家。k8s 是 Kubernetes 的简称,只因为 K 和 s 中间有8个字符。或许你还会看到 k3s ,这是轻量级的 Kubernetes,甚至可以跑在树莓派中。
计算机的核心就是抽象,操作系统的抽象,让普罗大众用起来了电脑。面向对象的抽象,让软件开发人员更容易设计复杂系统。容器化的抽象,使得应用可以轻松的在云平台中提服务。当我们容器过于繁杂,上百上千的时候,不免就需要一个工具可以对这些容器进行编排控制。不可否认的是,如果你的应用并没有存在容器太多,也不存在高并发分布式的情况下。你或许并不需要 k8s,这被称为 YAGNI 理论,不知道则可以不用。当然了,即便是我们实际项目并不需要 k8s,但学习跟进一下这个技术也是很有必要的。
Kubernetes 孵化于 Google 公司,并开源给了 CNCF(云原生基金会)。可在不同的服务器环境中,进行统一的容器编排部署,确保容器的高可用、高性能、可扩展、可恢复。下图为 k8s 一个集群的基础架构,主要包含两大部分:控制节点、工作节点。
控制节点相当于整个集群的大管家,负责协调调度工作节点、以及与外界交互的部分。我们连接 k8s 的方式有两种,分别是Restful API 接口、KubeCLI命令行,通过yaml格式或json格式来进行沟通。而控制节点中主要包含了:控制管理器、调度器、etcd。ControllerManager负责运行管理集群状态控制器;Scheduler负责将pod调度到集群中的工作节点上;etcd是一个分布式key/value存储,用来存储和检索有关集群的信息。控制节点的 API Server 则是与工作节点交互的接口。
工作节点主要包含:kubelet、kube-proxy。kubelet是在每个工作节点上运行的守护进程,他负责与控制平面通讯;kube-proxy是每个工作节点上运行的网络代理,他负责将流量路由到正确的pod。
Kubernetes 始终是个工具类软件而已,在使用角度来看,它和 Docker 类的工具并无两样。都只是协助业务提供了各种功能的调用,但本身并不具备提供服务的能力。所以在面对这类软件的时候,应该先了解它都具备什么样的功能调用,这样我们才知道自己需要他为我们做什么。
k8s 是针对容器的更高层次抽象,所以它的最小单位是 pod,一个可以包含多个容器的盒子。这里额外插入一个 k8s 世界中的一个重要理念:声明式无状态。我们和 k8s 通过 API 或 kubectl 沟通的时候,是一种声明式的方式告诉他的。也就是说,你只需要告诉 k8s 你期望最终的效果是什么样的,至于 k8s 怎么做,你不用管。并且 pod 也是一种无状态的,相同的一个 pod,他们的 ip 也不一样。即便崩溃后,k8s 重新新建了一个 pod 仍然不会记录上一个 pod的任何内容,ip也会变。所以这种声明式无状态的思想,要贯彻使用 k8s 的全过程。
Pod 既然这么容易变,那 pod 之间是如何调用的呢?我们可以使用 k8s 的service,一个 service 是一个静态的ip,可以索引它下面所有的 pod。
在当我们想在用户浏览器中使用 k8s 集群所提供的应用时,我们并不希望用户可以直接访问 service,因为它是我们内部沟通的一个组件。所以可以通过 Ingress 组件来对外提供服务,它再去转发到具体的 Service 中。
通常,开发和部署在不同环境下需要不同的配置。在 Spring 开发中,我们会用 profile 来区分。而在 k8s 中,提供了配置文件和一些敏感的用户名密码信息的组件,供应用配置使用。ConfigMap 存储非敏感的配置信息;Secret 存储加密后的配置信息。
如 Docker 容器一样,k8s 也提供了持久化的功能。比如数据库 pod 如果不持久化的话,就会存在数据丢失的问题。Volume 允许我们映射本地或远程的持久化路径地址,进行数据持久化。正如之前所说的,k8s 理念是无状态的,所以它本身并不提供任何数据的持久化。所有持久化的工作都需要我们自己完成。
真正在使用 k8s 的时候,我们其实很少会主动管理一个 pod。试想一下,如果做个分布式的部署,还需要每个工作节点都单独部署管理,那和 Docker 还有什么区别。所以我们会用 k8s 提供的 Deployment 组件,它可以直接声明我们想要的 pod,并且也指明了分布式部署的数量。并且它也提供了固定的 IP 以及负载均衡的功能。在无状态的微服务应用中,我们可以任意声明想要多少个 replica 当做该容器的替补。但如果我们部署数据库,用了 Volume 使其成为了有状态的 pod,则需要使用 StatefulSet 组件。它会保障数据库的读取和写入同步,以便不会出现数据库不同步的情况。虽然 k8s 为了兼容数据库这种场景提供了 StatefulSet 组件来支持有状态的服务。但其实有状态的服务使用外部托管,而不使用 k8s 去做也是一种常见的做法,因为 k8s 的主要能力就是无状态。
现在,我们已经了解了 k8s 的作用及基础架构。也明白了这个工具类的软件,都提供了什么样的功能组件。我们只需要使用这些组件的组合,通过编写 yaml 文件,就可以完成分布式应用的部署。
本文简明扼要的阐述了 k8s 中,所涉及的各种概念及理论。而后续的实操篇将介绍 minikube 及服务器中的使用,如果感觉理论篇不错的话欢迎阅读后面的文章。