kubernetes 概述及各组件详细说明

时间:2024-04-17 16:51:04

一、kubernetes是什么

  一)kubernetes是什么

  1. kubernetes是权限的基于容器技术的分布式架构领先方案
  2. 我们的系统设计遵循了kubernetes的设计思想,不必关心和业务无关的底层代码或功能模块,不必费心负载均衡的选型和部署实施问题,不必再考虑引入或开发服务治理框架,不必再头疼于服务监控和故障处理模块的开发。(可以节省不少于百分之三十的成本,同时可以将精力更加集中于业务本身,提供了强大的自动化机制)
  3. kubernetes是一个开放平台:大多数语言都能毫无困难地映射为kubernetes的service,并通过标准的TCP通信协议进行交互,而且他对现有的编程语言、编程框架、中间件没有任何侵入性。因为现有的系统也可以很容易改造升级并迁移至kubernetes平台上
  4. kubernetes是一个完备的分布式系统支撑平台。kubernetes具有完善的集群管理能力,包括多层次的安全保护和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建智能负载均衡、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力,可扩展的资源自动调度机制,以及多粒度的资源配额管理能力。 同时kubernetes提供了完善的管理工具,这些工具包括开发、部署测试、运维监控在内的各个环节。

  二)为什么要用kubernetes

  1.  可以“轻装上阵”地开发复杂系统了
  2. 使用kubernetes就是在全面拥抱微服务架构
  3. 系统可以随时随地整体“搬迁”到公有云上
  4. kubernetes系统架构具备了超强的横向扩展能力

  三)kubernetes特性

  kubernetes是一种用于在一组主机上运行和协同容器化应用程序的系统,旨在提供可预测性、可扩展性与高可用性的方法来完全管理容器化应用程序和服务的生命周期的平台。

  1. 自动装箱:建立容器之上
  2. 自我修复:支持容器故障后自动重启、节点故障后重新调度容器,以及其他可用节点、健康状态检查失败后关闭容器并重新创建等自我修复机制。
  3. 水平扩展:支持通过简单命令或UI手动水平扩展,以及基于CPU等资源负载率的自动水平扩展机制
  4. 服务发现和负载均衡:kubeDNS(或coreDNS)为系统内置了服务发现功能,它会为每个service配置DNS名称,并允许集群内的客户端直接使用此名称发出访问请求,而service则通过iptables或ipvs内建了负载机制
  5. 自动发布和回滚:监控更新过程中应用程序的监控状态,以确保它不会在同一时刻杀掉所有实例,而此过程中,一旦有故障发生,就立即自动回滚操作
  6. 密钥和配置管理:ConfigMap实现了配置数据与Docker镜像解耦,需要时,仅对配置做出变更而无须重新构建docker镜像。对于应用所依赖的一些敏感数据,如用户名和密码、令牌、密钥等信息,kubernetes专门提供了secret对象为其解耦
  7. 存储编排:本地存储、公用云存储、网络存储(NFS、glusterFS、Ceph等)
  8. 批量处理执行:支持批处理作业及CI(持续集成),如需要,一样可以实现容器故障后恢复

  四)kubernetes基本概念和术语

  1、概述

  https://www.cnblogs.com/xhyan/p/6656062.html

  https://www.cnblogs.com/zhenyuyaodidiao/p/6500720.html

  2、pod深入了解

  https://www.cnblogs.com/xhyan/p/6708344.html

  https://www.jianshu.com/p/d867539a15cf

  3、ConfigMap

  https://www.cnblogs.com/cocowool/p/kubernetes_configmap_secret.html

  使用ConfigMap的限制条件

  • ConfigMap必须在Pod之前创建
  • ConfigMap也可以定义为属于某个namespace。只有处于相同namespace中的pod可以引用它、、
  • ConfigMap中的配额管理还未实现
  • kubelet只支持被API server管理的pod使用ConfigMap。kubelet在本node上通过--mainifest-url或--config自动创建的静态pod将无法引用ConfigMap

  注意:

  滚动升级

  • 删除RC并不会影响通过该RC已创建好的pod。为了删除所有pod,可以设置replicas的值为0,然后更新该RC。另外kubectl提供了stop和delete命令来一次性删除RC和RC控制的全部pod。
  • deployment相对于RC的一个最大升级是我们可以随时知道当前pod“部署”的进度。

二、kubernetes master 节点组件

  

  一)apiserver

    API服务器是kubernetes控制面的组件,该组件公开了kubernetes API。api服务器是kubernetes控制面的前端。

    ApiServer 对外提供增删改查etcd中资源配置数据,worker节点kubelet同master节点的ApiServer进行交互

  master节点的scheduler和controller manager组件也需要同ApiServer进行交互以获取和修改对应资源的状态

  Kubernetes 集群中,API Server 扮演着通信枢纽的位置。API Server 不仅负责和 etcd 交互(其他组件不会直接操作 etcd,只有 API Server 这么做),并切对外提供统一的API调用入口, 所有的交互都是以 API Server 为核心的。API Server 提供了以下的功能:

  1. 整个集群管理的 API 接口:所有对集群进行的查询和管理都要通过 API 来进行。集群内部的组件(如kubelet)也是通过Apiserver更新和同步数据到etcd中。
  2. 集群内部各个模块之间通信的枢纽:所有模块之前并不会之间互相调用,而是通过和 API Server 打交道来完成自己那部分的工作。
  3. 集群安全控制:API Server 提供的验证和授权保证了整个集群的安全。
  4. 数据中心枢纽: API Server 负责和 Etcd 交互存放集群用到的运行数据。
  • 集群管理的API 入口

  • 资源配置控制入口

  • 提供完备的集群安全机制

  api server 是通过kube-apiserver 进程来提供服务的. 默认情况下在本机8080端口提供 rest 服务(--insecure-port), 也可以启用HTTPS 安全端口 (--secure-port=6443)

  https://www.jianshu.com/p/2a70f7189a54

  ApiServer三层认证
    kubernetes认证

kubernetes认证:kubernetes提供了多种认证方式:比如客户端证书、静态token、静态密码文件、ServiceAccountToken等等。可以是使用一种或多种认证方式。只要通过任何一个都被认作认证通过。


  • 客户端证书认证:客户端证书认证叫做TLS双向认证。也就是服务端客户端互相验证证书的正确性,在都正确的情况下协调通信加密方案。 api-server需要用-client-ca-file选项来开启

  • 静态Token:当有非常多的node节点时,手动为每个node节点配置TLS认证比较麻烦,这是就可以用到引导token的认证方式,前提需要在api-server开启experimental-bootstrap-token-auth特性。客户端的token信息与预先定义的token匹配认证通过后,自动为node颁发证书。当然引导token是一种机制,可以用到各种场景中

  • service account tokens认证:有些情况下,希望在pod内部访问api-server,获取集群的信息,甚至对集群进行改动。针对这种情况,kubernetes提供了一种特殊的认证方式:service account。

    • service account和pod、service、deployment一样式kubernetes集群中一种资源,用户也可以创建自己的service account

    • ServiceAccount 主要包含三个内容:namespace、Token和CA、

      • namespace指定了pod所在的namespace

      • CA用于验证apiserver的证书

      • token用作身份验证 它们都通过mount的方式保存在pod的文件系统中

    Role-Based Access,RBAC

在kubernetes1.6版本中新增角色访问控制机制(Role-Based Access,RBAC)。让集群管理员可以针对特定使用者或服务账号的角色,进行更精确的资源访问控制。在RBAC中,权限与角色相关联,用户通过称为适当角色的成员而得到这些角色的权限。这就极大简化了权限的管理。


在一个组织中,角色是为了完成各种工作而创建,用户则依据它的责任和资格来指派响应角色,用户可以很容易地从一个角色被指派到另一个角色

目前kubernetes中有一系列的鉴权机制,RBAC是更好的选择
kubernetes准入控制准入控制(AdmissionControl)本质上为一段准入代码,在对kubernetes api的请求过程中,顺序为:先讲过认证&授权,然后执行准入操作,最后对目标对象进行操作。这个准入代码在api-server中,而且必须被编译到二进制文件中才能被执行。
在对集群进行请求时,每个准入控制代码都按照一定顺序进行。若有一个准入控制拒绝了此次请求,那么整个请求结果将会立即返回,并提示用户相应的error信息。
常用组件(控制代码)如下

    * AlwaysAdmit:允许所有请求

    * AlwaysDeny:禁止所有请求,多用于测试环境

    * ServiceAccount:他讲serviceAccount实现自动化,他会辅助serviceAccount做一个事情。比如若pod没有serviceAccount属性,则他会自动添加一个default,并确保pod的serviceAccount始终存在

    * LimtRanger:观察所有的请求,确保没有违反已经定义好的约束条件,这些条件定义在namespace中的LimitRange对象中。若在kubernetes中使用LimitRange对象,则必须使用这个插件

    * NamespaceExists:它会观察所有的请求,若请求尝试创建一个不存在的namespace,则这个请求被拒绝

 

  二)kube-scheduler及调度器性能调优

  在kubernetes中,调度指的是将新生成的pod调度到合适的Node节点上,然后Node上对应的kubelet才能运行pod。

  

  k8s预选策略和优选函数简介:https://www.cnblogs.com/wn1m/p/11290733.html

  控制平面组件,负责监视新创建的、未指定运行节点(node)的pods。选择节点让pod在上面运行。

  默认调度器的调度规则是:根据Node最大资源空闲率来进行均衡调度。

  是一个策略丰富、拓扑感知、工作负载特定的功能,调度器显著影响可用性、性能和容量。调度决策考虑的因素包括单个pod和pod的集合的资源请求、硬件/软件/策略约束、亲和性和反亲和性规范、数据位置、工作负载剪得干扰和最后期限。

  1、调度概述

  调度器通过kubernetes的watch机制来发现新生成的且未调度到Node上的pod。调度器会将发现的每一个未调度的pod调度到合适的Node上运行,调度器会使用以下所述的调度原则来做出调度选择。

  2、kube-scheduler

  kube-sceduler时kubernetes集群中默认调度器,并且是集群控制面的一部分,kube-scheduler在设计上允许你写一个自己的调度组件并替换原有的kube-scheduler。

  对每一个新创建或未被调度的的pod,kube-scheduler都会选择一个最优的Node去运行这个pod。然而,pod内的每一个容器对资源都有不同的需求,而且pod本身也有不同的资源需求。因此,pod被调度到Node之前,会根据这些特定的资源调度需求,对集群中的Node进行一次过滤。

  在一个集群中,满足一个pod调度请求的所有node称之为可调度节点。如果没有任何一个Node满足pod的调度请求,那个这个pod会一直处于未调度状态直到调度器能够找到合适的Node。

  调度器先在集群中找到pod的所有可调度节点,然后根据一系列函数对这些可调度节点打分,然后选出得分最高的Node来运行pod。之后,调度器将这个调度决定通知给kube-apiserver,这个过程叫做绑定。

  在做调度决定时需要考虑的因素包括:单独和整体的资源需求,硬件/软件/策略限制,亲和以及反亲和要求,数据局域性,负载间的干扰等。

  3、kube-scheduler调度流程

  kube-scheduler 给一个 pod 做调度选择包含两个步骤:

  • 预选策略(Predicate)——过滤:过滤阶段会将所有满足 Pod 调度需求的 Node 选出来。例如,PodFitsResources 过滤函数会检查候选 Node 的可用资源能否满足 Pod 的资源请求。在过滤之后,得出一个 Node 列表,里面包含了所有可调度节点;通常情况下,这个 Node 列表包含不止一个 Node。如果这个列表是空的,代表这个 Pod 不可调度。

    1. 根据运行Pod的资源限制来排除不符合要求的Node
    2. 根据运行Pod时,是否要求共享宿主机的网络名称空间来判断,如: 某Pod启动要共享宿主机的网络名称空间,启动80端口,而某些Node的80已经被占用,那它就不符合,就也要不排除。
  • 优选策略(Priority)——打分:打分阶段,调度器会为 Pod 从所有可调度节点中选取一个最合适的 Node。根据当前启用的打分规则,调度器会给每一个可调度节点进行打分。最后,kube-scheduler 会将 Pod 调度到得分最高的 Node 上。如果存在多个得分最高的 Node,kube-scheduler 会从中随机选取一个。

    • 默认启用了7个红色的优选函数
  LeastRequested: 【与它相反对一个优选函数:MostRequested,它是Node资源占用越高得分越高,有点像是,先将某Node的资源先全部占满的意味,然后空出部分Node.】
     计算得分的算法公式=(cpu((capacity - sum(requested))*10 / capacity) + memory((capacity - sum(requested))*10 / capacity))/2
       此公式的含义:
      假如当前有16个核心,已经用了8个核心,那么总的使用率就是 (16-8)/16 = 0.5 ,而乘以10,是为了计算得分方便,将其转化为0~10之间的数,
      而内存的计算含义一样,假如内存32G,已经用了8G,则使用率为 (32-8)/32 = 0.75 ,乘以10
      将CPU + Memory/2 就可以得到一个平均值。该平均值越高,表示该节点的资源空闲率越高。
  BalanceResourceAllocation:
    它表示CPU内存资源占用率的相近程度,作为评估标准,越接近也优选选择,比如: Node1的CPU和内存使用率一个48%一个50%,而Node2的CPU和内存使用率都是50%,则Node2胜出。
  #它通常要和LeastRequested 结合来评估Node的资源利用率的。
  #两个组合主要是为了平衡各Node上资源的利用率。
NodePreferAvoidPods:
  根据Node节点上是否定义了注解信息"scheduler.alpha.kubernetes.io/preferAvoidPods",若没有则该Node得分为10,而且权重为1万,有此注解则说明该Node是适合运行Pod的。而对于那些有Replicas Controller的控制器则,该Node的得分为0,此时则表示Pod不能运行在该Node上,但这不能决定Pod一定不能运行在该Node上,因为最终是要看总体得分的。
  注解信息:
    # kubectl describe node node1.zcf.com
      Name: node1.zcf.com
      Roles: node
      ..........
      Annotations: node.alpha.kubernetes.io/ttl: 0      #这就是所谓的node上的注解信息。
      volumes.kubernetes.io/controller-managed-attach-detach: true

TaintToleration:
  基于Pod对调度Node上的污点容忍度来评估是否可调度到该Node上。
  简单说:就是取出Pod对象中定义的spec.tolerations列表,查看其中能容忍的污点,然后,一个一个去对比Node上存在的污点,若匹配的越多,则该Node的得分越低,就越不会调度到该Node上。
SelectorSpreading:
  此优化函数是希望将相同标签选择器选取的Pod尽可能的散开到多个Node上。因此假如:ReplicaSet控制器,已经在B上创建了一个Pod,那么它要再创建一个Pod时,此优选函数在计算A,B,C三个Node的得分时,会根据那个Node上拥有此ReplicaSet控制器的标签选择器所匹配的Pod数量,来评分,数量越少,分数越高,反之越低。
  而使用标签选择器的资源对象有:Service,Replication Controller,ReplicaSet,StatefulSet。
InterPodAffinity:
  遍历对象的亲和性条目,并将能够匹配到给定节点的条目的条目数相加结果值越大得分越高。
  简单说:NodeA上运行了3个Pod,NodeB上运行了6个Pod,NodeC上运行了5个Pod,现在要调度一个Pod到其中一个Node上,而该Pod的比较亲和某类Pod,此优选函数就会将这些Node上,所有匹配该Pod亲和条目的数量相加,值越大,则越得分越高。其中条目的理解,我还不是很懂。
NodeAffinity:
  它是根据pod中定义的nodeSeletor来对Node做亲和性检查, 能成功匹配的数量越多,则得分越高。
NodeLabel:
  根据Node是否有某些标签来做评估,然后计算得分的,此优选函数只关注标签,不关注值,只有Node上有这个标签就可以得分。
ImageLocality:
  它评分的标准是,判断Node上是否有运行该Pod的镜像,若有则得分,否则不得分。
  但它评估镜像是根据镜像总的体积大小来计算得分的,例如:NodeA上有1个镜像1G,NodeB上有2镜像,NodeC上有3个镜像,而运行此Pod需要4个镜像,其中一个镜像1G,其它都是比较小,这时NodeA的得分会最高。

 

  • 选定(Select):当优选选出一个Node后,该Pod将会被绑定到该Node上运行

  调度方式

  1. 节点倾向性(或叫 节点亲和性调度)
   这种调度通常会采用 nodeSelector 来完成调度。

  2. Pod倾向性 和 Pod非倾向性(这也称为Pod亲和性和非亲和性)
   有时候我们需要让某些Pod能运行在同一处时,就需要使用Pod亲和性来定义,如:我们要定义一个NMT(Nginx+Tomcat+MySQL),若这三个Pod分别被调度三个不同地域的机房中,比如北京,上海,深圳等地,那肯定不是我们所希望的,这时我们就需要使用Pod亲和性来定义这三个Pod能运行在相同的Node 或 相邻的Node上。
  而在另外一些情况下,我们又希望某些Pod一定不能运行在相同Node上,这时就需要使用Pod的非亲和性了。

  3. 污点 和 污点容忍调度
   Taints(污点):是定义在Node上的
   Tolerations(容忍): 是定义在Pod上的
    污点:指有时我们希望不将某些Pod调度到某些Node上,这时我们可对某些Node上打上污点,然后,当我们创建Pod时,我们可定义此Pod能容忍的污点范围。
    假如:NodeA上有5个污点: "吃喝嫖赌抽",而此次要调度的Pod比较大度,能容忍5个污点,而NodeA的污点正好是Pod能容忍污点的范围内,于是Pod就能"嫁入"该NodeA。
    假如,Pod运行到NodeA上后,后期我们又给该NodeA打上了新污点如:"坑蒙拐骗偷",此时Pod发现NodeA的恶性原来有这么多,怎么办?通常有两种选择策略:
    1. Pod继续运行在NodeA上"艰苦度日"
    2. Pod被驱逐,或者叫Pod逃离。 

  kube-scheduler给一个pod做调度选择包含两个步骤:

    1)过滤
    2)打分

  过滤阶段会将所有满足调度需求的node选择出来。例如,PodFitsResources 过滤函数会检查候选 Node 的可用资源能否满足 Pod 的资源请求。在过滤之后,得出一个Node列表,里面包含了所有可调度节点;通常情况下,这个Node列表不止一个Node。如果这个列表是空的,说明这个pod不可调度。

  在打分阶段,调度器会为pod在所有可调度节点中选择最合适的Node。根据当前的打分规则,调度器会给每一个可调度节点进行打分。

  最后,kube-scheduler会将pod调度到得分最高的Node上。如果存在多个得分最高的Node,kube-scheduler会从中随机选择一个。

  默认策略
  kube-scheduler 有一系列的默认调度策略。

  过滤策略

  • PodFitsHostPorts:如果 Pod 中定义了 hostPort 属性,那么需要先检查这个指定端口是否 已经被 Node 上其他服务占用了。
  • PodFitsHost:若 pod 对象拥有 hostname 属性,则检查 Node 名称字符串与此属性是否匹配。
  • PodFitsResources:检查 Node 上是否有足够的资源(如,cpu 和内存)来满足 pod 的资源请求。
  • PodMatchNodeSelector:检查 Node 的 标签 是否能匹配 Pod 属性上 Node 的 标签 值。
  • NoVolumeZoneConflict:检测 pod 请求的 Volumes 在 Node 上是否可用,因为某些存储卷存在区域调度约束。
  • NoDiskConflict:检查 Pod 对象请求的存储卷在 Node 上是否可用,若不存在冲突则通过检查。
  • MaxCSIVolumeCount:检查 Node 上已经挂载的 CSI 存储卷数量是否超过了指定的最大值。
  • CheckNodeMemoryPressure:如果 Node 上报了内存资源压力过大,而且没有配置异常,那么 Pod 将不会被调度到这个 Node 上。
  • CheckNodePIDPressure:如果 Node 上报了 PID 资源压力过大,而且没有配置异常,那么 Pod 将不会被调度到这个 Node 上。
  • CheckNodeDiskPressure:如果 Node 上报了磁盘资源压力过大(文件系统满了或者将近满了), 而且配置没有异常,那么 Pod 将不会被调度到这个 Node 上。
  • CheckNodeCondition:Node 可以上报其自身的状态,如磁盘、网络不可用,表明 kubelet 未准备好运行 pod。 如果 Node 被设置成这种状态,那么 pod 将不会被调度到这个 Node 上。
  • PodToleratesNodeTaints:检查 pod 属性上的 tolerations 能否容忍 Node 的 taints。
  • CheckVolumeBinding:检查 Node 上已经绑定的和未绑定的 PVCs 能否满足 Pod 对象的存储卷需求。

  打分策略

  • SelectorSpreadPriority:尽量将归属于同一个 Service、StatefulSet 或 ReplicaSet 的 Pod 资源分散到不同的 Node 上。
  • InterPodAffinityPriority:遍历 Pod 对象的亲和性条目,并将那些能够匹配到给定 Node 的条目的权重相加,结果值越大的 Node 得分越高。
  • LeastRequestedPriority:空闲资源比例越高的 Node 得分越高。换句话说,Node 上的 Pod 越多,并且资源被占用的越多,那么这个 Node 的得分就会越少。
  • MostRequestedPriority:空闲资源比例越低的 Node 得分越高。这个调度策略将会把你所有的工作负载(Pod)调度到尽量少的 Node 上。
  • RequestedToCapacityRatioPriority:为 Node 上每个资源占用比例设定得分值,给资源打分函数在打分时使用。
  • BalancedResourceAllocation:优选那些使得资源利用率更为均衡的节点。
  • NodePreferAvoidPodsPriority:这个策略将根据 Node 的注解信息中是否含有 scheduler.alpha.kubernetes.io/preferAvoidPods 来 计算其优先级。使用这个策略可以将两个不同 Pod 运行在不同的 Node 上。
  • NodeAffinityPriority:基于 Pod 属性中 PreferredDuringSchedulingIgnoredDuringExecution 来进行 Node 亲和性调度。你可以通过这篇文章 Pods 到 Nodes 的分派 来了解到更详细的内容。
  • TaintTolerationPriority:基于 Pod 中对每个 Node 上污点容忍程度进行优先级评估,这个策略能够调整待选 Node 的排名。
  • ImageLocalityPriority:Node 上已经拥有 Pod 需要的 容器镜像 的 Node 会有较高的优先级。
  • ServiceSpreadingPriority:这个调度策略的主要目的是确保将归属于同一个 Service 的 Pod 调度到不同的 Node 上。如果 Node 上 没有归属于同一个 Service 的 Pod,这个策略更倾向于将 Pod 调度到这类 Node 上。最终的目的:即使在一个 Node 宕机之后 Service 也具有很强容灾能力。
  • CalculateAntiAffinityPriorityMap:这个策略主要是用来实现pod反亲和。
  • EqualPriorityMap:将所有的 Node 设置成相同的权重为 1。

  4、调度器性能调优

  在大规模 Kubernetes 集群下调度器性能优化的方式。

  设置打分阶段 Node 数量占集群总规模的百分比

  在Kubernetes1.12版本之前,kube-scheduler会检查集群中所有节点的可调度性,并且给可调度节点打分。Kubernetes1.12版本添加了一个新的功能,允许调度器在找到一定数量的可调度节点之后就停止继续寻找可调度节点。

  该功能能提高调度器在大规模集群下的调度性能。这个数值是集群规模的百分比。这个百分比通过 percentageOfNodesToScore 参数来进行配置。其值的范围在1到100之间,最大值就是100%。如果设置为0就代表没有提供这个参数配置。

  Kubernetes1.14版本又加入了一个特性,在该参数没有被用户配置的情况下,调度器会根据集群的规模自动设置一个集群比例,然后通过这个比例筛选一定数量的可调度节点进入打分阶段。该特性使用线性公式计算出集群比例,如在100-node 的集群下取 50%。在 5000-node 的集群下取 10%。这个自动设置的参数的最低值是5%。换句话说,调度器至少会对集群中 5% 的节点进行打分,除非用户将该参数设置的低于5。

  注意: 当集群中的可调度节点少于 50 个时,调度器仍然会去检查所有的 Node,因为可调度节点太少,不足以停止调度器最初的过滤选择。

  如果想要关闭这个功能,你可以将 percentageOfNodesToScore 值设置成 100。

  调节 percentageOfNodesToScore 参数

  percentageOfNodesToScore 的值必须在 1 到 100 之间,而且其默认值是通过集群的规模计算得来的。另外,还有一个 50 个 Node 的数值是硬编码在程序里面的。设置这个值的作用在于:当集群的规模是数百个 Node 并且percentageOfNodesToScore 参数设置的过低的时候,调度器筛选到的可调度节点数目基本不会受到该参数影响。当集群规模较小时,这个设置将导致调度器性能提升并不明显。然而在一个超过 1000 个 Node 的集群中,将调优参数设置为一个较低的值可以很明显的提升调度器性能。

  值得注意的是,该参数设置后可能会导致只有集群中少数节点被选为可调度节点,很多 node 都没有进入到打分阶段。这样就会造成一种后果,一个本来可以在打分阶段得分很高的 Node 甚至都不能进入打分阶段。由于这个原因,这个参数不应该被设置成一个很低的值。通常的做法是不会将这个参数的值设置的低于 10。很低的参数值一般在调度器的吞吐量很高且对 node 的打分不重要的情况下才使用。换句话说,只有当你更倾向于在可调度节点中任意选择一个 Node 来运行这个 Pod 时,才使用很低的参数设置。

如果你的集群规模只有数百个节点或者更少,我们并不推荐你将这个参数设置得比默认值更低。因为这种情况下不太可能有效的提高调度器性能。

  调度器做调度选择的时候如何覆盖所有的 Node

  在将 Pod 调度到 Node 上时,为了让集群中所有 Node 都有公平的机会去运行这些 Pod,调度器将会以轮询的方式覆盖全部的 Node。你可以将 Node 列表想象成一个数组。调度器从数组的头部开始筛选可调度点依次向后直到可调度节点的数量达到 percentageOfNodesToScore 参数的要求。

  在对下一个 Pod 进行调度的时候,前一个 Pod 调度筛选停止的 Node 列表的位置,将会来作为这次调度筛选 Node 开始的位置。

  如果集群中的 Node 在多个区域,那么调度器将从不同的区域中轮询 Node,来确保不同区域的 Node 接受可调度性检查。如下例,考虑两个区域中的六个节点:

Zone 1: Node 1, Node 2, Node 3, Node 4
Zone 2: Node 5, Node 6

  调度器将会按照如下的顺序去评估 Node 的可调度性:

Node 1, Node 5, Node 2, Node 6, Node 3, Node 4

  在评估完所有 Node 后,将会返回到 Node 1,从头开始。

  三)controller-manager

  从逻辑上讲,每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在一个进程中运行。

  以守护进程的形式运行着kubernetes几个核心的控制循环(控制器)。包括deployment、replicaset、namespace、serviceaccount、node等等(以及下面的控制器),通过apiserver的list watch接口监控自己负责的资源的配置变化。

  1、controller manager组成

  Controller Manager 由 kube-controller-manager 和 cloud-controller-manager 组成, 是Kubernetes 的大脑, 它通过 apiserver 监控整个集群的状态, 并确保集群处于预期的工作状态。

    1)kube-controller-manager 组成
  • 节点控制器(Node Controller): 负责在节点出现故障时进行通知和响应
  • 任务控制器(Job controller): 监测代表一次性任务的 Job 对象,然后创建 Pods 来运行这些任务直至完成
  • 端点控制器(Endpoints Controller): 填充端点(Endpoints)对象(即加入 Service 与 Pod)
  • 服务帐户和令牌控制器(Service Account & Token Controllers): 为新的命名空间创建默认帐户和 API 访问令牌

  必须启动的控制器

EndpointController
ReplicationController
PodGCController
ResourceQuotaController
NamespaceController
ServiceAccountController
GarbageCollectorController
DaemonSetController
JobController
DeploymentController
ReplicaSetController
HPAController
DisruptionController
StatefulSetController
CronJobController
CSRSigningController
CSRApprovingController
TTLController

  默认启动的可选控制器,可通过选项设置是否开启

TokenController
NodeController
ServiceController
RouteController
PVBinderController
AttachDetachController

  默认禁止的可选控制器,可通过选项设置是否开启

BootstrapSignerController
TokenCleanerController

 

    2)cloud-controller-manager 组成

  在 Kubernetes 启用 Cloud Provider 的时候才需要, 用来配合云服务提供商的控制, 也包括一系列的控制器

Node Controller
Route Controller
Service Controller

  从v1.6开始,cloud provider已经经历了几次重大重构,以便在不修改Kubernetes核心代码的同时构建自定义的云服务商支持

  2、常见Pod控制器及含义

    1)Replication Controller

  Replication Controller 保证了在所有时间内,都有特定数量的Pod副本正在运行,如果太多了,Replication Controller就杀死几个,如果太少了,Replication Controller会新建几个,和直接创建的pod不同的是,Replication Controller会替换掉那些删除的或者被终止的pod,不管删除的原因是什么(维护阿,更新啊,Replication Controller都不关心)。基于这个理由,我们建议即使是只创建一个pod,我们也要使用Replication Controller。Replication Controller 就像一个进程管理器,监管着不同node上的多个pod,而不是单单监控一个node上的pod,Replication Controller 会委派本地容器来启动一些节点上服务(Kubelet ,Docker)。
  Replication Controller只会对那些RestartPolicy = Always的Pod的生效,(RestartPolicy的默认值就是Always),Replication Controller 不会去管理那些有不同启动策略pod
  Replication Controller永远不会自己关闭,但是,我们并不希望Replication Controller成为一个长久存在的服务。服务可能会有多个Pod组成,这些Pod又被多个Replication Controller控制着,我们希望Replication Controller 会在服务的生命周期中被删除和新建(例如在这些pod中发布一个更新),对于服务和用户来说,Replication Controller是通过一种无形的方式来维持着服务的状态

    2)ReplicaSets

  ReplicaSet是下一代复本控制器。ReplicaSet和 Replication Controller之间的唯一区别是现在的选择器支持。Replication Controller只支持基于等式的selector(env=dev或environment!=qa),但ReplicaSet还支持新的,基于集合的selector(version in (v1.0, v2.0)或env notin (dev, qa))。
  大多数kubectl支持Replication Controller的命令也支持ReplicaSets。rolling-update命令有一个例外 。如果想要滚动更新功能,请考虑使用Deployments。此外, rolling-update命令是必须的,而Deployments是声明式的,因此我们建议通过rollout命令使用Deployments。
  虽然ReplicaSets可以独立使用,但是今天它主要被 Deployments 作为协调pod创建,删除和更新的机制。当使用Deployments时,不必担心管理他们创建的ReplicaSets。Deployments拥有并管理其ReplicaSets。

    3)Deployment

  Deployment为Pod和Replica Set(下一代Replication Controller)提供声明式更新。
  你只需要在Deployment中描述你想要的目标状态是什么,Deployment controller就会帮你将Pod和Replica Set的实际状态改变到你的目标状态。你可以定义一个全新的Deployment,也可以创建一个新的替换旧的Deployment。

  一个典型的用例如下:

  1. 使用Deployment来创建ReplicaSet。ReplicaSet在后台创建pod。检查启动状态,看它是成功还是失败。
  2. 然后,通过更新Deployment的PodTemplateSpec字段来声明Pod的新状态。这会创建一个新的ReplicaSet,Deployment会按照控制的速率将pod从旧的ReplicaSet移动到新的ReplicaSet中。
  3. 如果当前状态不稳定,回滚到之前的Deployment revision。每次回滚都会更新Deployment的revision。
  4. 扩容Deployment以满足更高的负载。
  5. 暂停Deployment来应用PodTemplateSpec的多个修复,然后恢复上线。
  6. 根据Deployment 的状态判断上线是否hang住了。
  7. 清除旧的不必要的ReplicaSet。
    4)StatefulSet

  StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括

  1. 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
  2. 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
  3. 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
  4. 有序收缩,有序删除(即从N-1到0)

  StatefulSet由以下几个部分组成:

  1. 用于定义网络标志(DNS domain)的Headless Service
  2. 用于创建PersistentVolumes的volumeClaimTemplates
  3. 定义具体应用的StatefulSet

  StatefulSet中每个Pod的DNS格式为statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local,其中

  1. serviceName为Headless Service的名字
  2. 0..N-1为Pod所在的序号,从0开始到N-1
  3. statefulSetName为StatefulSet的名字
  4. namespace为服务所在的namespace,Headless Servic和StatefulSet必须在相同的namespace
  5. .cluster.local为Cluster Domain
    5)DaemonSet

  DaemonSet保证在每个Node上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。典型的应用包括:

  1. 日志收集,比如fluentd,logstash等
  2. 系统监控,比如Prometheus Node Exporter,collectd,New Relic agent,Ganglia gmond等
  3. 系统程序,比如kube-proxy, kube-dns, glusterd, ceph等
     6) ResourceQuota Controller

  资源配额管理确保指定的资源对象在任何时候都不会超量占用系统物理资源。
  支持三个层次的资源配置管理:

1)容器级别:对CPU和Memory进行限制
2)Pod级别:对一个Pod内所有容器的可用资源进行限制
3)Namespace级别:包括

    Pod数量
    Replication Controller数量
    Service数量
    ResourceQuota数量
    Secret数量
    可持有的PV(Persistent Volume)数量
k8s配额管理是通过Admission Control(准入控制)来控制的;
Admission Control提供两种配额约束方式:LimitRanger和ResourceQuota;
LimitRanger作用于Pod和Container;
ResourceQuota作用于Namespace上,限定一个Namespace里的各类资源的使用总额。
    7)Namespace Controller

  用户通过API Server可以创建新的Namespace并保存在etcd中,Namespace Controller定时通过API Server读取这些Namespace信息。

  如果Namespace被API标记为优雅删除(即设置删除期限,DeletionTimestamp),则将该Namespace状态设置为“Terminating”,并保存到etcd中。同时Namespace Controller删除该Namespace下的ServiceAccount、RC、Pod等资源对象。

    8)Endpoint Controller

  Service、Endpoint、Pod的关系

  Endpoints表示了一个Service对应的所有Pod副本的访问地址,而Endpoints Controller负责生成和维护所有Endpoints对象的控制器。它负责监听Service和对应的Pod副本的变化。

如果监测到Service被删除,则删除和该Service同名的Endpoints对象;
如果监测到新的Service被创建或修改,则根据该Service信息获得相关的Pod列表,然后创建或更新Service对应的Endpoints对象。
如果监测到Pod的事件,则更新它对应的Service的Endpoints对象。

  

  kube-proxy进程获取每个Service的Endpoints,实现Service的负载均衡功能。

    9)Service Controller

  Service Controller是属于kubernetes集群与外部的云平台之间的一个接口控制器。Service Controller监听Service变化,如果是一个LoadBalancer类型的Service,则确保外部的云平台上对该Service对应的LoadBalancer实例被相应地创建、删除及更新路由转发表

    10)Node Controller

  kubelet在启动时会通过API Server注册自身的节点信息,并定时向API Server汇报状态信息,API Server接收到信息后将信息更新到etcd中。

  Node Controller通过API Server实时获取Node的相关信息,实现管理和监控集群中的各个Node节点的相关控制功能。流程如下

  1. Controller Manager在启动时如果设置了–cluster-cidr参数,那么为每个没有设置Spec.PodCIDR的Node节点生成一个CIDR地址,并用该CIDR地址设置节点的Spec.PodCIDR属性,防止不同的节点的CIDR地址发生冲突。
  2. 具体流程见以上流程图。
  3. 逐个读取节点信息,如果节点状态变成非“就绪”状态,则将节点加入待删除队列,否则将节点从该队列删除。

  四)etcd

  etcd在kubernetes集群是用来存放数据并通知变动的。
  Kubernetes中没有用到数据库,它把关键数据都存放在etcd中,这使kubernetes的整体结构变得非常简单。

  在kubernetes中,数据是随时发生变化的,比如说用户提交了新任务、增加了新的Node、Node宕机了、容器死掉了等等,都会触发状态数据的变更。状态数据变更之后呢,Master上的kube-scheduler和kube-controller-manager,就会重新安排工作,它们的工作安排结果也是数据。这些变化,都需要及时地通知给每一个组件。

  etcd有一个特别好用的特性,可以调用它的api监听其中的数据,一旦数据发生变化了,就会收到通知。有了这个特性之后,kubernetes中的每个组件只需要监听etcd中数据,就可以知道自己应该做什么。kube-scheduler和kube-controller-manager呢,也只需要把最新的工作安排写入到etcd中就可以了,不用自己费心去逐个通知了

    • http server:(在etcd3里面变成grpc server),主要处理client的操作请求以及节点间的数据同步和心跳保持

    • raft状态机:通过对raft一致性协议的实现来保证etcd集群的高可用

    • store:负责ecd中事务操作的逻辑,是api server的命令的具体体现

    • wal存储:负责具体的数据持久存储操作。它分为两部分

      • entry 负责实际的日志数据存储(在etcd里数据的存储都是带版本号的,对于同一个键值可能有多个版本的记录存在,所以数据的存储方式即通过食物日志进行存储,而在内存里存有键和版本号的映射关系以方便查询)

      • snapshot 则是对日志数据的状态存储,应防止过多的数据存在

三、kubernetes worker 节点组件

  一)kubelet

  一个在集群中每个节点(node)上运行的代理。它保证容器(containers)都运行在pod中。

  kubelet接收一组通过各机制提供给它的PodSpecs,确保这些PodSpecs中描述的容器处于运行状态且健康。kubelet不会管理不是由kubernetes创建的容器。

  二)kube-proxy

  kube-proxy是集群中每个节点上运行的网络代理,实现kubernetes服务概念的一部分。

  维护主机上kube服务涉及的网络规则和连接转发,负责service的实现,采用IPVs

  由于IPVS的优势,所以尽可能的采用IPVS作为kube-proxy的工作模式

  kube-proxy有如下三种工作模式

  三)Container Runtime:容器引擎docker

  容器运行环境是负责运行容器的软件。

  Kubernetes 支持多个容器运行环境: Docker、 containerdCRI-O 以及任何实现 Kubernetes CRI (容器运行环境接口)

四、CNI网络组件

  一)CNi:

  1、什么是CNI?

       CNI是Container Network Interface的缩写,是一个标准的通用的接口。为了让用户在容器创建或销毁时都能够更容易地配置容器网络,现在容器平台:docker,kubernetes,mesos。

  2、CNI如何实现?

  CNI用于连接容器管理系统和网络插件。提供一个容器所在的network namespace,将network interface插入该network namespace中(比如veth的一端),并且在宿主机做一些必要的配置(例如将veth的另一端加入bridge中),最后对namespace中的interface进行IP和路由的配置。

  CNI插件是可执行文件,会被kubelet调用。启动kubelet --network-plugin=cni,--cni-conf-dir 指定networkconfig配置,默认路径是:/etc/cni/net.d,并且,--cni-bin-dir 指定plugin可执行文件路径,默认路径是:/opt/cni/bin

  二)网络解决方案:

     容器网络解决方案:flannel、calico、weave、Canal、Terway、以及 Contiv。

  1、Flannel:

  在默认的Docker配置中,每个节点上的Docker服务会分别负责所在节点容器的IP分配。这样导致的一个问题是,不同节点上容器可能获得相同的内外IP地址。

      Flannel的功能简单的来讲就是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址。 

  Flannel的设计目的就是为集群中的所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得同属一个内网且不重复的IP地址,并让属于不同节点上的容器能够直接通过内网IP通信。

  Flannel实质上是一种覆盖网络(overlay network),也就是将TCP数据包装在另一种网络包里面进行路由转发和通信,目前已经支持udp、vxlan、host-gw、aws-vpc、gce和alloc路由等数据转发方式,常用的的三种转发模式。

 

hostgw 这种方式就是直接路由 (性能最高 要求集群节点在同一个网段)
vxlan 是flannel推荐的方式。需要通信的网络设备能够支持vxlan协议 (性能较好)
udp 该方式与vxlan很类似,它对ip层网络进行包装。通常用于调试环境或者不支持vxlan协议网络环境中。(性能最差)
 

  优点:

                1.Flannel相对容易安装和配置。

                2.支持多个Kubernetes发行版。

                3.使集群中的不同Node主机创建的Docker容器都具有全集群唯一的虚拟IP地址。

                4.Flannel可以使用Kubernetes集群的现有etcd集群来使用API存储其状态信息,因此不需要专用的数据存储。

                5.默认路由使用的方法是使用VXLAN,因为VXLAN性能更良好并且需要的手动干预更少。

 

        缺点:

                1.不支持pod之间的网络隔离。Flannel设计思想是将所有的pod都放在一个大的二层网络中,所以pod之间没有隔离策略。

                2.由于使用二层技术,vlan 隔离和 tunnel 隧道则消耗更多的资源并对物理环境有要求,随着网络规模的增大,整体会变得越加复杂在 较大的k8s集群规模下不适用。

  2、Calico:

  calico是基于BGP路由实现的容器集群网络方案,Calico是一个纯三层的协议,使用虚拟路由代替虚拟交换。与 Flannel 不同的是 Calico 不使用隧道或 NAT 来实现转发,而是巧妙的把所有二三层流量转换成三层流量,并通过 host 上路由配置完成跨 Host 转发。

  基础的calico使用体验可能和flannel host-gw是基本一样的。Calico在每个计算节点都利用Linux Kernel实现了一个高效的虚拟路由器vRouter来负责数据转发。每个vRouter都通过BGP1协议把在本节点上运行的容器的路由信息向整个Calico网络广播,并自动设置到达其他节点的路由转发规则。

  Calico保证所有容器之间的数据流量都是通过IP路由的方式完成互联互通的。Calico节点组网时可以直接利用网络结构,不需要额外的NAT、隧道或者Overlay Network,没有额外的封包解包,能够节约CPU运算,提高网络效率。支持两种网络IPIP、BGP

  优点:

            1.二层网络通讯需要依赖广播消息机制,广播消息的开销与 host 的数量呈指数级增长,Calico 使用的三层路由方法,完全抑制了二层广播,减少了资源开销,不需要额外的NAT,隧道或者Overlay Network。

            2.不同之处在于flannel方案下路由都是通过代码逻辑进行配置。calico会在每个节点建立bgp peer,bgp peer彼此之间会进行路由的共享和学习,所以自动生成并维护了路由。在k8s集群大规模的情况下集群间的网络保持通畅。

            3.Calico 较少的依赖性使它能适配所有 VM、Container、混合环境场景。

            4.支持network-policy,自定义ingress(进栈)egress(出栈)规则。

            5.传输性能方便高于Flannel,自定义隔离pod间通信。

 
  缺点:

            1.通过路由规则可以看出,路由规模和 pod 分布有关,如果 pod离散分布在 host 集群中,会产生较多的路由项。

            2.1台 Host 上可能虚拟化十几或几十个容器实例,过多的 iptables 规则造成复杂性和不可调试性,同时也存在性能损耗。

            3.网关路由问题,当对端网络不为二层可达时,需要通过三层路由机时,需要网关支持自定义路由配置,即 pod 的目的地址为本网段的网关地址,再由网关进行跨三层转发。

            4.简单使用和flannel无异,深层的使用需要有较高的学习成本。

  3、Weave Net:

  和flannel一样它能够创建一个虚拟网络,用于连接部署在多台主机上的Docker容器,这样容器就像被接入了同一个网络交换机,那些使用网络的应用程序不必去配置端口映射和链接等信息。外部设备能够访问Weave网络上的应用程序容器所提供的服务,同时已有的内部系统也能够暴露到应用程序容器上。Weave能够穿透防火墙并运行在部分连接的网络上。与Calico一样,Weave也为Kubernetes集群提供网络策略功能。Weave通过UDP封装实现L2 Overlay,封装支持两种模式,一种是运行在user space的sleeve mode,另一种是运行在kernal space的 fastpath mode。
     

   优点:

               1.Weave通过创建虚拟网络使Docker容器能够跨主机通信并能够自动相互发现。

               2.通过weave网络,由多个容器构成的基于微服务架构的应用可以运行在任何地方主机,多主机,云上或者数据中心。应用程序使用网络就好像容器是插在同一个网络交换机上一样,不需要配置端口映射,连接等。

               3.Weave网络自动在两个节点之间选择最快的路径,提供接近本地网络的吞吐量和延迟。同时支持主机间通信加密。

               4.Weave网络能够在节点间转发流量,它甚至能够在网状网络部分连接的情况下工作。这意味着你可以在混合了传统系统和容器化的应用的环境中使用Weave网络来保持通信。

  缺点:

               1.只能通过weave launch或者weave connect加入weave网络。

  4、Canal:

          Canal 是一个项目的名称,它试图将Flannel提供的网络层与Calico的网络策略功能集成在一起。Canal名称的由来是Flannel和Calico的结合,最终只实现了将两种技术部署在一起的预期能力。出于这个原因,即使这个项目不复存在,业界还是会习惯性地将Flannel和Calico的组成称为“Canal”。由于Canal是Flannel和Calico的组合,因此它的优点也在于这两种技术的交叉。网络层用的是Flannel提供的简单overlay,可以在许多不同的部署环境中运行且无需额外的配置。在网络策略方面,Calico强大的网络规则评估,为基础网络提供了更多补充,从而提供了更多的安全性和控制。
 
  优点:集成Flannel和Calico和功能。
  缺点:部署相对比较复杂,维护和配置有较高的学习成本。

  5、Terway:

       Terway是阿里云容器服务Kubernetes版自研的网络插件,使用原生的弹性网卡分配给Pod实现Pod网络。将阿里云的弹性网卡和辅助IP分配给容器,支持Network Policy来定义容器间的访问策略,支持对单个容器做带宽的限流,兼容Calico的Network Policy。在Terway网络插件中,每个Pod拥有自己网络栈和IP地址。同一台ECS内的Pod之间通信,直接通过机器内部的转发,跨ECS的Pod通信,报文通过VPC的弹性网卡直接转发。由于不需要使用VxLAN等的隧道技术封装报文,因此具有较高的通信性能。
      
       优点:相比Flannel支持了Network Policy访问策略,支持对单个容器做带宽对限流。
       缺点:依赖与阿里云服务器平台。

  6、Contiv:

        Contiv是一个用于跨虚拟机、裸机、公有云或私有云的异构容器部署的开源容器网络架构。Contiv具有2层、3层、overlay和ACI模式,能够与思科基础设施进行本地集成,并使用丰富的网络和安全策略将应用意图与基础设施功能进行映射。能够和非容器环境协作,不依赖物理网络。支持物理网卡sriov和offload。支持Policy/ACI/Qos租户,并支持L2(VLAN), L3(BGP), Overlay (VXLAN)。
  优点

              1.集成Flannel和Calico所有的功能。

              2.能够与思科基础设施完美的集成。

              3.支持物理网卡sriov和offload。支持Policy/ACI/Qos租户。

              4.支持L2(VLAN), L3(BGP), Overlay (VXLAN)。 

  缺点

               1.集成配置比较复杂,学习资料少。

               2.学习成本较高,需要定制化开发

五、kubernetes核心组件:附加(add-on)组件

  一)DNS(kubeDNS / coreDNS)

  尽管其他插件都并非严格意义上的必需组件,但几乎所有 Kubernetes 集群都应该 有集群 DNS, 因为很多示例都需要 DNS 服务。

  集群 DNS 是一个 DNS 服务器,和环境中的其他 DNS 服务器一起工作,它为 Kubernetes 服务提供 DNS 记录。

  Kubernetes 启动的容器自动将此 DNS 服务器包含在其 DNS 搜索列表中。

  二)dashboard

  Dashboard 是Kubernetes 集群的通用的、基于 Web 的用户界面。 它使用户可以管理集群中运行的应用程序以及集群本身并进行故障排除

  三)heapster

 

  四)ingress controller

  五)EFK

六、资源清单说明

  一)endpoint

  1、概述

  endpoint是k8s集群中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址。service配置selector,endpoint controller才会自动创建对应的endpoint对象;否则,不会生成endpoint对象。例如,k8s集群中创建一个名为hello的service,就会生成一个同名的endpoint对象,ENDPOINTS就是service关联的pod的ip地址和端口。

  一个 Service 由一组 backend Pod 组成。这些 Pod 通过 endpoints 暴露出来。 Service Selector 将持续评估,结果被 POST 到一个名称为 Service-hello 的 Endpoint 对象上。 当 Pod 终止后,它会自动从 Endpoint 中移除,新的能够匹配上 Service Selector 的 Pod 将自动地被添加到 Endpoint 中。 检查该 Endpoint,注意到 IP 地址与创建的 Pod 是相同的。现在,能够从集群中任意节点上使用 curl 命令请求 hello Service <CLUSTER-IP>:<PORT> 。 注意 Service IP 完全是虚拟的,它从来没有走过网络,如果对它如何工作的原理感到好奇,可以阅读更多关于 服务代理 的内容。

  Endpoints是实现实际服务的端点集合。

  Kubernetes在创建Service时,根据Service的标签选择器(Label Selector)来查找Pod,据此创建与Service同名的EndPoints对象。当Pod的地址发生变化时,EndPoints也随之变化。Service接收到请求时,就能通过EndPoints找到请求转发的目标地址。

  Service不仅可以代理Pod,还可以代理任意其他后端,比如运行在Kubernetes外部Mysql、Oracle等。这是通过定义两个同名的service和endPoints来实现的。

  在实际的生产环境使用中,通过分布式存储来实现的磁盘在mysql这种IO密集性应用中,性能问题会显得非常突出。所以在实际应用中,一般不会把mysql这种应用直接放入kubernetes中管理,而是使用专用的服务器来独立部署。而像web这种无状态应用依然会运行在kubernetes当中,这个时候web服务器要连接kubernetes管理之外的数据库,有两种方式:一是直接连接数据库所在物理服务器IP,另一种方式就是借助kubernetes的Endpoints直接将外部服务器映射为kubernetes内部的一个服务。

  简单认为:动态存储pod名字与pod ip对应关系的list,并提供将请求转发到实际pod上的能力

  2、kubernetes发布tomcat服务,通过deployment,service布署

  service及deployment的yaml文件

[root@k8s-master ~]# pwd
/root
[root@k8s-master ~]# cat deployment-hello.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 4
  template:
    metadata:
      labels:
        run: hello
    spec:
      containers:
       - name: hello
         image: tomcat:8 #确保node节点上有该镜像且可正常运行,注意是node节点机器上,不是master机器
         imagePullPolicy: IfNotPresent ##Always,IfNotPresent,Never
         ports:
         - name: http
           containerPort: 8080

 

[root@k8s-master ~]# cat service-hello.yaml 
apiVersion: v1
kind: Service
metadata:
  name: service-hello
  labels:
  name: service-hello
spec:
  type: NodePort      #这里代表是NodePort类型的,另外还有ingress,LoadBalancer
  ports:
  - port: 80          #这里的端口和clusterIP(kubectl describe service service-hello中的IP的port)对应,即在集群中所有机器上curl 10.98.166.242:80可访问发布的应用服务。
    targetPort: 8080  #端口一定要和container暴露出来的端口对应,nodejs暴露出来的端口是8081,所以这里也应是8081
    protocol: TCP
    nodePort: 31111   # 所有的节点都会开放此端口30000--32767,此端口供外部调用。
  selector:
    run: hello         #这里选择器一定要选择容器的标签,之前写name:kube-node是错的。
[root@k8s-master ~]# pwd
/root

  创建service

[root@k8s-master ~]# kubectl create -f service-hello.yaml 
service/service-hello created

[root@k8s-master ~]# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4h24m
service-hello NodePort 10.98.166.242 <none> 80:31111/TCP 42s
[root@k8s-master ~]#

root@k8s-master ~]# kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4h25m <none>
service-hello NodePort 10.98.166.242 <none> 80:31111/TCP 104s run=hello

[root@k8s-master ~]# kubectl describe service service-hello
Name:                     service-hello
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 run=hello
Type:                     NodePort
IP:                       10.98.166.242
Port:                     <unset>  80/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  31111/TCP
Endpoints:                10.244.1.22:8080,10.244.1.23:8080,10.244.1.24:8080 + 1 more...
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>
[root@k8s-master ~]#

  endpoint

[root@k8s-master ~]# kubectl get endpoints
NAME            ENDPOINTS                                                        AGE
kubernetes      192.168.111.130:6443                                             20h
service-hello   10.244.1.22:8080,10.244.1.23:8080,10.244.1.24:8080 + 1 more...   15h
[root@k8s-master ~]# kubectl describe endpoint service-hello
error: the server doesn\'t have a resource type "endpoint"
[root@k8s-master ~]# kubectl describe endpoints service-hello
Name:         service-hello
Namespace:    default
Labels:       <none>
Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2019-04-03T02:18:57Z
Subsets:
  Addresses:          10.244.1.22,10.244.1.23,10.244.1.24,10.244.1.25
  NotReadyAddresses:  <none>
  Ports:
    Name     Port  Protocol
    ----     ----  --------
    <unset>  8080  TCP

Events:
  Type     Reason                  Age                From                 Message
  ----     ------                  ----               ----                 -------
  Warning  FailedToUpdateEndpoint  48m (x2 over 69m)  endpoint-controller  Failed to update endpoint default/service-hello: Operation cannot be fulfilled on endpoints "service-hello": the object has been modified; please apply your changes to the latest version and try again
[root@k8s-master ~]#