K8S是什么?


1. 了解云计算平台

可以将经典的云计算架构分为三大服务层,也就是IaaS(基础设施即服务)PaaS(平台即服务)SaaS(软件即服务)

IaaS:这一层通过虚拟化技术提供计算、存储、网络等基础资源,可以在上部署各种OS以及应用程序,开发者可以通过云厂商提供的API控制整个基础架构,无须对其进行物理上的维护和管理。典型的就有阿里云这样的设施,它通过在远程提供机房以及自动初始化完成的虚拟机,通过这个虚拟机来完成用户的工作

PaaS:这一层提供了软件部署平台,抽象掉了硬件和操作系统,开发者只需要关注自己的业务逻辑,而不需要关注底层

SaaS:这一层直接为开发者提供了软件服务,将软件的开发、管理、部署等全部都交给第三方,用户不再需要关心技术,可以实现一个开箱即用。

那么怎么来理解这个问题呢?

比如说IaaS服务就相当于在当地购买了一套房子,但是如何装修(在实际物理上通过远程API来安装操作系统)维护运行环境(给操作系统添加环境变量,安装前置软件)完全由客户决定

PaaS服务就相当于租房子,你不需要装修,只需要拿着行李箱(将自己的软件部署安装上去)就可以了,你不需要考虑操作系统层面的问题

SaaS服务就相当于住临时酒店,你需要什么就跟管家服务提供商说,然后管家就会帮你把生活物资准备好(软件服务定制),然后你自己入住酒店,然后把你需要的物资拿来用就行了

那么云计算的宗旨就是不用本地的计算设备,而是通过购买云厂商的计算设备进行计算,这样的话就可以调用远程部署的物理设备

有时候用户只是希望运行一些简单的程序,比如说跑一个小程序,为了避免相互影响,那么就要建立虚拟机,这显然就会浪费不少资源,毕竟IaaS的产品都是按照资源进行收费,同时操作会复杂,花费时间也会比较长

如果想要迁移应用程序到其他计算设备上,那么就要执行虚拟机的迁移,迁移会比较复杂

环境不一致,在业务部署发布的过程中,服务之间的各种依赖,比如说有操作系统,系统库/依赖包等,这些都会给业务开发和升级造成很大的制约

2. Docker解决了什么?

Docker的出现,它实现了容器标准,降低了容器技术的门槛,它的优点主要有轻量(指的是不像创建一个虚拟机一样,还需要创建一个系统内核程序)移植起来比较容易跨平台镜像一致性,交付同学可以利用容器保证交付版本和交互环境的一致性,也便于各个模块的单独升级,测试人员也可以针对单个功能模块进行测试,加快测试验证的速度

Docker通过引入镜像的概念,解决了环境打包的问题,通过直接打包应用运行所需要的整个操作系统,其实本质上就是打包了运行应用程序所需要的系统库和依赖包,赋予了本地环境和云端环境无差别的能力,这样就避免了用户通过试错来匹配不同环境之间差异的痛苦过程

由于一个镜像的构造是复杂的,不希望在构建镜像的过程中,全称在可视化较差的命令行环境下执行,因此发明了Dockerfile,通过Dockerfile,可以以一种编码的过程来设计镜像,使得开发者可以随时随地地构建无差别的镜像

3. 容器调度平台是做什么的?

为什么需要容器调度平台?

简单来说,当我们的应用程序规模大起来之后,那么通常会引入很多台物理服务器,那么如何通过一个统一的API来访问这些物理服务器,并且在之上部署容器,就成了一个非常重要的问题,一般来说,容器调度平台需要完成一下的工作:

调度能力:可以自动生成容器实例,通过一定的算法,将容器调度到指定的物理服务器上

亲和/反亲和:生成的容器可以相邻和相隔,帮助提高可用性和性能

健康检查:可以实现容器状态的健康检查,避免中央数据库和实际的事务效果不一致

可扩展:自动根据需要增加或者删除容器实例

网络:允许容器之间相互通信

服务发现:允许容器支架你相互发现

滚动升级:容器升级可以避免对业务造成影响,同时可以出错回滚,它指的是在构建容器的镜像改动时,能够一套机制热插拔这个容器执行的服务

Docker-Swarm

它是内置于Docker之中的,能够直接调度Docker容器,并且使用标准的DokckerApi,为用户提供无缝衔接的使用体验,更多的是面向开发者,而且对容错性的支持和不够好

K8s

K8s的目标就是消除编排物理或者虚拟计算、网络、存储等基础设备的负担,让应用研究商和开发者可以专注在容器为核心的引用上,同时优化集群的资源利用率

关于Pod和Label:它将容器组合成一个个互相依赖的逻辑单元,相关容器组被组合成Pod之后被共同部署和调度,就形成了服务,这就是K8S和其他两个调度管理系统最大的区别,相对来说,K8S采用这样的方式简化了集群范围内相关容器被共同调度管理的复杂性。

K8S不和任何平台绑定,可以跑在任何环境中,包括有公有云、私有云、物理机,甚至笔记本和树莓派都可以运行

通过minikube这类工具,可以快速搭建一套K8S集群

声明式API而不是命令式API,声明式API关注的是用户输入的状态,K8S会解析这些状态,并且努力达到这种状态,而命令式API关注的是用户输入的指令,通过用户输入的指令,平台执行这些指令,而不管最后的状态

可以通过YAML和JSON进行声明,然后通过PATCH的方式就可以完成对API的修改

4. 关于Borg的架构

一个集群可能有许多台服务器,然后可以用Cell来定义这一个集群,这一个集群中的服务器的硬件配置可以是异构的,包括有CPU差异,磁盘差异等,Cell内的这些机器是通过高速网络进行连通的,以此来保证网络的高性能

注意,一个Cell可以描述多个集群,它的定义是递归的,也就是说一个Cell可以包含大Cell的小Cell

分布式架构中的常见架构是Server-Agent(服务代理模式),主要的模块包括有BorgMaster、``

Borglet运行在每个节点或者机器上,它其实就是一个agent程序,主要负责任务的启停,如果任务失败了,那么他就会对任务进行重启等一系列操作,运行这些任务一般都是通过容器来做资源隔离的,Borglet会对任务的运行状态进行监控和汇报

每个集群中会有对应的Master节点,为了避免单点故障,往往需要部署多个BorgMater副本,就如我们图里显示的那样,这五个副本分别维护一根整个集群状态的内存拷贝,并且持久化到一个高可用的存储上

通过Paxos会从这5个BorgMaster副本中选择出一个Leader,负责处理整个集群的变更请求,其余四个都处于StandBy的状态,如果这个Leader宕机了,就会执行选举算法来提供服务。

BorgMatserBorglet之间的交互方式是BorgMaster主动请求Borglet,即使出现诸如整个Cell意外端点恢复,也不会存在大量的Borglet主动去连接BorgMaster,这就避免了大规模的流量将BorgMaset节点打挂的情况

5. 关于K8S的架构

K8S本身不是容器,而是一个容器编排工具,具体的架构如下:

K8S通过借鉴Brog的整体架构,主要由MasterNode来组成

Master是控制节点,部署着K8S的控制面,负责整个集群的管理和控制,Node节点为计算节点,这些节点上运行着一些负载容器,跟Borg一样,为了保证高可用,同时也需要部署多个Master实例

同时在K8S集群中采用了分布式存储系统ETCD,用于保存集群中的所有对象以及状态信息,建议将etcd一起部署到Master上,在集群节点资源足够的情况下,建议这样做,因为etcd是非常重要的,比如说存储了密钥信息,容器寻址信息等,必须要保证ETCD数据的安全性,它通过Raft来实现的

6. K8S的组件有哪些?

集群(cluster):将同一软件服务的多个节点组织到一起,共同为系统提供服务过程称之为集群,称为该软件的集群

K8S集群:多个节点,推荐3个以上,角色(master控制节点)(worker计算节点)

Pod:一个Pod可以运行多个容器(一个以及以上)

控制平面组件(Control Plane Components)

会为集群做出全局决策,比如资源的调度,以及检测响应集群事件,比如说当不满足部署的replicas字段的时候,会启动新的pod,做一个调度的,也就是实现一个自愈的能力

理解K8S的组件组成,可以通过这个容器调度平台的功能来思考:

kube-apiserver:它是信息的汇聚中心,提供了所有内部和外部的API请求的唯一入口,是负责集群的认证、授权、访问控制、服务发现等能力

kube-scheduler:简单来说,它负责容器Pod的调度,也就是说,当一个Pod被创建出来之后,还没有投入生产的时候,这时候就会进入一个Ready的状态,然后按照预定的调度策略,将这个Pod调度到满足调节的节点上,你可以理解为,针对这种Pod,调度器要通过apiserver去监听(轮询、查询)这些Pod,根据调度策略,选择合适的节点

kube-controller-manager:负责维护整个k8s集群的状态,比如说有多副本创建,滚动更新,这个组件包含了一组资源控制器,在启动的时候,会通过goroutine拉起多个资源控制器,这些控制器的逻辑仅依赖于当前的状态,因为在分布式系统中无法保证全局状态的同步。

计算节点上会完成什么?

容器运行时主要负责容器的镜像管理以及容器创建和运行,也就是客户端镜像,只要符合CRI规范的运行,就都可以在K8中使用

Kubelet:负责维护Pod的生命周期,比如创建和删除Pod对应的容器,负责存储和网络的管理,会配合CSICNI插件一起工作

Kube-Proxy:负责内部网络的通信,在主机上维护网络规则以及提供转发和负载均衡能能力

7. Master节点和Node节点的交互方式

K8S中所有的状态都是采用上报的方式实现的,APISERVER不会主动和Kubelet请求连接,所有容器状态汇报都是由APISERVER发起的,一旦启动Kubelet进程之后,它会主动向APIServer注册自己。

(实现也许是在一个节点启动之后,通过脚本部署一个守护容器,然后向中央数据库中写入数据)

一旦新增的Node被API纳管进来之后,Kublet进程就会定期向APISERVER定期汇报心跳,包括自身的健康状态,负载数据统计,当有一段时间内心跳包没有更新,那么kube-controller-manager就会标记为NodeLost,各个组件都是以APISERVER为中心,通过松散耦合的方式,借助于声明式API,各部件通过watch的机制(简单来说就是开启一个线程,定期检查任务的执行状态),然后执行相应的处理

8. 如何实现K8S的集群搭建?

对于一个分布式系统而言,要想达到生产可用,就必须要具备身份认证和权限授权的能力,一般来说,各内部组件相互通信会采用自签名的TLS的证书,所谓自签名就是说没有通过CA认证的证书,而是服务器通过openssl指令以及服务器的相关信息生产出来的信息,然后通过HTTPS来加强安全访问,为了能够确定各自的身份和权限,通常借助于mTLS(双向TLS)认证

如果K8S集群要生产可用,就需要签发一些证书,具体来看看都需要哪些证书:

etcd集群内部各member之间需要一对CA用于签发证书,这时候就需要签发出一对TLS证书用于在内部各member之间的数据互访和同步

同时etcd集群需要对外暴露服务,方便kube-apiserver读写数据,这时候就需要一对CA和TLS证书,一般来说 ,为了方便,这里可以使用同一份CA证书来签发证书

kube-apiserver跟ETCD集群之间的访问,也需要使用CA的证书,单独为kebe-apiserver签发一对TLS证书

这时候有个悖论了,要知道,如果想要实现K8S内部组件的通信,有两个过程是一定要实现的

  • 通过软件手段部署集群
  • 通过软件手段组织组件之间的访问控制

如果我先部署集群了,那么在部署集群的过程中,有没有可能产生一些超越权限的行为呢,怎么来担保安全呢?因此我需要施加一些权限控制,来保证集群的行为不会超越权限,但是如果集群都没有部署完,那么K8S中的控制组件又怎么去设置集群的权限呢?这是一个典型的问题

那么怎么解决呢?kube-apiserver启动的时候会预设一些权限,用于组件内部的接入访问,在组件签发证书的时候,就需要使用各自预设的CA来标识身份

Minikube

支持虚拟化的能力,可以借助于本地的虚拟化能力,通过Hyper-V等创建出虚拟机,然后在虚拟机中搭建出来一个K8S集群。

Kubeadm

一般用来搭建生产集群


文章作者: 穿山甲
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 穿山甲 !
  目录