k8s 理论知识

一 、k8s介绍

Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。

1.1 优点

  • 可移植: 支持公有云,私有云,混合云,多重云(multi-cloud)
  • 可扩展: 模块化, 插件化, 可挂载, 可组合
  • 自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展

1.2 容器化和传统化对比

传统化

早期,各机构是在物理服务器上运行应用程序。 由于无法限制在物理服务器中运行的应用程序资源使用,因此会导致资源分配问题。 例如,如果在物理服务器上运行多个应用程序, 则可能会出现一个应用程序占用大部分资源的情况,而导致其他应用程序的性能下降。 一种解决方案是将每个应用程序都运行在不同的物理服务器上, 但是当某个应用程式资源利用率不高时,剩余资源无法被分配给其他应用程式, 而且维护许多物理服务器的成本很高。

虚拟化

因此,虚拟化技术被引入了。虚拟化技术允许你在单个物理服务器的 CPU 上运行多台虚拟机(VM)。 虚拟化能使应用程序在不同 VM 之间被彼此隔离,且能提供一定程度的安全性, 因为一个应用程序的信息不能被另一应用程序随意访问。

虚拟化技术能够更好地利用物理服务器的资源,并且因为可轻松地添加或更新应用程序, 而因此可以具有更高的可伸缩性,以及降低硬件成本等等的好处。

每个 VM 是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统(OS)。

容器的优势

容器类似于 VM,但是更宽松的隔离特性,使容器之间可以共享操作系统(OS)。 因此,容器比起 VM 被认为是更轻量级的。且与 VM 类似,每个容器都具有自己的文件系统、CPU、内存、进程空间等。 由于它们与基础架构分离,因此可以跨云和 OS 发行版本进行移植。

容器因具有许多优势而变得流行起来。下面列出的是容器的一些好处:

  • 敏捷应用程序的创建和部署:与使用 VM 镜像相比,提高了容器镜像创建的简便性和效率。
  • 持续开发、集成和部署:通过快速简单的回滚(由于镜像不可变性), 提供可靠且频繁的容器镜像构建和部署。
  • 关注开发与运维的分离:在构建、发布时创建应用程序容器镜像,而不是在部署时, 从而将应用程序与基础架构分离。
  • 可观察性:不仅可以显示 OS 级别的信息和指标,还可以显示应用程序的运行状况和其他指标信号。
  • 跨开发、测试和生产的环境一致性:在笔记本计算机上也可以和在云中运行一样的应用程序。
  • 跨云和操作系统发行版本的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、 Google Kubernetes Engine 和其他任何地方运行。
  • 以应用程序为中心的管理:提高抽象级别,从在虚拟硬件上运行 OS 到使用逻辑资源在 OS 上运行应用程序。
  • 松散耦合、分布式、弹性、解放的微服务:应用程序被分解成较小的独立部分, 并且可以动态部署和管理 - 而不是在一台大型单机上整体运行。
  • 资源隔离:可预测的应用程序性能。
  • 资源利用:高效率和高密度。

1.3 核心组件

k8s 集群主要分为平面控制节点(master)和工作节点(node)

  • master
    1、kube-apiserver:集群中所有资源的统一访问入口。

API 服务器是 Kubernetes 控制平面的组件, 该组件负责公开了 Kubernetes API,负责处理接受请求的工作。 API 服务器是 Kubernetes 控制平面的前端。
Kubernetes API 服务器的主要实现是 kube-apiserver。 kube-apiserver 设计上考虑了水平扩缩,也就是说,它可通过部署多个实例来进行扩缩。 你可以运行 kube-apiserver 的多个实例,并在这些实例之间平衡流量。

2、kube-scheduler:将新创建的pod调度到合适的节点上。

kube-scheduler 是控制平面的组件, 负责监视新创建的、未指定运行节点(node)的 Pods, 并选择节点来让 Pod 在上面运行。
调度决策考虑的因素包括单个 Pod 及 Pods 集合的资源需求、软硬件及策略约束、 亲和性及反亲和性规范、数据位置、工作负载间的干扰及最后时限。

3、kube-controller-manager:集群中所有资源对象的自动化控制中心。

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

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

4、etcd:保存集群中的所有资源对象的数据。

etcd 是兼顾一致性与高可用性的键值数据库,可以作为保存 Kubernetes 所有集群数据的后台数据库。
你的 Kubernetes 集群的 etcd 数据库通常需要有个备份计划。

  • node
    1、kubelet:会监控Api Server上的资源变动,若变动与自己有关系,kublet就去执行任务;定期向master会报节点资源使用情况。

kubelet 会在集群中每个节点(node)上运行。 它保证容器(containers)都运行在 Pod 中。
kubelet 接收一组通过各类机制提供给它的 PodSpecs, 确保这些 PodSpecs 中描述的容器处于运行状态且健康。 kubelet 不会管理不是由 Kubernetes 创建的容器。

2、kube-proxy:实现service的抽象,为一组pod抽象的服务提供统一接口并提供负载均衡。

kube-proxy 是集群中每个节点(node)所上运行的网络代理, 实现 Kubernetes 服务(Service) 概念的一部分。
kube-proxy 维护节点上的一些网络规则, 这些网络规则会允许从集群内部或外部的网络会话与 Pod 进行网络通信。
如果操作系统提供了可用的数据包过滤层,则 kube-proxy 会通过它来实现网络规则。 否则,kube-proxy 仅做流量转发。

二、工作原理

2.1 pod调度流程

1、用户通过kubectl提交创建的yaml文件到apiserver中。
2、当apiserver获取到创建pod请求(yaml文件)时,会先校验一下yaml文件是否有问题,如果没有问题,会将数据存储到etcd中。
3、但etcd存储pod的信息成功后,会立即通知apiserver,资源调度系统schedule会定时去监控apiserver,当apiserver获取到pod的信息之后,
会通知schedule服务,schedule服务发现pod的属性中dest node 为空的时候(Dest Node = "")便会立即触发调度流程进行调度。

三、 Scheduler调度方式

3.1 调度介绍

3.1.1 节点预选(Predicate)

排除完全不满足条件的节点,如内存大小,端口等条件不满足。

预选阶段(Predicates),过滤节点,调度器用一组规则过滤掉不符合要求的 Node 节点,比如 Pod 设置了资源的 request,那么可用资源比 Pod 需要的资源少的主机显然就会被过滤掉,在这个阶段输出满足所有要求的节点并输入给第二个阶段,如果没有满足的条件,调度一直会忙活着找符合条件的资源。这个阶段,我们能看到的pod就是一直处于pending状态。预选阶段常见的算法,具体参考如下:
PodFitsResources:节点资源是否满足
PodFitsHost:如果 Pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配
PodFitsHostPorts:如果 Pod 中定义了 hostPort 属性,那么需要先检查这个指定端口是否已经被节点上其他服务占用
PodMatchNodeSelector:检查 Node 的标签是否能匹配 Pod 的 nodeSelector 的标签值
NoDiskConflict:检查 Pod 请求的存储卷在 Node 上是否可用,若不存在冲突则通过检查
NoVolumeZoneConflict:检测 Pod 请求的 Volumes 在节点上是否可用,因为某些存储卷存在区域调度约束
CheckNodeDiskPressure:检查节点磁盘空间是否符合要求
CheckNodeMemoryPressure:检查节点内存是否够用
CheckNodeCondition:Node 可以上报其自身的状态,如磁盘、网络不可用,表明 kubelet 未准备好运行 Pod,如果节点被设置成这种状态,那么 Pod 不会被调度到这个节点上
PodToleratesNodeTaints:检查 Pod 属性上的 tolerations 能否容忍节点的 taints 污点
CheckVolumeBinding:检查节点上已经绑定的和未绑定的 PVC 能否满足 Pod 的存储卷需求
经过上面的阶段过滤后选择打分最高的 Node 节点和 Pod 进行 binding 操作,然后将结果存储到 etcd 中 最后被选择出来的 Node 节点对应的 kubelet 去执行创建 Pod 的相关操作
3.1.2 节点优先级排序(Priority)

根据优先级选出最佳节点

优选阶段(Priorities),为节点的优先级打分,将预选阶段过滤出来的 Node 列表进行打分,调度器会考虑一些整体的优化策略,比如把 Deployment 控制的多个 Pod 副本尽量分布到不同的主机上,使用最低负载的主机等等策略,在优选节点常见算法:
PodMatchNodeSelector:检查 Node 的标签是否能匹配 Pod 的 nodeSelector 的标签
LeastRequestedPriority:通过计算 CPU 和内存的使用率来决定权重,使用率越低权重越高,当然正常肯定也是资源是使用率越低权重越高,能给别的 Pod 运行的可能性就越大
SelectorSpreadPriority:为了实现高可用,对同属于一个 Deployment 或者 RC 下面的多个 Pod 副本,尽量调度到多个不同的节点上,当一个 Pod 被调度的时候,会先去查找该 Pod 对应的 controller,然后查看该 controller 下面的已存在的 Pod,运行 Pod 越少的节点权重越高
InterPodAffinityPriority:遍历 Pod 的亲和性条目,并将那些能够匹配到给定节点的条目的权重相加,结果值越大的节点得分越高
MostRequestedPriority:空闲资源比例越低的 Node 得分越高,这个调度策略将会把你的所有的工作负载(Pod)调度到尽量少的节点上
RequestedToCapacityRatioPriority:为 Node 上每个资源占用比例设定得分值,给资源打分函数在打分时使用
BalancedResourceAllocation:优选那些使得资源利用率更为均衡的节点。
NodePreferAvoidPodsPriority:这个策略将根据 Node 的注解信息中是否含有 preferAvoidPods 来计算其优先级,使用这个策略可以将两个不同 Pod 运行在不同的 Node 上
TaintTolerationPriority:基于 Pod 中对每个 Node 上污点容忍程度进行优先级评估,这个策略能够调整待选 Node 的排名
ImageLocalityPriority:Node 上已经拥有 Pod 需要的容器镜像的 Node 会有较高的优先级
ServiceSpreadingPriority:这个调度策略的主要目的是确保将归属于同一个 Service 的 Pod 调度到不同的 Node 上,如果 Node 上没有归属于同一个 Service 的 Pod,这个策略更倾向于将 Pod 调度到这类 Node 上。最终的目的:即使在一个 Node 宕机之后 Service 也具有很强容灾能力。
3.1.3节点择优(Select)

根据优先级选定节点

3.2 亲和性调度

  • 节点亲和性
  • pod亲和性
3.2.1 节点亲和性

节点亲和性规则:硬亲和性 required 、软亲和性 preferred。
硬亲和性规则不满足时,Pod会置于Pending状态,软亲和性规则不满足时,会选择一个不匹配的节点
当节点标签改变而不再符合此节点亲和性规则时,不会将Pod从该节点移出,仅对新建的Pod对象生效

1)节点硬亲和
requiredDuringSchedulingIgnoredDuringExecution

  • 方式一:Pod使用 spec.nodeSelector (基于等值关系)
  • 方式二:Pod使用 spec.affinity 支持matchExpressions属性 (复杂标签选择机制)
# 调度至 zone = foo 的节点
kubectl label nodes kube-node1 zone=foo
apiVersion: v1
kind: Pod
metadata:
  name: with-required-nodeaffinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 定义硬亲和性
        nodeSelectorTerms:
        - matchExpressions:   #集合选择器
          - {key: zone,operator: In,values: ["foo"]}
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1

2)节点软亲和
preferredDuringSchedulingIgnoredDuringExecution

  • 柔性控制逻辑,当条件不满足时,能接受被编排于其他不符合条件的节点之上
  • 权重 weight 定义优先级,1-100 值越大优先级越高
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy-with-node-affinity
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:   #节点软亲和性
          - weight: 60
            preference:
              matchExpressions:
              - {key: zone, operator: In, values: ["foo"]}
          - weight: 30
            preference:
              matchExpressions:
              - {key: ssd, operator: Exists, values: []}
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
3.2.2 pod亲和性

1、Pod对象间亲和性,将一些Pod对象组织在相近的位置(同一节点、机架、区域、地区)
2、Pod对象间反亲和性,将一些Pod在运行位置上隔开
调度器将第一个Pod放置于任何位置,然后与其有亲和或反亲和关系的Pod据此动态完成位置编排
3、基于MatchInterPodAffinity预选策略完成节点预选,基于InterPodAffinityPriority优选函数进行各节点的优选级评估
4、位置拓扑,定义"同一位置"

1)Pod硬亲和调度
requiredDuringSchedulingIgnoredDuringExecution
Pod亲和性描述一个Pod与具有某特征的现存Pod运行位置的依赖关系;即需要事先存在被依赖的Pod对象

# 被依赖Pod
kubectl run tomcat -l app=tomcat --image tomcat:alpine
kubectl explain pod.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.topologyKey
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 硬亲和调度
      - labelSelector:
          matchExpressions:    #集合选择器
          - {key: app, operator: In, values: ["tomcat"]}  # 选择被依赖Pod
# 上面意思是,当前pod要跟标签为app值为tomcat的pod在一起
        topologyKey: kubernetes.io/hostname  # 根据挑选出的Pod所有节点的hostname作为同一位置的判定
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1

2)Pod软亲和调度
preferredDuringSchedulingIgnoredDuringExecution:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-with-preferred-pod-affinity
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      name: myapp
      labels:
        app: myapp
    spec:
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - {key: app, operator: In, values: ["cache"]}
              topologyKey: zone
          - weight: 20
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - {key: app, operator: In, values: ["db"]}
              topologyKey: zone
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1

3)Pod反亲和调度

1、Pod反亲和调度用于分散同一类应用,调度至不同的区域、机架或节点等。
2、将 spec.affinity.podAffinity替换为 spec.affinity.podAntiAffinity。
3、反亲和调度也分为柔性约束和强制约束。

apiVersion: v1
kind: Pod
metadata:
    name: pod-first
    labels: 
        app: myapp
        tier: fronted
spec:
    containers:
    - name: myapp
      image: ikubernetes/myapp:v1
---
apiVersion: v1
kind: Pod
metadata:
    name: pod-second
    labels:
        app: backend
        tier: db
spec:
    containers:
    - name: busybox
      image: busybox:latest
      imagePullPolicy: IfNotPresent
      command: ["/bin/sh", "-c", "sleep 3600"]
    affinity:
      podAntiAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
            - {key: app, operator: In, values: ["myapp"]}
          topologyKey: zone

3.3 污点和容忍度

3.3.1 介绍

污点 taints 是定义在节点上的键值型属性数据,用于让节点拒绝将Pod调度运行于其上,除非Pod有接纳节点污点的容忍度容忍度 tolerations 是定义在Pod上的键值属性数据,用于配置可容忍的污点,且调度器将Pod调度至其能容忍该节点污点的节点上或没有污点的节点上。

使用PodToleratesNodeTaints预选策略和TaintTolerationPriority优选函数完成该机制

节点亲和性使得Pod对象被吸引到一类特定的节点 (nodeSelector和affinity)
污点提供让节点排斥特定Pod对象的能力

  • 定义污点和容忍度
    污点定义于nodes.spec.taints容忍度定义于pods.spec.tolerations

语法: key=value:effect

  • effect定义排斥等级:
    NoSchedule,不能容忍,但仅影响调度过程,已调度上去的pod不受影响,仅对新增加的pod生效。
    PreferNoSchedule,柔性约束,节点现存Pod不受影响,如果实在是没有符合的节点,也可以调度上来
    NoExecute,不能容忍,当污点变动时,Pod对象会被驱逐
3.3.2 管理节点的污点

同一个键值数据,effect不同,也属于不同的污点

#给节点添加污点:
kubectl taint node  =:
kubectl taint node node2 node-type=production:NoShedule  #举例
#查看节点污点:
kubectl get nodes  -o go-template={{.spec.taints}}
#删除节点污点:
kubectl taint node  [:]-
kubectl patch nodes  -p '{"spec":{"taints":[]}}'

kubectl taint node kube-node1 node-type=production:NoSchedule
kubectl get nodes kube-node1 -o go-template={{.spec.taints}}
# 删除key为node-type,effect为NoSchedule的污点
kubectl taint node kube-node1 node-type:NoSchedule-

# 删除key为node-type的所有污点
kubectl taint node kube-node1 node-type-

# 删除所有污点
kubectl patch nodes kube-node1 -p '{"spec":{"taints":[]}}'
3.3.3 给Pod对象容忍度

spec.tolerations字段添加

tolerationSeconds用于定义延迟驱逐Pod的时长

# 等值判断
tolerations:
- key: "key1"
  operator: "Equal"  #判断条件为Equal
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600

# 存在性判断
tolerations:
- key: "key1"
  operator: "Exists"    #存在性判断,只要污点键存在,就可以匹配
  effect: "NoExecute"
  tolerationSeconds: 3600
apiVersion: v1
kind: Deployment
metadata:
    name: myapp-deploy
    namespace: default
spec:
    replicas: 3
    selector:
        matchLabels:
            app: myapp
            release: canary
    template:
        metadata:
            labels:
                app: myapp
                release: canary
        spec:
            containers:
            - name: myapp
            image: ikubernetes/myapp:v1
            ports:
            - name: http
              containerPort: 80
            tolerations:
            - key: "node-type"
              operator: "Equal"
              value: "production":
              effect: "NoExecute"
              tolerationSeconds: 3600
3.3.4 问题节点标识

自动为节点添加污点信息,使用NoExecute效用标识,会驱逐现有Pod
K8s核心组件通常都容忍此类污点

  • node.kubernetes.io/not-ready 节点进入NotReady状态时自动添加
  • node.alpha.kubernetes.io/unreachable 节点进入NotReachable状态时自动添加
  • node.kubernetes.io/out-of-disk 节点进入OutOfDisk状态时自动添加
  • node.kubernetes.io/memory-pressure 节点内存资源面临压力
  • node.kubernetes.io/disk-pressure 节点磁盘面临压力
  • node.kubernetes.io/network-unavailable 节点网络不可用
  • node.cloudprovider.kubernetes.io/uninitialized kubelet由外部云环境程序启动时,自动添加,待到去控制器初始化此节点时再将其删除
3.3.5 Pod优选级和抢占式调度
  • 优选级,Pod对象的重要程度
  • 优选级会影响节点上Pod的调度顺序和驱逐次序
  • 一个Pod对象无法被调度时,调度器会尝试抢占(驱逐)较低优先级的Pod对象,以便可以调度当前Pod
  • Pod优选级和抢占机制默认处于禁用状态
  • 启用:同时为kube-apiserver、kube-scheduler、kubelet程序的 --feature-gates 添加 PodPriority=true
  • 使用:事先创建优先级类别,并在创建Pod资源时通过 priorityClassName属性指定所属的优选级类别

你可能感兴趣的:(k8s 理论知识)