当前位置:   article > 正文

Kubernetes知识整理_kubernetes用到哪些知识

kubernetes用到哪些知识

架构

角色

Master

Kubernetes中的Master是集群的控制节点,每个Kubernetes集群里都需要有一个Master节点来负责整个集群的管理和控制。

Master节点上运行着以下一组关键进程:

  • Kubernetes API Server(kube-apiserver):提供了HTTP Rest接口的关键服务进程,是Kubernetes里所有资源的增、删、改、查等操作的唯一入口,也是集群控制的入口进程。
  • Kubernetes Controller Manager(kube-controller-manager):Kubernetes里所有资源对象的自动化控制中心,可以理解为资源对象的“大总管”。
  • Kuberbetes Scheduler(kube-scheduler):负责资源调度(Pod调度)的进程,相当于公交公司的“调度室”。

从Master运行的进程就可以看出Master的重要性,所以通常会单独占有一个服务器(高可用部署建议用3台服务器),一旦Master不可用,那么对集群内容器的管理都将失效:

  • kube-apiserver服务不可用,无法接收新的管理命令。
  • kube-controller-manager服务不可用,服务自动化管理就会失效,例如一个Deployment指定需要3个副本,当副本数!=3的时候,就需要靠kube-controller-manager来控制副本数变成3的。
  • kube-scheduler服务部可用,则会出现pod无法真正被分配到node上,因为pod与node的绑定,是scheduler的职责。

除此之外,Master节点还会运行etcd(分布式数据存储服务):kubernetes里的所有资源对象的数据全部是保存在etcd。

Node

集群中,非Master的节点被称为Node节点,Node节点才是Kuberbetes集群中的工作节点,每个Node都会被Master分配一些负载(Pod),当某个Node挂掉时,其上的工作负载会被Master自动转移到其他Node节点上。

每个Node节点上都运行着以下一组关键进程:

  • kubelet:负责Pod对应容器的创建、启停等任务,同时与Master节点协作(例如上报自己的状态、接收pod分配和移除的命令),实现集群管理的基本功能。
  • kube-proxy:实现Kubernetes Service的通信与负载均衡机制的重要组件。
  • Docker Engine:Docker引擎,负责本机的容器创建和管理工作。

组件

Kubernetes API Server

主要作用:

  • 集群管理的API入口
  • 资源配额控制的入口
  • 提供完备的集群安全机制

apiserver也是作为一个Service运行在k8s集群中,Service的名字是“kubernetes”,在集群内可以通过该域名来访问他,并且的它的Cluster IP地址是整个地址池的第一个地址!

apiserver提供一套REST接口用于管理资源对象的增、删、改、查和监听变化;还提供了一套特殊的proxy接口,将受到的REST请求转发到某个Node上的kubelet守护进程。

集群中各个功能模块之间就是通过apiserver提供的REST接口(GET、LIST和WATCH方法)来实现,从而实现各模块之间的信息交互。例如:

  • Node节点上的kubelet每隔一段时间周期就会调用一次apiserver的接口,上报自己的状态。
  • Controller Manager中的Node Controller模块通过watch接口,监控Node的信息,
  • kubelet-scheduler通过watch接口,监听需要新建的Pod服务信息后,检索所有符合该Pod要求的Node列表,然后执行Pod调度逻辑,调度成功后将Pod绑定到目标Node上。

Controller Manager

作为集群内部的管理控制中心,负责集群内的Node、Pod副本、Endpoint(服务端点)、Namespace(命名空间)、ServiceAccount(服务账号)、ResourceQuota(资源定额)等对象的管理。

内部包含:Relication Controller、Node Controller、ResourceQuota Controller、Namespace Controller、ServiceAccount Controller、Token Controller、Service Controller、Endpoint Controller等多个Controller,一种Controller就是管理一种资源对象。

Relication Controller

这里的Relication Controller不是资源对象RC,而是“副本控制器”。核心作用是确保集群中一个RC关联的Pod副本数量保持预设值:

  •  确保当前集群中有且仅有N个Pod实例,N是RC中定义的Pod副本数量。
  • 通过调整RC的spec.relicas属性值来实现系统扩容或者缩容。
  • 通过调整RC的Pod模板(主要是镜像版本)来实现系统的滚动升级。

Node Controller

kubelet进程在启动时,会通过apiserver注册自身的节点信息,并定时向apiserver汇报状态信息。

apiserver在收到这些信息后,会将信息更新到etcd中,etcd中存储的节点信息包括:节点健康状态、节点资源、节点名称、节点地址信息、操作系统版本、Docker版本、kubelet版本等。

Node Controller通过apiserver实时获取Node的相关信息,实现管理和监控集群中的各个节点的相关控制功能。节点的健康状态包含:就绪true、未就绪false和未知unknown。

例如,有个Node节点很久没有上报自己的状态,Node Controller就会变更该Node节点的状态为未就绪,然后出发集群的恢复动作(像重建未就绪节点上的Pod)。

ResourceQuota Controller

资源配额管理,该功能用于避免由于某些业务进程的涉及缺陷,导致整个系统运行絮乱甚至以外死机。在k8s中,主要由三个层次的资源配置管理:

  • 容器级别,可以对CPU和Memory进行限制。
  • Pod级别,可以对一个Pod内所有容器的可用资源进行限制。
  • Namespace级别,为Namespace(多租户)级别的资源限制。包括:Pod数量、RC数量、Service数量、ResourceQuota数量、Secret数量、可持有的PC数量。

k8s的资源配额管理是通过Admission Controller(准入控制)来控制的,当用户通过apiserver请求创建或修改资源时,Admission Controller会计算当前配合使用情况,如果不符合约束,则创建对象失败。

NamespaceController

用于可以通过apiserver创建或删除的Namesapce,Namespace Controller定时通过apiserver拉取Namespace的信息。如果Namespace被标记为优雅删除,则将该Namespace的状态设置为“Timinating”并保存到etcd中。

同时Namespace Controller删除该Namespace下的ServiceAccount、RC、Pod、secret、PersistentVolume、ListRange、ResourceQuota和Event等资源对象。

Service Controller

Service Controller属于k8s集群与外部的云平台之间的一个接口控制器。

Service Controller监听Service的变化,如果是一个LoadBalancer类型的Service,则Service Controller确保外部云平台上该Service对他的LoadBalancer实例被相应的创建、删除及更新理由转发表。

Endpoint Controller

Endpoint Controller监听Service和对应Pod的变化:

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

Scheduler

Kubernetes Scheduler在整个系统中承担“承上启下”的重要功能:

通过API创建新的Pod或者Controller Manager为补足副本数创建Pod后,Scheduler根据特定的调度算法和调度策略,将Pod绑定到集群的某个Node节点上,并写入etcd中。这就是所谓的“承上”。

Node接地上的Kubelet进程通过API Server的watch接口监听Pod和Node的绑定事件,当有新的Pod被绑定到自己身上,kubelet就会进行处理,负责Pod的下半生。这就是所谓的“启下”。

Scheduler默认调度流程分为两步:

  1. 预选调度过程:遍历所有目标Node,筛选出符合要求的候选节点。
  2. 确定最优节点:采用优选策略计算出每个候选节点的积分,积分最高者胜出。

预选策略有:

  • NoDiskConflict,没有磁盘冲突。
  • PodFitsResources,有足够的资源。节点上所有Pod的requests资源加上当前待分配Pod的资源是否超过Node的可用的总资源。
  • PodSelectorMatches,Pod中定义了nodeSelector,则要满足Pod的nodeSelector。
  • PodFitsHost,Pod如果定义了nodeName,则要满足Pod的nodeName=节点名称。
  • PodFitPorts,Pod要使用的端口是否被占用,不能有端口冲突。
  • CheckNodeLabelPresence,自定义的,太复杂,忽略~
  • CheckServiceAffinity,自定义的,太复杂,忽略~

默认的预选策略就是前面5个,要5个都通过了,node节点才会进行备选列表。

优选策略有:

  • LeastRequestedPriority,node上所有Pod加上待分配Pod的请求资源和系统总资源进行一个计算,得分高的优先:((nodeCpuCapacity-totalMilliCPU)*10 / nodeCpuCapacity + (nodeMemory-totalMemoey)*10 / nodeMemory) / 2
  • CalculateNodeLabelPriority,自定义,太复杂,忽略~
  • BalancedResourceAllocation,选择备选节点中,资源使用率最均衡的节点:10 - 10 * Math.abs(totalMilliCPU / nodeCpuCapacity - totalMemoey / nodeMemory)

Kubelet

在Kubernetes集群中,每个Node节点上都会启动一个kubelet服务进程。主要的职责有:

节点管理

一般把kubelet的启动参数设置为“--register-node”设置为true,向运行在Master上的API Server注册节点信息。并在之后,定时向API Server发送节点的新信息,API Server在接收到这些信息后,将这些信息写入etcd。

Pod管理

大部分情况下(非静态Pod),kubelet通过API Server监听etcd目录,同步Pod列表。

当发现有新的绑定到本节点的Pod,就会按照Pod清单的要求创建Pod。

如果发现删除本节点的Pod,则删除相应的Pod,并通过Docker client删除Pod中的容器。

如果监听到的信息是修改,则停止原来的Pod,启动新的Pod。

容器健康检查

执行LivenessProbe探针来判断容器健康状态。

执行ReadinessProbe探针来判断容器是否启动完成。

cAdvisor资源监控

cAdvisor自动查找在其所在节点上的容器,自动采集CPU、内存、文件系统和网络的使用统计信息。并且通过它所在节点机器的Root容器,采集并分析节点机器的全面使用情况。

Kubelet-proxy

Kubernetes集群上的每个Node上都会运行一个kube-proxy服务进程,这个进程可以看做Service的透明代理兼负载均衡器,其核心功能是将某个Service的访问请求转发到后端的多个Pod实例上。

kube-proxy通过查询和监听API Server中Service和Endpoints的变化,为每个Service都创建一个“服务代理对象”。

服务代理对象是kube-proxy内部的一个数据结构,其中包含了一个用于监听此服务请求的SocketServer。

SocketServer端口是随机选择一个本地空闲的端口,然后再通过修改Iptables,将Service的Cluster IP和NodePort上的流量转发到该随机端口上(NAT)。

kube-proxy内部创建了一个负载均衡器——LoadBalancer,上面保存了Service到对应后端的Endpoints列表的动态转发路由表(反向代理)。

相关资料:k8s四层负载均衡--Service - 运维人在路上 - 博客园

资源对象

Pod

Pod是kubernetes里最重要也是最基本的概念。

每个Pod都有一个特殊的被称为“根容器”的Pause容器,Pause容器术语Kubernetes平台的一部分;除了Pause容器外,一个Pod还会包含一个或多个紧密相关的用户业务容器。如下图:

kubernetes将Pod设计成这样的原因有:

  • 当一组容器作为一个单元的情况下,难以判断这个单元的健康状态。例如一个Pod里,运行3个容器,其中1个容器挂了,另外2个还正常运行,那这个pod算是死亡的,还是存活的?引入Pause“根容器”,直接以Pause的状态来代表整个Pod的状态,就简单了。
  • Pod里的多个业务容器共享Pause容器的IP,共享Pause容器挂载的Volume,这样就简化了密切关联的业务容器之间的通讯问题,例如另个容器之间需要共享文件,就很容易做到了。

每个Pod都会被分配一个唯一的IP,称为Pod IP,一个Pod中的多个容器共享Pod的IP地址。

Pod可以分为普通Pod静态Pod

普通Pod

普通的Pod一旦创建,就会被存储到etcd中,随后被Master中的Scheduler调度到某个具体的Node上并进行绑定,随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器,并启动起来。

静态Pod

不受Master节点的管理,而是直接在Node节点上直接运行,并且创建的静态Pod也不会存储到etcd中。

有两种配置方式:

  • 配置文件方式:kubelet的启动参数"--config”指定要监控的配置文件目录,kubelet会定期扫描该目录,将该目录下的yaml或json文件进行创建操作。
  • http方式:通过设置kubelet启动参数“--mainfest-url”,kubelet定期从该url地址下载pod的定义文件,以yaml或json格式解析。

无法与ReplicationController、Deployment或者DaemonSet进行关联,并且kubelet也无法对它们进行健康检查。

Pod生命周期

  • Pending,API Server已经创建了该Pod,但Pod内还有一个或多个容器的镜像没被创建,包括正在下载镜像的过程
  • Running,Pod内所有容器都已创建,且至少有一个容器处于运行、正在启动或正在重启状态。
  • Succeeded,Pod内所有容器全部成功执行退出,且不会再重启。
  • Failed,Pod内所有容器都已经退出,但至少有一个容器退出状态为失败。
  • Unknown,由于某种原因,无法获取Pod的状态,可能由于网络不通。

Pod的yaml定义如下:

  1. apiVersion: v1
  2. #版本号
  3. kind: Pod
  4. #Pod
  5. metadata:
  6. #元数据
  7. name: string
  8. #pod的名称
  9. namespace: string
  10. #pod所属的命名空间
  11. labels:
  12. #自定义标签列表
  13. - name: string
  14. annotations:
  15. #自定义注释列表
  16. - name: string
  17. spec:
  18. #初始化容器的配置
  19. initContainers:
  20. - name:
  21. image:
  22. command:
  23. #pod容器中的详细定义
  24. containers:
  25. #pod容器列表
  26. - name: string
  27. #容器的名称
  28. image: string
  29. #容器的镜像名称
  30. imagePullPolicy: [Always | Never | IfNotPresent]
  31. #镜像拉取策略,默认Always
  32. command: [string]
  33. #容器的启动命令列表,如不指定则使用镜像打包时实用的启动命令
  34. args: [string]
  35. #容器启动的命令参数列表
  36. workingDir: string
  37. #容器的工作目录
  38. volumeMounts:
  39. #挂载到容器内部的存储卷配置
  40. - name: string
  41. #引用pod定义的共享存储卷名称,需要与volumes[]部分定义的共享存储卷名称
  42. mountPath: string
  43. #存储卷在容器内Mount的绝对路径,应少于512字符
  44. readOnly: boolean
  45. #是否为只读模式,默认读写模式
  46. ports:
  47. #容器需要暴露的端口列表
  48. - name: string
  49. #端口的名称
  50. containerPort: int
  51. #容器需要监听的端口号
  52. hostPort: int
  53. #容器所在主机需要监听的端口号,默认与containerPort相同。设置hostPort时,同一台宿主机将无法启动该容器的第二副本。
  54. protocol: string
  55. #端口协议,支持TCP、UDP,默认TCP
  56. env:
  57. #容器运行前需要设置的环境变量列表
  58. - name: string
  59. #环境变量名称
  60. value: string
  61. #环境变量的值
  62. resources:
  63. #资源限制和资源请求的设置
  64. limits:
  65. #资源限制设置
  66. cpu: string
  67. #CPU限制,单位为core数,
  68. memory: string
  69. #内存限制,单位可为MiB,GiB
  70. requests:
  71. #资源限制设置
  72. cpu: string
  73. #CPU请求,容器启动初始可用数量
  74. memory: string
  75. #内存请求,容器启动初始可用数量
  76. livenessProbe:
  77. #对pod内各容器健康检查的设置,到探测到无响应几次后,系统将重启容器,可以设置的方法:exec、httpGet和tcpSocket
  78. #对于一个容器仅需设置一种健康检查方法
  79. exec:
  80. #对pod内各容器健康检查的设置
  81. command: [string]
  82. #exec方式需要指定的命令或脚本
  83. httpGet:
  84. #对pod各容器健康检查设置 ,需要指定path、port
  85. path: string
  86. port: number
  87. host: string
  88. scheme: string
  89. httpHeaders:
  90. - name: string
  91. value: string
  92. tcpSocket:
  93. #对pod内各容器健康检查的设置
  94. port: number
  95. initialDelaySeconds: 0
  96. #容器启动完成后首次探测时间,单位0s
  97. timeoutSeconds: 0
  98. #对容器健康检查的探测等待响应时间设置,默认1s,超过该时间设置,将认为容器不健康,会重启该容器
  99. periodSeconds: 0
  100. #对容器健康检查的定期探测时间设置,默认10s探测一次
  101. successThreshold: 0
  102. failureThreshold: 0
  103. securityContext:
  104. privileged: false
  105. restartPolicy: [Always | Never | OnFailure]
  106. #pod的重启策略
  107. nodeSelecrets: object
  108. #设置Node的Label,以key:value格式指定,pod将被调度到具有这些label的Node上
  109. imagePullScerets:
  110. #pull镜像时使用的Secret名称,以namespace:secretkey格式指定
  111. - name: string
  112. hosNetwork: false
  113. #是否使用主机网络模式,默认false,设置true表示设置容器使用宿主机网络,不在使用Docker网桥,该pod将无法在同一台宿主机上启动2个副本
  114. volumes:
  115. #该pod上定义的共享存储卷列表
  116. - name: string
  117. #共享存储卷的名称。在pod中每个存储卷定义一个名称。容器定义部分volumeMounts[].name将应用定义名称
  118. #Volume的常用类型:emptyDir、hostPath、secret、configMap、nfs等等
  119. emptyDir: {}
  120. #类行为emptyDir的存储卷,表示与pod同生命周期的一个临时目录 ,其值为一个空对象。
  121. hostPath:
  122. #类型为hostPath的存储卷,表示挂载pod所在的主机目录
  123. path: string
  124. #通过此处指定
  125. secret:
  126. #类型为secret的存储卷,表示挂载集群预定义的secret对象到容器内部
  127. secretName: string
  128. items:
  129. - key: string
  130. path: string
  131. configMap:
  132. name: string
  133. items:
  134. - keys: string
  135. path: string

其中container的livenessProbe、resources和restartPolicy跟开发关系较大。

livenessProbe(健康检查)

即容器的健康检查,如果容器不健康,会被重启。健康检查的方式可以有exec、httpGet和tcpSocket三种。

resources(资源)

即容器的资源请求(requests)和资源限制(limits)。Master的Scheduler根据requests的来作为分配Node的一个依据,Node根据limits来对容器使用的资源做限制。

restartPolicy(重启策略)

  • Always:当容器失效时重启。
  • OnFailure:当容器终止运行且退出码不为0时重启。
  • Never:不会容器状态如何,都不重启

spec.initContainers也很有意思:

初始化容器可以在应用启动之前进行一些初始化操作:

  • 等待其他关联组件正确运行
  • 基于环境变量或配置模板生成配置文件
  • 从远程数据库获取本地需要的配置,或者将自身注册到某个中央数据库
  • 下载相关依赖包,或者对系统进行一些预配置操作

使用skywalking的时候,需要在容器力能访问到skywalking-agent.jar的java agent代理包。

我们是怎么达成这个效果的?

改变了服务的基础镜像!在java镜像的基础来,加多了skywalking一层,形成了新基础镜像,所有业务服务都以此作为基础镜像。

如果是在k8s里,其实就可以利用initContainers来实现相同的效果。一个很小的镜像,包含了skywalking-agent.jar包,把这个包cp到Pod上定义的一个类型为emptyDir的volumeMounts上,业务服务容器也挂载这个volumeMounts。

Label

Label是Kubernetes的另外一个核心概念。一个是Label就是一个键值对key=value,key和value都由用户自己指定。

Label可以附加到各种资源对象上,例如Node、Pod、Service、RC等,一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上。

Label通常在定义资源对象的时候确定,当然,也可以时候再给对象动态添加或删除。

Labek相当于我们熟悉的“标签”,给某个资源对象定义一个Label,相当于给它打上了一个标签,随后可以通过Label Selector(标签选择器)查询和筛选有指定标签的资源对象。

Label Selector的表达式有两种表达式:

  • 基于等式,name=redis-slave,env!=production
  • 基于集合,name in (redis-master, redis-slave),name not in (frontend)

支持多个Label Selector表达式的组合实现复杂条件选择,多个表达式之间用“,”分隔,多个表达式之间是AND关系,例如:

name=redis-slave,env!=production,查询的是name是redis-slave且env不是production的对象。

通过Label和Label Selector可以很方便实现资源的分组管理功能。在K8s中的重要场景如下:

  • kuberbnetes-controller进程通过对象RC上定义的Label Selector来筛选要监控的Pod副本数,从而实现Pod副本数始终符合预期。
  • kube-proxy进程通过Service的Label Selector来选择对应的Pod,自动建立起来每个Service到对应Pod的请求转发路由表,实现Service的负载均衡。
  • 通过对Node定义特定的Label,并且在Pod定义文件中使用NodeSelector这种标签调度策略,kube-scheduler进程可以实现Pod的定向调度。

Annotation

Annotation(注解)与Label类似,也使用key/value键值对的形式进行定义。

不同的是,Label具有严格的命令规则,它定义的是kubernetes对象的元数据,并且用于Label Selector。

而Annotation则是用户任意定义的“附加”信息,以便于外部工具进行查找,很多时候,kubernetes的模块自身会通过Annotation的方式标记资源对象的一些特殊信息。

通常来说,用Annotation来记录的信息如下:

  • build信息、release信息、docker镜像信息等,例如时间戳、release id号、镜像hash值等等。
  • 日志库、监控库、分析库等资源的地址信息。
  • 程序调试工具信息,例如工具名称、版本号等。
  • 团队的联系信息,例如联系电话、负责人名称、网址等。

Volume

Volume(存储卷)是Pod中能被多个容器访问的共享目录

  • 定义在Pod上,可以被Pod里的多个容器挂载到具体的文件目录下。
  • Volume与Pod的生命周期相同,但与容器的生命周期不相关。

常用的Volume类型有:emptyDir、hostPath、secret、configMap、nfs等等。

我们业务服务最可能使用的是host'Path和emptyDir。

emptyDir是在Pod分配到Node时创建的,当Pod从Node上移除的时候,emptyDir的数据也会被删除。适合用来做这些用途:

  • 临时空间,例如用于某些应用运行时需要的临时目录,且无需永久保留。
  • 长时间任务的中间过程数据的临时保存目录。

hostPath则是挂载宿主机上的文件或目录,常用于这些用途:

  • 容器应用的日志文件保存。
  • 需要访问宿主机上Docker引擎内部数据接口的容器一个月时,可以通过定义hostPath为宿主机/var/lib/docker目录,使容器内部应用可以直接访问docker的文件系统。

在pod中定义一个emptyDir的volume,r然后在containers中引用,挂载到/data0/java/logs目录下,配置如下:

  1. spec:
  2. volumes:
  3. - name: datavol
  4. emptyDir: {}
  5. containers:
  6. - name: demo
  7. volumeMounts:
  8. - name: datavol
  9. mountPath: /data0/java/logs/

Persistent Volume

PV可以理解成kubernetes集群中的某个网络存储中的对应的一块存储,它与Volume很类似,但有一下区别:

  • PV只能是网络存储,不属于任何Node,但可以在每个Node上访问。
  • PV并不是定义在Pod上的,而是独立于Pod之外定义。
  • PV目前支持的类型包括:gecePersistentDisk、AWSElatisticBlockStore、AzureFile等等。

在使用虚拟机的情况下,我们通常会先定义一个网络存储,然后从中划出一个“网盘”并挂接到虚拟机上。Persistent Volume和与相关联的Persistent Volume Claim(简称PVC)也起到了类似的作用。

下面是一个NFS类型PV的一个yaml定义文件,声明了需要5Gi的存储空间:

  1. apiVersion: v1
  2. kind: PersistentVolume
  3. metadata:
  4. name: pv003
  5. spec:
  6. capacity:
  7. storage: 5Gi
  8. accessModes:
  9. - ReadWriteOnce
  10. nfs:
  11. path: /somepath
  12. server: 172.17..0.2

其中比较重要的是PV的accessModes属性,目前有一下类型:

  • ReadWriteOnce:读写权限、并且只能被单个Node挂载
  • ReadOnlyMany:只读权限、允许被多个Node挂载
  • ReadWriteMany:读写权限、 允许被多个Node挂载

Persistent Volume Claim

PV是定义资源,PVC则是对资源的请求。

相关的yaml配置:

  1. kind: PersistentVolumeClaim
  2. apiVersion: v1
  3. metadata:
  4. name: myclaim
  5. spec:
  6. accessModes:
  7. - ReadWriteOnce
  8. resources:
  9. requests:
  10. storage: 8Gi
  11. storageClassName: slow
  12. selector:
  13. matchLabels:
  14. release: "stable"
  15. matchExpressions:
  16. - {key: environment, operator: In, values: [dev]}

PV和PVC的相互作用遵循这个生命周期:

Provisioning(配置)->Biding(绑定)->Using(使用)->Releasing(释放)->Recycling(回收)

Provisioning:配置PVC。

Biding:k8s会自动关联合适的PV,如果没有合适的PV,则PVC会一直是Pending状态,只有关联PV之后,Pod才可以挂载使用PVC。

Using:Pod使用PVC。

Releasing:删除Pod定义的时候,PVC就是释放的状态,但是它还不能被用于另外一个Pod定义,数据还是保存在PVC上。

Recycling:会对卷的数据进行清理,回收后可重复利用。

ConfigMap

应用部署的一个最佳时间是将应用所需的配置信息与程序进行分离,这样可以使得应用程序更好的复用,通过不同的配置也能实现更灵活的功能。

在我们公司,使用的是apollo来实现程序和配置的分离,但其实,k8s也提供了类似的功能,就是ConfigMap了。

ConfigMap供容器使用的典型用法:

  • 生成容器内的环境变量
  • 设置容器启动命令的启动参数(需要配为环境变量)
  • 以Volume的形式挂载为容器内部的文件或目录

ConfigMap以一个或多个key/value的形式保存在kubernetes系统中供应用使用,既可以用于表示变量的值(例如apploglavel=info),也可以用于表示一个完整的配置文件的内容(例如server.xml='<?xml...>...')。

ConfigMap的yaml定义如下:

  1. apiVersion: v1
  2. kind: ConfigMap
  3. metadarta:
  4. name: app-config
  5. data:
  6. apploglevel: info
  7. key-server.xml: |
  8. <?xml versiob="1.0" encoding="utf-8">
  9. <server ....></server>

在Pod中可以这样使用:

  1. ...
  2. spec:
  3. containers:
  4. - name: app
  5. env:
  6. - name: APPLOGLEVEL
  7. valueFrom:
  8. configMapKeyRef:
  9. name:app-config
  10. key: apploglevel
  11. volumeounts:
  12. - name: serverxml
  13. mountPath: /configfiles
  14. volumes:
  15. - name: serverxml
  16. configMap:
  17. name: app-config
  18. items:
  19. - key: key-server.xml
  20. path: server.xml

RC

RC就是一种根据Pod的Label,来管理Pod副本数的资源对象。下面是一个RC的部分定义:

  1. apiVersion: v1 #指定api版本,此值必须在kubectl apiversion中
  2. kind: ReplicationController #指定创建资源的角色/类型
  3. metadata: #资源的元数据/属性
  4. name: test-rc #资源的名字,在同一个namespace中必须唯一
  5. labels:
  6. k8s-app: apache
  7. software: apache
  8. project: test
  9. app: test-rc
  10. version: v1
  11. spec:
  12. replicas: 2 #副本数量2
  13. selector: #RC通过spec.selector来筛选要控制的Pod
  14. software: apache
  15. project: test
  16. app: test-rc
  17. version: v1
  18. name: test-rc
  19. template: #这里Pod的定义
  20. metadata:
  21. labels: #Pod的label,可以看到这个label与spec.selector相同
  22. software: apache
  23. project: test
  24. app: test-rc
  25. version: v1
  26. name: test-rc
  27. spec: ......

ReclicationController本身是资源对象,所以也有自己的metadata,可以定义自己的name和labels等信息。

spec.relicas表示需要维持Pod的副本数。

spec.selector则表示要管理哪些Pod(通过Label Selector实现)。

spec.template则是要管理的Pod的模板,例如期望的副本数spec.relicas=2,但是当前Pod只有1个副本存活,则RC会根据spec.template创建一个新的Pod。

需要注意,spec.selector中和label必须和spec.template.metadat.labels的内容匹配!

不匹配会出现什么问题?

RC的label selector选择不到它创建的pod,认为当前运行的pod数量不满足期望值,会一直创建~

需要注意,删除RC并不会直接删除RC管理的Pod!

应该将RC的副本数设置为0,再更新RC。

ReplicaSet

Replica Set是新一代的RC,一样是用于管理Pod的副本数保持为期望值。不过Replica Set的标签选择能力比RC更强!

Replica Set的yaml定义如下:

  1. apiVersion: apps/v1
  2. kind: ReplicaSet
  3. metadata:
  4. name: nginx
  5. labels:
  6. app: nginx
  7. spec:
  8. replicas: 3 #副本数量
  9. selector: #标签选择器
  10. matchLabels:
  11. app: nginx
  12. matchExpressions:
  13. - {key: version, Operator: In, values: {1.16}}
  14. template: # Pod的模板
  15. metadata:
  16. labels:
  17. app: nginx
  18. spec:
  19. containers:
  20. - name: nginx
  21. image: nginx:1.16

Replica Set的spec.selector.matchLabels与R承德spec.selector作用相同。

但是replica Set支持多了matchExpressions,可以用于定义一组基于集合的筛选条件,可以用的条件运算符有:In、NotIn、Exists和DoesNotExist。

如果同时定义了matchLabels和matchExpressions,则需要同时满足两者,是AND关系。

虽然Relica Set比Replication Controller更加强大,但是k8s并不建议直接使用Relica Set,而是使用Deployment,Deployment没自动创建对应的Relica Set来管理Pod的副本。

Deployment

为什么建议不要直接使用Relica Set,而是使用Deployment呢?

假设我们现在有一个服务a,在生产环境上运行着4个副本。那么当我们要发布新版本的a服务到生产的时候,我们期望发布过程是怎样的?

  1. 希望不要一次性停掉所有a服务的副本,更希望是将一部分替换为新版本,替换成功,再接着替换,直到全部替换完成。因为期望在发布的过程中,a服务对外还是可用的。
  2. 因为是一部分一部分来替换成新版本,那么当然会想要知道进度,总共4个,当前新版本的有几个,旧版本的有几个。
  3. 当新版本的代码有问题,发布之后pod启动异常,希望能够回滚到上一个正常的版本。

这几件事情,使用relica set不是说不能做到,还就会需要很多人工干预。但是deployment将这些事情都封装好,我们只要在配置文件中定义好我们的策略即可。deployment的yaml定义如下:

  1. apiVersion: extensions/v1beta1
  2. kind: Deployment
  3. metadata: <Object>
  4. spec: <Object>
  5. minReadySeconds: <integer> #设置pod准备就绪的最小秒数
  6. paused: <boolean> #表示部署已暂停并且deploy控制器不会处理该部署
  7. progressDeadlineSeconds: <integer>
  8. strategy: <Object> #将现有pod替换为新pod的部署策略
  9. rollingUpdate: <Object> #滚动更新配置参数,仅当类型为RollingUpdate
  10. maxSurge: <string> #滚动更新过程产生的最大pod数量,可以是个数,也可以是百分比
  11. maxUnavailable: <string> #
  12. type: <string> #部署类型,Recreate,RollingUpdate
  13. replicas: <integer> #pods的副本数量
  14. selector: <Object> #pod标签选择器,匹配pod标签,默认使用pods的标签
  15. matchLabels: <map[string]string>
  16. key1: value1
  17. key2: value2
  18. matchExpressions: <[]Object>
  19. operator: <string> -required- #设定标签键与一组值的关系,In, NotIn, Exists and DoesNotExist
  20. key: <string> -required-
  21. values: <[]string>
  22. revisionHistoryLimit: <integer> #设置保留的历史版本个数,默认是10
  23. rollbackTo: <Object>
  24. revision: <integer> #设置回滚的版本,设置为0则回滚到上一个版本
  25. template: ......

spec.strategy就是部署的策略:

spec.strategy.type: Recreate就是停止旧Pod,直接重新建新的Pod;

spec.strategy.type: RollingUpdate就是滚动升级,一部分一部分的替换。采用滚动升级的策略,还能设置spec.strategy.rollingUpdate.maxSurge和spec.strategy.rollingUpdate.maxUnavailable。

spec.strategy.rollingUpdate.maxSurge:50%,按刚才a服务的例子,滚动升级的过程中,最多允许出现6个副本同时运行。

spec.strategy.rollingUpdate.maxUnavailable:50%,按刚才a服务的例子,最少需要运行2个副本。

Service

Service是k8s中最核心的资源对象之一。

Service的作用就是把一组Pod副本组合成同一个集群,所有Pod请求都由Service接收,Service再将请求转发到组成集群的Pod中。

Service的yaml定义如下:

  1. apiVersion: v1 #API的版本号,版本号可以用 kubectl api-versions 查询到
  2. kind: Service #表明资源对象,例如Pod、RC、Service、Namespace及Node等
  3. metadata: #资源对象的元数据定义
  4. name: engine #service名称
  5. spec: #资源对象的详细定义,持久化到etcd中保存
  6. type: ClusterIP #Service类型,ClusterIP供kubernates集群内部pod访问
  7. ports: #暴露的端口列表
  8. - port: 8080 #Service监听的端口,对应ClusterIP,即ClusterIP+ServicePort供集群内部pod访问的
  9. targetPort: 8080 #对应pod中容器的端口
  10. protocol: TCP #协议,支持TCP、UDP,默认TCP
  11. name: http #端口名称
  12. selector: #label选择器,管理label对应的pod
  13. name: enginehttpmanage #pod的label
  14. status: #公有云上才会使用到
  15. loadbalancer:
  16. ingress:
  17. ip:
  18. host:

spec.ports[].targetPort不是必填的,没有指定targetPort的情况下,默认targetPort等于port。ports是一个数组,可以支持多端口服务。Selector决定了Service由哪些Pod组成。

k8s中,每个Pod都会被分配一个单独的IP地址,而且每个Pod都提供了一个独立的Endpoint(Pod IP + ContainerPort)。存在多个Pod的时候,别人要怎么访问这些pod呢

如果要客户端记录下所有Pod的Endpoint,然后客户端自己做负载均衡,那就太为难调用者了。

更好的做法是部署一个负载均衡器,代理这组Pod的请求,Pod的调用者直接把请求发送到负载均衡器,再由负载均衡器把请求转发给这组Pod中的一个。

在k8s里,这个负载均衡器就是Service。Service一旦被创建,就会被分配一个可用的ClusterIP,而且在Service的整个声明周期中,它的Cluster IP都不会发生改变。

创建Service的时候,除了分配一个固定的Cluster IP,还在添加一个DNS域名解析:service的name→cluser IP。这就是kubernetes中的服务发现机制,简单明了,比什么dubbo、springCloud好理解多了~

像在房多多里,就可以用微服务的域名作为service的name,例如调用http://project.zqb.ep.fdd:65535/projects,就能拿到项目列表。

不过Service的ClusterIP并不是一个真实的IP,有自己的局限性:

  • Cluster IP仅仅作用于kerbernetes这个对象,并由kubernetes管理和分配IP地址。
  • Cluster IP无法被ping,因为没有一个“实体网络对象”来相应。
  • Cluster IP只能结合Service Port组成一个具体的通信端口,单独的cluster IP不军备TCP/IP通信的基础,并且他们属于kubernetes集群这样一个封闭的空间,集群之外要与这个端口通信,需要做额外的工作。
  • 在kubernetes集群之内,Node IP网,Pod IP网和Cluster IP网之间的通信,采用的是kubernetes自己设计的一种编程方式的特殊路由规则。

总结下来,就是Cluster IP只在kubernetes中生效,集群外部无法直接访问到这个地址。那怎么才能让集群外部访问到Service呢

这个时候,就要使用NodePort:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: engine
  5. spec:
  6. type: NodePort
  7. ports:
  8. - port: 8080
  9. nodePort: 31002
  10. protocol: TCP
  11. name: http
  12. selector:
  13. name: enginehttpmanage

这样配置,所有Node节点就会在31002端口开启TCP监听,从集群外部访问访问任意一个节点的31002端口,请求都会被正确转发到service管理的后端Pod上。

不过这样子,就会需要在所有Node的前面再部署一个负载均衡,例如nginx,作为流量的统一入口,再分发到各个Node节点上。

一般来讲,k8s中的每个Service对应我们微服务中的一个“微服务”。

到这里,可能会有点困惑,微服务不应该是Deployment么,为什么变成Service了?Pod、RelicaSet、Deployment和Service的关系是怎样的?

deployment根据Pod的标签关联到Pod,是为了管理pod的生命周期,pod挂了,重新启动一个新的pod;滚动升级;回滚等。

service根据Pod的标签关联到pod,是为了让外部访问到pod,给pod做负载均衡。

这里就涉及另外一个问题:Pod是受Deployment控制的,会有Pod销毁,也会有新的Pod被创建,Service需要转发的Pod列表是会动态变化的!k8s如何解决这种变化

有一种特殊的Service,是不需要设置Cluster IP的,这种Service被称为Headless Service(无头服务)。配置如下:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: nginx
  5. labels:
  6. app: nginx
  7. spec:
  8. ports
  9. - port: 80
  10. clusterIP: None
  11. selector:
  12. app: nginx

其中指定了clusterIP=None,表示不需要分配cluster ip地址。无法直接访问该Service,目的只是为了能通过Service来得到Label Selector选择的后端Pod,将Pod列表返回给客户端。

多用于StatefulSet,来搭建“去中心化”类的应用集群(集群中的节点需要感知到其他节点的加入/退出集群,通过Service的Label Selector实现)。

Ingress

对于基于HTTP的服务来说,不同的URL地址经常对应到不同的后端服务,这些应用层的转发机制仅通过Kubernetes的Service机制是无法实现的。

例如:

  • 访问https://api.fangdd.com/bcc.bp.fdd请求转发到bcc.bp.fdd服务
  • 访问https//api.fandd.com/acc.ap.fdd请求转发到acc.ap.fdd服务

是不是类似我们的统一网关功能~

Ingress对象是k8s v1.1版本添加的,专门用于不同URL的访问请求转发到后端不同的Service。

Kubernetes使用一个Ingress策略定义和一个具体的Ingress Controller,两者结合实现一个完成的Ingress负载均衡器。

Ingress Controller

定义Ingress策略之前,需要先部署Ingress Controller。在K8s中,Ingress Controller将以Pod的形式运行,通过监控apiserver的/ingress接口,实现配置的动态变更。基本流程如下:

  1. 监听apiserver,获取全部ingress定义。
  2. 基于ingress的定义,生成Nginx所需的配置文件/etc/nginx/nginx.conf。
  3. 执行nginx -s reload,重新加载nginx.conf配置文件的内容。

这个谷歌有提供现成的nginx-ingress-controller镜像。这个镜像需要配置一个默认的backend服务,用于在客户端访问的url地址不存在时,能够返回一个404应答。

定义Ingress策略

  1. apiVersion: extensions/v1betal
  2. kind: Ingress
  3. metadata:
  4. name: website-ingress
  5. spec:
  6. rules:
  7. - host: api.fangdd.com
  8. http:
  9. paths:
  10. - path: /bcc-bp-fdd
  11. backend:
  12. serviceName: bcc-bp-fdd
  13. servicePort: 8080

这样定义,访问api.fangdd.com/bcc-bp-fdd的请求,就被被转发到bcc-bp-fdd服务的8080端口。

Ingerss可以实现如下的转发效果:

  • 转发到单个服务上,即不指定host也不指定path
  • 同一个域名选,不同URL转发到不同的服务上,即指定host也指定path,像上面的配置
  • 不同的域名被转发到不同的服务上
  • 不使用域名的转发

DaemonSet

DaemonSet与Deployment有点类型,都是通过label管理一批Pod。

比较特别的是,在DaemonSet里,不需要指定Pod的副本数,它会给每个Node都分配运行一个Pod,每个Node有且只有一个Pod。

像Filebeat这种,拉取每个Node节点上的日志的,就适合定义成DaemonSet。

yaml配置:

  1. apiVersion: apps/v1
  2. kind: DaemonSet
  3. metadata:
  4. name: deamonset-example
  5. labels:
  6. app: daemonset
  7. spec:
  8. selector:
  9. matchLabels:
  10. name: deamonset-example
  11. template:
  12. metadata:
  13. labels:
  14. name: deamonset-example
  15. spec:
  16. containers:
  17. - name: daemonset-example
  18. image: wangyanglinux/myapp:v3

StatefulSet

在k8s中,Pod管理对象RC、Deployent、DaemonSet和Job都是面向无状态的服务。但现实中有很多服务是有状态的,特别是一些复杂的中间件集群,例如Mysql几圈、Kafka集群、Zookeeper集群等。

这些有状态的集群有一下的共同点:

  • 每个节点都有固定的身份ID,通过这个ID,集群中的成员可以相互发现并且通信。
  • 集群的规模比较固定,集群规模不会随意变动。
  • 集群里的每个节点都是有状态的,通常会把数据持久化到存储中。
  • 如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。

为了实现支持有状态的集群,StatefulSet被设计出了如下特性:

  • Stateful里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。例如定义一个StatefulSet,名字为kafka,那么第1个Pod叫kafka-0,第二个pod叫kafka-1,一次类推。
  • StatefulSet控制的Pod副本的启停顺序是受控制的,操作第n个Pod时,前n-1个Pod已经是就绪状态。
  • StatefulSet里的Pod采用稳定的持久化存储卷,通过PV/PVC来实现,删除Pod时默认不会删除与Stateful相关的存储卷(保证数据安全)。

StatefulSet处理要跟PV卷捆绑使用,以存储Pod的状态数据,还要与Headless Service配合使用。需要在StatefulSet的定义中,指定它属于哪个Headless Service。

Event

Event是一个事件记录,记录了事件最早产生时间、最后重现时间、重复次数、发起者、类型,以及导致该事件的原因等信息。

Event通常会关联到某个具体的资源对象上,是排查故障的重要参考。例如有个Pod一直启动不了,可以用kubelet describe pod xxx 来查看它的信息描述,利用输出的Event信息来定位问题原因。

Namespace

Namespace(命名空间)是kubernetes系统中的另一个非常重要的概念,Namespace在很多情况下用于多租户隔离。Namespace通过将集群内部的资源对象“分配”到不同的Namespace,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。

网络

k8s中的网络

Kubernetes网络原理及方案

有助开发的点

可以在容器内获取Pod的信息

Downward API可以通过一下两种方式将Pod信息注入容器内部:

  • 环境变量:用于单个变量,可以将Pod信息和Container信息注入容器内部。
  • Volume挂载:将数组类信息(例如metadata.labels)生成文件,挂载到容器内部。

JAVA服务的resources.requests和resources.limits

我们生产的k8s节点配置是16核128G,那么我们的java服务使用的内存是多少呢?

能直接通过-Xms=1G -Xmx=2G这样指定初始1G内存,最大2G内存么?

这个是不合适的,例如-Xmx=2G,但是Pod的resources.requests.memory和resources.limits.memory都动态调整为4G,那指定java服务最大堆内存为2G就不合适了。

最好的方式,是根据Pod配置的resources来动态识别自己能使用的内存。JDK 版本java 8u191+新增里几个启动参数,专门支持Docker环境:

  • MaxRAMPercentage,类似于Xmx,最大的内存比例
  • InitialRAMPercentage,类似于Xms,初始化内存比例
  • MinRAMPercentage,类似于Xmn,最小内存比例

既然是比例,然分母是谁?resources.requests.memory还是resources.limits.memory?

resources.limits.memory!个人觉得,选择limits,是因为真的允许Pod使用到这么多内存。如果使用requests,就丢失了limits的作用。

那么对于java服务,requests和limits应该怎么配置?例如一个服务,95%时间使用1G内存,5%的时候使用2G内存,应该怎么配置好的?

requests.memory: 1Gi和limits.memory: 2Gi 似乎是比较合理的?

但可能不太对,配置成requests.memory: 2Gi和limits.memory: 2Gi 更合适一点。

我们java的堆大小,是扩大之后,并不会缩小,因为我们只指定了MaxRAMPercentage值。当达到业务高峰之后,服务占用的内存就会是2G,并不会因为空闲了,就把内存还给操作系统。

而k8s分配Pod到Node节点的时候,是按requests的值来分配,只会认为node节点被占用1G内存。这就容易造成k8s节点的负载不均衡了。

查看jvm中的各种参数以及默认值 - smile_lg - 博客园

调整jvm参数_假笨说Java堆大小动态调整的JVM参数_weixin_39890452的博客-CSDN博客

jdk1.8.191 JVM内存参数 InitialRAMPercentage和MinRAMPercentage - fengjian1585 - 博客园

K8s自身有服务发现机制,可以代替SpringCloud和Dubbo

定义Service之后,可以把Service名作为域名,加上Service暴露的端口来访问业务服务。例如定义一个Service,名字为project.zqb.ep.fdd,暴露的端口为65535,则可以通过http://project.zqb.ep.fdd:65535/来访问业务服务接口。

这样子,只要知道我们要调用的业务服务在k8s中定义的Service的name和暴露的端口(还记得发布系统中,创建申请创建一个服务的时候,都会分配或指定一个端口么,这就是原因),就能调用到业务服务的接口,完全不需要引入SpringCloud或者Dubbo。

使用k8s自身的服务发现机制,看起来很美好,但是存在一个问题,负载不均衡!

例如我们业务服务提供的是http接口,客户端调用的时候,采用长连接的方式,那么在第一次调用后,就会跟Service背后的某个Pod建立了场链接,之后的所有调用,都会调用这个Pod。这样,请求就没有均衡的分配到Service代表的所有Pod上。

解决方式有:

  • 在客户端实现负载均衡。该方式需要修改客户端程序,这里可以根据具体需求设置一个时间值或者请求量的值,当建立的长连接超过时间阈值或者请求量阈值时,断开连接,再与服务端重新建立连接,从而实现负载均衡。
  • 在服务端实现负载均衡。该方式需要修改服务端程序,这里可以根据具体需求设置一个时间值或者请求量的值,当建立的长连接超过时间阈值或者请求量阈值时,断开连接,客户端会再与服务端建立连接,从而实现负载均衡。
  • 使用服务网格实现负载均衡。就是我们现在使用的mesh网关。
  • 通过nginx实现负载均衡。对于这种方式,在k8s中有较为简单且方便的实现方式,即为后端pod建立一个ingress,服务请求直接通过Ingress转发到Service的后端Pod上,跳过了kubelet-proxy的转发功能。

具体分析可以看:解决k8s中的长连接负载均衡问题

个人认为“在客户端实现负载均衡”和“在服务端实现负载均衡”是不大可取的,使用service mesh或者ingress是比较好的选择。

服务质量等级Qos

  • Guaranteed:Pod里的每个容器都配置了内存和CPU的limits/requests。如果只配置了limits没有配置requests,requests默认与limits一致。
  • Burstable:Pod里至少有一个容器配置了内存或者CPU的limits/requests,但又不满足Guaranteed的条件。
  • BestEffort:Pod内的容器都没有配置limits和requests。

在发生oom的时候,有优先干掉oom_score_adj分高的。对于oom_score_adj分,BestEffort>Burstable>Guaranteed。

k8s的自我保护——保护和驱逐策略

Node节点上的资源,并不能全部都交给Pod使用,操作系统需要使用一部分,k8s的进程本身也需要消耗一部分。所以有两个配置,可以预留这两部分的内存:

--system-reserved=memory=1.5Gi    #系统保留资源

--kube-reserved=memory=1.5Gi    #k8s保留资源

kubelet持续监控主机的资源使用情况,并尽量防止计算资源被耗尽。一旦出现资源紧缺的迹象,kubelet就会主动终止部分pod的运行,以回收资源。

触发驱逐的信息有:

信号

压力类型

描述

memory.availableMemoryPressue内存不足
nodefs.availableDiskPressure内盘不足
nodefs.inodesFreeDiskPressure文件系统的inode不足
imagefs.availableDiskPressure镜像文件存储空间不足
imagefs.inodesFreeDiskPressure镜像文件的inode不足

当出现MemoryPressue:Scheduler不再调度新的BestEffort pod到这个节点。

当出现DiskPressure:不再向这个节点调度pod

软驱逐

系统资源达到软驱逐阈值并在超过宽限期之后才会执行驱逐动作。

--eviction-soft:描述驱逐阈值,例如:memory.available<1.5G

--eviction-soft-grace-period:驱逐宽限期,memory.available=1m30s

--eviction-max-pod-grace-period:终止pod最大宽限时间,单位s

硬驱逐

系统资源达到硬驱逐阈值时立即执行驱逐动作。

--eviction-hard=memory.available<500Mi,nodefs.available<1Gi,imagefs.available<100Gi

当发生MemoryPressue,开始驱逐的时候,Node会对运行在它之上的Pod打分,优先干掉oom_score_adj高的Pod。

回收资源的时候,为了让系统更稳定,不会一直波动(一会标识自己正常,一会标识自己存在内存压力),就有了其他配置:

--eviction-minimum-reclaim:每一次 eviction 必须至少回收多少资源。

--eviction-pressure-transition-period:默认为5分钟,达到pressure condition的时间,超过阈值时,节点会被设置为memory pressure或者disk pressure,然后开启pod eviction。

相关资料

Kubernetes 文档 | Kubernetes

七张图了解Kubernetes内部的架构

解决k8s中的长连接负载均衡问题

kubernetes-pod驱逐机制

超详细总结!

浅谈 K8s 网络模型CNI协议

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/996382
推荐阅读
相关标签
  

闽ICP备14008679号