K8S--架构原则和对象设计

一、K8S主要功能

  K8s是用来对docker容器进行管理和编排的工具,其是一个基于docker构建的调度服务,提供资源调度、均衡容灾、服务注册、动态扩容等功能套件,其作用如下所示:

  (1)数据卷:pod中容器之间数据共享,可以使用数据卷

  (2)应用程序健康检查:容器内服务可能发生异常导致服务不可用,可以使用健康检查策略保证应用的健壮性。

  (3)复制应用程序实例:控制器维护着pod的副本数量,保证一个pod或者一组同类的pod数量始终可用。

  (4)弹性伸缩:根据设定的指标(CPU利用率等)动态的自动缩放pod数

  (5)负载均衡:一组pod副本分配一个私有的集群IP地址,负载均衡转发请求到后端容器,在集群内布,其他pod可通过这个Cluster IP访问集群。

  (6)滚动更新:更新服务不中断,一次更新一个pod,而不是同时删除整个服务

  (7)服务编排:通过文件描述部署服务,使的程序部署更高效。

  (8)资源监控:Node节点组件集成cAdvisor资源收集工具,可通过Heapster汇总整个集群节点资源数据,然后存储到InfluxDB时序数据库,再由Grafana展示

  (9)提供认证和授权:支持属性访问控制、角色访问控制等认证授权策略。

  K8S的架构图如下所示:

      

   从上图可以看到,K8S提供了:

    web browsers提供可视化操作

    kubectl来接收Docker镜像进行部署

    scheduler进行任务调度

    Controller进行请求控制

    API Server进行请求的统一网关处理

    etcd用于存储集群中的网络及状态信息

    Kubelet来接收控制器的处理任务

    Container Registry用来存储镜像仓库

二、K8S集群

(一)集群概述

  一个K8S集群包含一个master节点和一群node节点,Mater节点负责管理和控制,Node节点是工作负载节点,里面是具体的容器,容器中部署的是具体的服务。

  Mater节点包括API Server、Scheduler、Controller Manager、etcd。

    API Server:整个集群的对外接口,供客户端和其他组件调用。

    Scheduler:负责集群内部资源调度

    Controller Manager:负责管理控制器。

    etcd:用于保存集群中所有网络配置和对象状态信息。

  node节点包括Docker、kubelet、kube-proxy、Fluentd、kube-dns(可选)、pod     

 (二)Mater节点

  上面已经提到,Mater节点包括API Server、Scheduler、Controller Manager、etcd。

  1、API Server

    API Server是整个集群的统一入口,各组件的协调者,以HTTP的形式对外提供服务,所有对象资源的增删改查和监听操作都交给API Server处理后再提交给etcd进行存储。

  2、Scheduler

    Scheduler负责集群内部资源调度,其会根据调度算法为新创建的pod选择一个node节点,Scheduler在整个集群中起到了承上启下的重要功能,承上是指她负责接收Controller Manager创建的新的pod,为其安排一个node节点,启下指的是当为pod选定node节点后,目标Node上的kubelet服务进程会接管该pod。

      

    这里就要提一下创建Pod的流程:

      (1)kubectl发送创建pod的请求,此时这个命令被apiserver拦截,把创建的pod存储到etcd的podQueue

      (2)Scheduler发起调用请求,此时这个命令被apiserver拦截,获取etcd中podQueue.NodeList,使用调度算法(调度算法:预选调度、优选策略)选择一个合适的node节点

      (3)把选择合适的pod、node存储到etcd中

      (4)node节点上的Kubelet进程,发送请求获取pod、node对应创建资源

      (5)此时node发现pod是本node需要创建的,kubelet就开始创建pod

  3、Controller Manager

    每个资源都对应一个控制器(Kubernets Controller),其用来处理集群中常规的后台任务,而Controller Manager是用来负责管理控制器的。

    K8S集群有以下控制器:

      (1)Replication Controller:保证Replication Controller中定义的副本数量与实际运行的pod数量一致。

      (2)Node Controller:管理维护Node,定期检查Node节点的健康状态,标识出失效和未失效的Node节点。

      (3)Namespace Controller:管理维护Namespace,定期清理无效的Namespace,包括Namespace下的API对象,例如pod和service等

      (4)Service Controller:管理维护Service,提供负载以及服务代理。

      (5)Endpoints Controller:管理维护Endpoints,即维护关联service和pod的对应关系,其对应关系通过Label来进行关联的

      (6)Service Account Controller:管理维护Service Account,为每个Namespace创建默认的Service Account,同时为Service Account创建Service Account Secret。

      (7)Persistent Volume Controller:持久化数据控制器,用来部署有状态服务

      (8)Deamon Set Controller:让每一个Node节点都运行相同的服务

      (9)Deployment Controller:无状态服务部署控制器

      (10)Job Controller:管理维护Job,为Job创建一次性任务Pod,保证完成Job指定完成的任务数目。

      (11)Pod Autoscaler Controller:实现pod的自动伸缩,定时获取监控数据,进行策略匹配,当满足条件时执行pod的伸缩动作。

  4、etcd

    etcd是一个第三方服务,分布式键值对存储系统,用于保存网络配置、集群状态等信息,例如service、pod等对象的信息。

    K8S中一共有两个服务需要用到etcd来协调和存储数据,分别是网络插件flannel和K8S本身,其中flannel使用etcd存储网络配置信息,K8S本身使用etcd存储各种对象的状态和元信息配置。

(三)Node节点

  上面提到,node节点包括Docker、kubelet、kube-proxy、Fluentd、kube-dns(可选)、pod等信息。

      

  1、kubelet

    kubelet是Mater在Node节点上的代理,每个Node节点都会启动一个kubelet进程,用来处理Mater节点下发到Node节点的任务,管理本机运行容器的生命周期,比如创建容器、Pod挂载数据卷、下载secret、获取容器和节点的状态等工作,kubelet将每个pod转换成一组容器。

    kubelet默认监听四个端口:10250、10255、10248、4194

    10250端口:kubelet API的端口,也就是kubelet server与api server的通讯端口,定期请求apiserver获取自己所应当处理的任务,通过该端口可以访问和获取node资源及状态。

    10248端口:健康检查的端口,通过访问该端口可以判断kubelet是否正常工作,可以通过 kubelet 的启动 参数 --healthz-port 和 --healthz-bind-address 来指定监听的地址和端口

    4194端口:kubelet通过该端口可以获取到该节点的环境信息以及node上运行的容器状态等内容,访问 http://localhost:4194 可以看到 cAdvisor 的管理界面,通过 kubelet 的启动参 数 --cadvisor-port 可以指定启动的端口。

    10255端口:提供了pod和node的信息,接口以只读形式暴露出去,访问该端口不需要认证和鉴权。

  2、kube-proxy

    在Node节点上实现Pod网络代理,维护网络规则和四层负载均衡工作,kube-proxy本质上类似于一个反向代理,我们可以把每个节点上运行的kube-proxy看作是service的透明代理兼LB。

    kube-proxy监听apiserver中service与endpoints的信息,配置iptables规则,请求通过iptables直接转发给pod。

    

   3、docker

    运行容器的引擎,pod内部运行的都是容器,这个容器是由Docker引擎创建的,Docker引擎是node节点的基础服务。

  4、pod

    pod是最小的部署单元,一个pod由一个或多个容器组成,pod中共享存储和网络,在同一个Docker主机上运行。pod内部可以运行一个或多个容器,一般情况下,为了便于管理,一个pod下只运行一个容器。

(四)Pod

  pod就是一个容器,内部封装了docker容器,同时拥有自己的ip地址,也有用自己的HostName,Pod就像一个物理机一样,实际上Pod就是一个虚拟化的容器(进程),pod中运行的是一个或者多个容器。

      

   pod是一个大的容器,由K8S创建,pod内部的是docker容器,由Docker引擎创建。K8S不会直接管理容器,而是管理Pod。

  pod的作用是管理线上运行的应用程序,在通常情况下,在服务上线部署的时候,pod通常被用来部署一组相关的服务。而一个调用链上的服务就叫做一组相关的服务。但是实际生产上一般是一个Pod对应一个服务,不会在一个Pod上部署太多的服务。

  pod的具体结构如下图所示,一个Node中有很多pause容器,这些pause容器和pod是一一对应的,每个Pod里面运行着一个特殊的被称为Pause的容器,其他的容器则为业务容器,这些容器共享Pause容器的网络和存储,因此他们之间的通信更高效,在同一个pod里面的容器之间仅需要通过localhost就可以通信。

      

   K8S中的pause容器主要为每个业务容器提供以下功能,从而对各个Pod进行了隔离:

    PID命名空间隔离:pod中不同的应用程序可以看到其他应用程序的进程ID

    网络命名空间隔离:Pod中多个容器能够访问同一个IP和端口范围

    IPC命名空间隔离:Pod中多个容器能够使用System VIPC或POSIX消息队列进行通信

    UTS命名空间隔离:pod中多个容器共享一个主机名和挂在卷

    Pod中各个容器可以访问在Pod级别定义的Volumes

  一个Pod创建的过程:首先kubelet会先创建一个pod,然后立马会创建一个pause容器,pause容器是默认创建的,然后再创建内部其他的业务容器。

三、核心组件及原理

  1、RC控制器(ReplicationController)

    用来确保容器应用的副本数始终与用户定义的副本数一致,如果有副本由于异常退出,Replication Pod会自动创建新的Pod来替代,而如果出现多余的pod,控制器也会自动将其回收。

    在新版的K8S中,建议使用ReplicaSet来取代Replication Controller

  2、RS控制器(ReplicaSet)

    ReplicaSet和Replication Contreoller并没有本质上的区别,ReplicaSet支持集合式的选择器。

    虽然ReplicaSet可以独立使用,但一般情况下还是建议使用Deployment来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题。

    RC和RS的区别是RC只支持单个标签选择器,不支持复合标签选择器;而RS同时支持单个和复合选择器。

  3、label(标签)

    label用于区分对象,例如区分是service还是pod,以键值对的形式存在,每个对象可以有多个标签,可以通过标签关联对象。

    label是replication Controller和Service运行的基础,二者是通过label来进行关联Node上运行的Pod。我们可以通过给指定的资源对象捆绑一个或多个不同的Label来实现多维度资源分配管理功能,一些常用的Label如下所示:

版本标签:"release":"stable","release":"canary"......
环境标签:"environment":"dev","environment":"qa","environment":"production"
架构标签:"tier":"frontend","tier":"backend","tier":"middleware"
分区标签:"partition":"customerA","partition":"customerB"
质量管控标签:"track":"daily","track":"weekly"

    label就类似与标签,给某个对象定义了一个label就相当于给对象定义了一个标签。

    如果多个pod拥有相同的标签,就说明这是一组pod。

  4、selector

    标签选择器是K8S非常重要的一环,其用来查询和筛选某些拥有具体标签的对象,K8S也是使用这种方式进行对象的查询。

    Label Selector在K8S中的应用有以下几个场景:

      Kube-Controller进程通过资源对象RC上定义的Label Selector来筛选要监控的Pod的副本数量,从而实现副本数量与用户定义的副本数量保持一致。

      Kube-proxy进程通过Service的Label Selector来筛选对应的Pod,自动建立起每个Service到对应Pod的请求链路表,从而实现Service的负载均衡。

      Kube-Scheduler通过对某些Pod的自定义Label,并且在pod定义文件中使用Node Selector这种标签的调度策略,从而实现了Pod定向调度的特性。

    例如上面Label的例子中,如果服务中既有环境Label又有版本Label,使用RC只能对同一个版本标签或者同一个环境标签的Pod进行选择,不能同时对版本和环境两个维度进行筛选,而RS可以对两个维度同时进行筛选。

  5、Deployment

    RS虽然可以控制副本的数量,但是单独的RS部署却不能滚动更新。因此衍生了Deployment组件,其支持滚动更新,其会先创建新版本的pod容器,然后再删除老旧版本的pod容器。

    滚动发布:滚动发布有金丝雀发布和灰度发布,该种发布一般是以25%的模式进行发布,也就是先删除25%旧版本,在部署对应数量的新版本Pod,然后再删除25%旧版本,这样以此滚动更新。

    因此实际生产中一般都是用RS和Deployment的组合来进行发布服务。

    总体来说,Deployment是用来管理RS,RS来管理Pod,deployment支持动态更新,也就是在更新时动态的创建一个新的RS,然后由新RS创建新版本的Pod,然后将旧版本RS中的Pod进行删除。如果发生回滚,就是一个逆向操作,产生一个旧版本的RS,用来生成旧版本的Pod。

    在滚动发布过程中,对于流量是转发到新版本还是老版本的Pod中,是由商城的Service进行转发的。

    Deployment为Pod和ReplicaSet提供了一个声明式定义方法,典型的应用场景:

      定义Deployment来创建Pod和ReplicaSet

      滚动升级和回滚应用

      扩容和缩容

      暂停和继续Deployment

      

   6、HPA(HorizontalPodAutoScale)

    HPA仅适用于Deployment和ReplicaSet,在V1.0版本中,仅支持根据pod的CPU利用率进行扩容缩容,在新版本中,支持根据内存和用户自定义的metric进行扩容缩容。说的通俗一点,就是在流量突然增大,可以自动扩容,流量降下后,可以自动缩容。

  7、StatefullSet

    deployment和StatefullSet都是用来进行服务部署的,但是这两个组件各自使用的场景不一样,deployment是用来部署无状态服务的,而StatefullSet是用来部署有状态服务的。

    这里说明一下有状态服务和无状态服务,有状态服务指的是需要进行实时的数据更新和存储的服务,如果将某个服务抽离,再加入进来就没办法进行正常工作,例如mysql、redis等;无状态服务指的是没有对应数据进行更新和存储的服务,如果将某个服务抽离,再加入进来依然可以提供服务,我们常用的业务服务一般都是无状态服务,而docker业主要是为了无状态服务提供部署的。

    StatefullSet应用场景包括:

      (1)稳定的持久化存储,即pod重新调度后仍然可以访问相同的持久化数据,基于PVC实现

      (2)稳定的网络标志,即pod重新调度后,podName和HostName不变,基于Headless Service来实现

      (3)有序部署&有序扩展,即pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行,也就是说,从0到N-1,在下一个pod运行前,所有之前的pod都处于running和ready状态。基于init contains实现。

      (4)有序收缩&有序删除,即从N-1到0进行回收或删除

    总体来说,Pod是可能随时删除或者新增的,一个pod也是有自己的网络和存储的,对于例如Mysql这类的Pod,可能不能发生网络和存储上的变化,StatefullSet就是为了解决这个问题而产生的。

  8、DaemonSet

    DaemonSet确保全部Node上运行一个Pod副本,当有Node加入集群时,也会为他们新增一个pod,当有Node从集群中被移除时,这些pod也会被回收,删除DaemonSet将会删除其创建的所有pod。最典型的场景就是每个Pod里面都有服务在运行,需要收集服务运行日志,但是Pod是由K8S自动创建或删除的,因此需要使用DaemonSet来设定在每一个Pod中进行日志收集。

    DaemonSet的一些典型用法:

      (1)运行集群存储Daemon,例如在每个Node上运行glustered、ceph

      (2)在每个Node上运行日志收集Daemon,例如fluentd、logstash

      (3)在每个Node上运行监控Daemon,例如Prometheus Node Exporter

    Job负责批处理任务,即仅执行一次的任务,他保证批处理任务的一个或多个pod成功结束。

  9、Volume

    数据卷,共享pod中容器使用的数据。

  

 

posted @ 2021-07-22 22:35  李聪龙  阅读(4563)  评论(0编辑  收藏  举报