本篇文章主要是对k8s的名词进行一些解释,对组件和架构两个方向去切入。
组件
Node和Pod
下图矩形是node,node包含两个pod。一个是my-app(应用程序),一个是DB(数据库)

一个node可以由多个pod。
pod可以放多个容器去运行,但是为了降低耦合度,一般是一个pod里面运行一个容器。
Service和Ingress
Service

pod和pod之间通过IP进行通讯,但是pod死亡以后,新的pod会获取新的ip,那这样的话,就会很复杂,比如上图连接的数据库pod死了,那我又得重新配置,很麻烦。所以这个IP是永久的,不变的。
Ingress

对于自己的应用,我们需要暴露出去,让浏览器能够访问。但是对于数据库内部访问足以,这要暴露出去,不是没事找事吗。
my-app的外部URL(service)基本都不怎么用,一般用来做测试。暴露出去http:my-app-ip:port是一个网址,例如http:10.1.3.4:80,这样不合适,一般是网址的形式,例如https:my-app.com
那my-app的请求就先到达Ingress,由ingress去转发。
Configmap和 Secret
Configmap

你现在DB的service是mongo-db-service,现在你要改了,改成下面的mongo-db。

改了之后可麻烦了,你要重新构建这个应用程序,然后推送到仓库,接着在弄进你的pod。那有没有办法解决这个问题呢?有,那就是Configmap

你的配置数据,例如数据库的URL那就直接放在ConfigMap,如果你要修改的话,可以在ConfigMap修改。
ConfigMap就是存放外部配置的组件。
Secret
想一个问题,你的数据库账号密码能不能刚在ConfigMap呢?
答案是能!但有安全风险!有安全风险,那怎么办?
那就放在一个加密的组件Secret。

Secret和ConfigMap功能差不多,你可以认为是ConfigMap的pro max版本。用来存储机密数据。
Volumes
数据存储也是很重要的。

看上图的DB会产生一些数据,这些数据在pod重启之后就会“死掉”。数据无价,数据可是很重要的东西。重启就丢掉了。那怎么能行呢?肯定要一个持久化存储的东西,这就是Volumes。

Volumes基本原理是将硬盘驱动器的物理存储连接到pod,并且可以存储在本地计算机上(也就是可以和pod运行的同一服务器节点上),当然也可以云存储。Volumes不属于k8s集群,所以你只需要对它进行外部引用。
Deployment and StatefulSet
Deployment

如果my-app这个pod挂掉了,在传统中,需要停机去修复,重新部署,在这期间用户是不能访问应用的。

在k8s中,就不一样的,my-app这样的pod多的是,挂掉一个,其他相同的pod顶上。其他节点的my-app(副本)就会去连接service(带有dns功能的持久性静态IP)。
service同时也是LoadBlance,可以实现负载均衡。把请求转发到最不忙的pod。
本节主角还是Deployment ,回到主题,既然pod副本多的是,那这些副本是怎么来的呢?你手动一个一个去创建吗?理论和实际都可以,如果有1000个pod呢?那不如直接定义一个蓝图,这个蓝图指定运行该pod的多少副本。这个蓝图组件就是Deployment

这个Deployment 是pod的抽象层,使得我们更加方便的去控制pod,与pod交互,复制pod等操作。在实践中,我们主要使用Deployment 而不是pod。
StatefulSet

DB挂掉之后应用也是不能访问的。那好办,多弄几个副本,使用Deployment 去创建一堆DB的副本pod。听起来不错,但是数据库有状态,即数据。这些DB的副本需要访问的相同的共享数据存储,而且需要某种机制来管理哪些部分当前正在写入,哪些部分当前正在存储中读取,以避免数据不一致。这种功能Deployment 是做不到的。

StatefulSet(有状态集)因此而生,就是这些有状态的应用的蓝图。作用和Deployment 差不多,也能复制pod,扩展或者缩小pod的规模,且保持数据一致。使用有状态集部署数据库应用会比Deployment 更难。所以k8s集群外部托管数据库应用也是一种常见的作法。

我们现在my-app有两个pod,DB有两个pod,还要两个负载均衡(service),一种一套(my-app和DB)重新启动或者崩溃,在修复之前,用户依然正常访问,这样就可以避免停机。
架构
这是一个整体的架构图,看不明白没关系,先放在这里。
工作节点(从节点)
必须三个进程安装Work Node:
- Container runtime
- Kubelet
- Kube Proxy
Work Node才是实际干活的,也就在工作节点。
Container runtime
首先来看Container runtime,这个是用来运行容器的,可以是docker,也可以是其他的容器技术。

Kubelet
对Pod和下面Container runtime的进程进行调度的是kubelet,这是k8s本身的进程。
kubelet和Container runtime不同,它拥有Container runtime和工作节点的接口。kubelet负责获取配置并且实际运行Pod,然后和资源(例如cpu,内存,硬盘)从该节点分配给容器

Kube Proxy
通常k8s集群由多个节点组成,这些节点必须安装Container runtime和kubelet,除此之外,这么多的节点是需要通讯的。而通讯用的是之前的组件service,它也是一个负载均衡器,把请求转发到Pod的第三个进程——Kube Proxy。它具有智能转发逻辑,确保通信能以低开销高性能的方式工作。

总结,Work Node三个进程如下

Master(主节点)
如何去调度pod?
如何去监视pod的状态?
如何重新调度或者重新启动它?
如果有一台服务器,如何让它加入集群,成为Node并且在这服务器上创建pod或者其他组件?
答案是Master Node

Master Node 有四个进程。
Api-Server

Api-Server:
- 是集群的大门,网关。获取集群中任何更新的初始请求,是交互的同一接口。
- 就像保安一样看住大门,对请求做验证。如果你的请求正常,那么它就把你都请求转发给其他进程。
Scheduler

另外一个重要的进程是Scheduler。
负责调度:
- 先查看请求的应用程序需要多少资源(多少cpu,多少内存,多少存储空间)
- 然后智能调度。Scheduler会遍历所有的工作节点Work Node,查看每一个Node的可用资源。
- 当看到Node的信息,最不忙或者拥有最多可用资源的时候,就在该Node上调度新的Pod

这里要注意的是,Scheduler只是决定哪一个Node应该被调度,也就是只是决策者,但是不具体执行。实际上执行调度的进程,是从节点的Kubelet,kubelet从Scheduler获取请求

Controller manager

Controller manager 也是一个很重要的进程。它的作用是检测这些Node的状态,然后尽快恢复集群状态。然后向Scheduler发送请求,Scheduler去计算所需的的资源以及智能调度,然后发消息给Kubelet,让它执行。
Etcd

最后一个Master进程是etcd,是集群状态的键值存储,你可以认为是集群的大脑,集群的状态信息都会保存在etcd中

Api-Server 如何知道集群是否健康?
Scheduler如何知道可用资源?
Controller manager 如何知道集群状态改变?
这些集群的的数据都是存储在etcd,所以要从etcd获取。
注意etcd只存储k8s集群的信息,用于Master和Work Node进行通讯。业务的数据在Volumes,请不要混淆了!!!
参考视频:
架构图来自:1.k8s是什么_哔哩哔哩_bilibili
感谢Nana女士的讲解,同时本人的英语水平不高,难免有些翻译错误和理解不到位的地方。请大佬指正,各位大佬阅读后也可移步去上面网址。