# 一、Kubernetes的整体架构
学习k8s,最终目的是为了部署应用,部署一个完整的k8s, 就要知道k8s的组成。k8s主要包含两大部分: 中间包含三个绿色包的是master服务器. 下面是node节点.
在这里提前说一下etcd,etcd是k8s集群的一个数据库存储服务器。它采用了RAFT算法来选举主节点, 所以, 要求我们的master节点个数必须是3,5, 7, 9这样的奇数,也就是大于1的奇数个。3个节点可以保证1次高可用, 5个节点可以保证两次高可用,7个节点可以保证3次高可用。 以此类推。也就是3个节点最多可以死一次。5个节点最多可以死2次。node节点的个数不限制。
上图是k8s的简单架构图。可以看到有如下几个部分:
- master节点:左上角的最大快区域,是我们整个k8s的核心。上面说的大于1的奇数个节点,说的就是这里。
- node节点:
- etcd存储端:用来存储k8s中的数据的,主要采用Raft算法。
- internet网络层:
- firewall防火墙:
- web UI:
- kubectl:
# 二、Master节点
master节点在整个服务中起着至关重要的作用
master中主要有三个部分的内容:scheduler,控制器,api server。
## 1、Api Server
api server是所有服务请求访问统一的入口(所有请求的统一的入口)。如果想要给k8s下达命令,不管是什么类型的命令,都需要发送给api servier。
Api Server 本身是一个HTTP Server,也就是一个web服务器,它是无状态的。它的所有数据都会写入到Etcd。 如果你想要管Api Server要数据,它本身是没有的,他会去Etcd里面查询,然后返回给你。
从上图可以看出. Master中scheduler需要和api server交互, rc要和api server交互, kubectl(客户端)也要和api sever交互, web UI也要和api server交互, etcd也要和api server交互. apiserver是非常繁忙的.
api server采用的是无状态http请求,所以,他不会记录任何数据,所有数据都存储在etcd上。
Kubernetes API 服务器的主要实现是 kube-apiserver。 kube-apiserver 设计上考虑了水平伸缩,也就是说,我们可以通过部署多个实例进行伸缩。 你可以运行 kube-apiserver 的多个实例,并在这些实例之间平衡流量。
## 2、Scheduler 任务调度器
scheduler是k8s本身的一个调度器,这个调度器可以存在多个组成高可用。
scheduler是任务调度器, 负责调度任务, 选择合适的节点来执行任务. 当用户下达资源请求的时候,任务调度器会把任务分配给后端的多个node节点上,要基于一定的原则,**公平的**,快速的分发。也就是说,保证每个节点都有事做,不要浪费资源,做到资源利用最大化。所以,scheduler调度区非常关键,**他是保证整个集群资源利用高不高的核心组件。**
举个例子,一个任务来了, 要部署一个应用,到底应该部署在哪个节点上呢? 这个过程就是通过scheduler进行任务调度的。有的机器繁忙,有的机器空闲,scheduler会找一台空闲的机器进行部署。通过scheduler进行任务调度分发至不同的node.
scheduler会将任务交给api server, 由api server将任务写入到etcd, 也就是说scheduler不会直接和etcd交互。
## 3、controller-manager 控制器管理器
controller-manager: 控制器, 处理集群中常规后台任务,一个资源对应一个控制器。假如集群中有的pod已经死了,控制管理器就会处理将其删除或者救活。集群中的扩容,维稳都是有控制管理器来实现的。相当于是集群的管家。
举例来说,有一个订单服务,我们要部署这个服务,首先是交给任务调度器,任务调度器调用api server,将信息保存到etcd,etcd会创建一个controller-manager来专门管理这个订单服务。通常来说,一个资源对应一个控制器。
## 4、kubectl
命令行管理工具。这个工具我们可以安装在任何节点上。通常,我们将其安装在master节点上。 可以安装在安卓手机上,苹果手机上,windows电脑上,只要能够通过网络连接到api server,就能下发请求。
## 5、Web UI
Web UI是一套可操作的界面。Dashboard是 Kubernetes 集群的通用的、基于 Web 的用户界面。 它使用户可以管理集群中运行的应用程序以及集群本身并进行故障排除。
这个仪表盘不是给开发者使用的,开发者通常还是使用命令行,命令行是最全的。
# 三、etcd数据存储
先来说说etcd数据库的背景。我们熟悉的docker是docker公司开发的,其实在docker公司吧docker做大之前,还有一个公司也在默默的付出,就是Core OS公司,知道这家公司的人不多,但这个公司的技术背景是非常强悍的。docker公司和Core OS公司关系非常好,可以说技术是半共享状态。docker里面很多技术也是core OS公司贡献的。但是最终的结果是docker公司走红,一飞升天了,但是core OS公司没有几个人知道,但是core OS公司也获得了强大的技术背景的实例。core OS公司也想崛起,还开发了一款容器,但很显然,没法和docker比,于是core OS公司ua拿了一个策略,加入到了k8s的生态构建。core OS为k8s构建了很多组件,etcd就是core OS公司开发并且维护的,采用golang语言编写。 etcd是k8s的总存储,由core OS公司负责,由此可见技术能力是很强的。
etcd是键值对数据库, 存储K8s集群的所有重要信息(持久化). 在Kubernetes集群中起到的了持久化的作用.
## 1.etcd概念
etcd官方将其定位为一个**可信赖**的**分布式****键值存储**服务, 它能够为整个分布式集群存储一些关键数据, 协助分布式集群的正常运转.
> 可信赖的:官方已经提供了一个高可用方案,也就是说本省自带高可用
>
> 分布式:将数据分散到不同节点,以此来保证数据的强壮性
>
> 键值存储:就是简单的K-V对。etcd所有的数据类型只有一种存储结构,就是k-v结构。
## 2. Raft算法
- Raft是etcd采用的算法,叫做共识算法,或最终一致算法。
> 举个例子,什么是共识算法。 比如有一个村子,村子里有几百个村民, 然后有一个人考上了***大学,可厉害。旁边的邻居知道了,然后就开始一传十,十传百, 最后整个村子的人都知道了。 这就是共识算法
>
> 那最终一致是怎么回事呢?整个村子的人可能有的人先知道这个事,有的人晚点知道,但最终大家都知道。过程不一定一致,但结果是一致的。
>
> 刚刚说了Raft的节点为什么是3,5,7,9个呢,因为要投票选举,如果数据在某个节点,比如我的数据值是2017,另外两个事2018,已投票我就输了,那就是以你俩的数据为准,你俩成为leader了,来管理我,你们来提供服务,我要听你们的话,你们把数据给我。
- 每一个Raft集群中都包含多个服务器,在任意时刻,每一台服务器只能处于Leader、Follower以及Candidate三种状态;在处于正常的状态时,集群中只会存在一个Leader,其余都是Follower。
- Leader:领导者
- Follower:跟随者
- Candidate:竞选者
注意:一个能被外部正常访问的集群只有Leader和Follower两种状态。并且通常只有一个leader,其余都是follower
读写的信息, 所有的读写信息都被存在Raft里面, 而且, 为了防止这些信息出现损坏, 他还有一个WAL预写日志
## 2. Raft算法
- ## etcd的版本
etcd现在有两个版本, v2和v3版本,
- V2:v2版本将数据保存到内存, 这样很可能会不稳定,一宕机,数据全没了。
- V3: v3版本将数据保 存到磁盘. 然后进行缓存加速。并且,如果使用了V3版本,官方建议采用SSD进行存储和读取
- 如何选择版本呢?不用我们自己选择,k8s已经集成了etcd。正常我们都选择使用v3版本, 但Kubernetes v1.11版本之前使用的是v2版本.
-
## 3、Raft内部结构
Raft内部结构如下图,主要包含几个方面:Http Server, Raft,Wal,Store。下面来详细介绍
### 1> HTTP Server
这里采用的是使用http进行构建的c/s服务, k8s也是采用的http协议进行c/s服务的开发. 为什么要这么做呢? 因为http天生支持一系列的操作. 例如: get ,post, put, delete, 授权认证等. 所以, 没有必要再去采用标准的tcp协议. 开发一系列的认证流程, 所以, 直接采用http协议即可. http协议主要解决的是数据传输问题。
### 2> Raft
共识算法,上面说过了,这里不再赘述
### 3> WAL 预写日志
什么叫预写日志呢?在写入修改底层数据之前,把所有的操作先保存在日志里。
- Raft:共识算法,从一开始就被设计成一个易于理解和实现的共识算法。每一个Raft集群中都包含多个服务器,在任意时刻,每一台服务器只能处于Leader、Follower以及Candidate三种状态;在处于正常的状态时,集群中只会存在一个Leader,其余都是Follower。
共识算法,或者叫最终一致算法。比如:有3台etcd机器在运行的过程中,突然停了,那么3台etcd中的配置可能是不一样的,但是,一旦运行起来,经过一段时间,最终会达到一致。每一个Raft集群都包含多个服务器,在任意时刻,每一台服务器只可能处于Leader(主节点)、Follower(跟随者)、Candidater(竞选者)三种状态中的一种。在处于正常状态(可访问)时,集群中只会存在一个Leader,其余的服务器都是Follower。
- WAL: 预写日志, 吸入到数据库之前,先保存到日志里。如果要对数据进行更改, 那么先写入一条日志, 然后定时的对日志进行完整的备份. 也就是完整+临时. 比如: 我先备份一个大版本, 备份以后, 还会有1个子版本, 两个子版本....., 然后将这些版本再次进行一个完整备份,把它变成一个大版本. 这样做的好处, 我们不能始终进行完整备份, 因为消耗的数据量太大. 为什么还要在一定时间内进行完整的备份呢?防止增量备份太多, 还原的时候太费事. 并且, Raft还会实时的把这些数据和日志存入到本地磁盘进行持久化.
- Store: 把WAL中的日志和数据, 写入磁盘进行持久化.
# 四、Node节点
从图中可以看出, Node节点包含三个组件 ,kubelet, kube proxy, 以及container. 也就是说我们在node节点需要安装三个软件: kebelet, kebu proxy, docker
### 1)kubelet的作用
master端收到多个任务,调度器会把任务发送给node节点,在node节点上,任务都是以容器化的方式运行的。容器是被谁初始化的?容器的运行时,比如docker,docker会帮我们启动容器。一边是kuberates 的Api Server, 另一边是docker。他俩能够对话么?不能。举个例子: 一个是外国人,只会说英语,一个是中国人,只会说汉语。那如何让外国人和中国人交流呢?翻译呗。kubelet的作用就是连接k8s和docker的。kubelet监听api server,api server下发命令以后,kubelet要去调用docker,去执行指令,比如容器的创建。
kubelet的直接跟容器交互, 实现容器的生命周期管理.他会和CRI, C是容器, R是runtime, I是interface. CRI就是docker的操作形式. kubelet会和docker交互, 创建需要的容器. kubelet会维持Pod的生命周期.
也就是说,kubelet起到承上启下的作用。
### 2)kube proxy的作用:
下面调用linux的内核接口,叫做net link接口。当监听到api server发送的请求以后
kube proxy 上面监听api server,api server发出请求以后,会调用**linux的内核接口**,叫做net link接口,这个接口允许我们通过命令的方式,库调用的方式去实现IPVS的创建,实现netfire的管控,就是IPVS和防火墙的管控。负载均衡和数据的转发都是基于kube proxy组件实现的。
**负责写入规则至IPTABLES, IPVS实现服务映射访问.** 之前说过svc, 可以进行负载操作, 负责的操作就是通过kube proxy完成的. 怎么实现Pod与Pod之间的访问, 以及负载均衡. 默认操作是操作防火墙, 去实现Pod的映射. 新版本还支持IPVS.
由此可见,kubelet和kube proxy这两个功能各有各的用途。
## 3、其他重要的插件
### 1)Web UI
Web UI是一套可操作的界面。Dashboard是 Kubernetes 集群的通用的、基于 Web 的用户界面。 它使用户可以管理集群中运行的应用程序以及集群本身并进行故障排除。
### 2) COREDNS
可以为集群中的SVC创建一个域名IP对应的关系解析. 也就是说,我们在集群中访问其他Pod的时候, 完全不需要通过Pod的ip地址, 通过CoreDns给他生成的域名去实现访问. 他是集群中的重要重要组件, 也是实现负载均衡的其中一项功能.
### 3)DASHBOARD
给K8S集群提供一个 B/S结构访问体系.
### 4)Ingress Controller
官方只为我们实现了四层代理. Ingress可以实现七层代理, 也就是可以根据组件名和域名进行负载均衡.
### 5)Federation
提供一个可以跨集群中心多K8s统一集群管理功能.
### 6)Prometheus(普罗米修斯)
提供K8S集群的监控能力.
### 7)ELK
提供k8s集群日志统一接入平台
# 二、K8S和docker的关系
为什么会说k8s和docker的关系呢?这还要源于k8s发布的一则消息,在后续版本将不再增加垫片这个组件。导致很多人觉得docker不行了,很可能会被k8s遗弃,为什么这个垫片会有这么大的影响呢?这就要从CRI和O-CRI说起了。
先来看看容器是如何创建的?
kubelet监听了server api,有任何的变化都会下发命令给docker,然后docker操作容器。那么,kubelet调用docker的时候,是使用命令还是调用接口呢?
肯定是直接调用接口。因为调用命令最终也是去执行接口,中间还转一步,效率太低了。
但是,kubelet能直接调用docker接口么?
我们知道docker采用的是CRI容器运行时接口,
而k8s是google的产品,现在是CNCF云容器基金会的产品,这是一个开源镜像,k8s会直接对接到CRI这样一个私有协议么?我是公共使用的,所以肯定不会对接到私有协议接口。那么,我会对接到O-CRI接口,这时一个共有协议接口。问题来了,docker是CRI私有协议接口,k8s是O-CRI共有协议接口,对接不过去啊。所以,怎么办?再加一层转换,这层转换的作用是承上启下,上面承的是O-CRI,下面承的是CRI。这个转换是在kubectl实现的。这一层被叫做垫片。承上启下用的。
最开始,Docker的名气要比k8s大的多得多,所以,k8s就承接了垫片的任务。而如今,k8s的名气已经很大了,它不再需要依赖于docker,于是他要去掉垫片。并且发了公告。
那么docker是不是就完蛋了,k8s没有垫片做转换了,就不能调用docker接口了。docker也很机智,随即发布消息,他会增加垫片功能。这样k8s依然可以调用docker容器。但是,我们要知道,docker就重了,k8s减负了,k8s可以兼容任何容器,现在市面上有好几款容器,他不是飞docker不可的了。