K8s Scheduler(4-2)

理解resource limit 会如何影响pod 调度

  • Kubernetes 提供request 和 limit 两种方式设置容器资源。

  • 为了提高资源利用率,k8s调度时根据pod 的request值计算调度策略,从而实现节点资源超卖。

  • k8s根据limit限制pod使用资源,当内存超过limit时会触发oom。 且限制pod的cpu 不允许超过limit。

  • 根据pod的 request和limit,k8s会为pod 计算服务质量,并分为Guaranteed(requests和limits显示设置且相等或者只设置了limits,那么requests也会与之相等), Burstable(limits和requests显示设置不相等), BestEffort 这3级。当节点资源不足时,发生驱逐或者oom时, Guaranteed 级别的pod 优先保护, Burstable 节点次之(request越大,使用资源量越少 保护级别越高), BestEffort 最先被驱逐。

  • Kubernetes提供了RequestQuota和LimitRange 用于设置namespace 内pod 的资源范围 和 规模总量。 RequestQuota 用于设置各种类型对象的数量, cpu和内存的总量。 LimitRange 用于设置pod或者容器 request和limit 的默认值,最大最小值, 以及超卖比例(limit / request)。

  • 对于一些重要的线上应用,我们应该合理设置limit和request,limit和request 设置一致,资源不足时k8s会优先保证这些pod正常运行。

  • 为了提高资源利用率。 对一些非核心,并且资源不长期占用的应用,可以适当减少pod的request,这样pod在调度时可以被分配到资源不是十分充裕的节点,提高使用率。但是当节点的资源不足时,也会优先被驱逐或被oom kill。

不使用调度器, 手动调度一个pod

使用static pod可以实现手动调度一个pod。

static pod的特点总结如下:

  1. 不通过apiserver watch, 由本机的kubelet进程执行watch,并拉起
  2. 只在本机进行调度
  3. 没有健康检查
  4. 不被controller manager调度
  5. 因为apiserver里有pod的镜像信息, 通过apiserver还是可以看到pod的信息
如何创建?

方法一: kubelet启动时要指定参数kubelet --pod-manifest-path=,这里的the directory要放置static pod的编排文件的目录。 把static pod的编排文件放到此目录下, kubelet可以监听到变化, 并根据编排文件创建pod。

方法二: 指定--manifest-url=, kubelet会从这个URL下载编排文件, 并创建pod

如何删除?

当我们直接用kubectl的命令kubectl delete pod删除一个静态pod时, 我们会发现static pod过一段时间又会被kubelet拉起。

要完全删除一个static pod, 可以移除把该static pod的编排文件, 从--pod-manifest-path=所指定的目录里移除即可。

使用场景?

因为static pod有一个特性是我们的应用的docker 容器被删除,或者pod被kubectl误删了之后, static pod还能被kubelet进程拉起。通过这种方式保证了应用的可用性。 有点相当于systemd的功能, 但比systemd好的一点是, static pod的镜像信息会在apiserver中注册。 这样的话, 我们就可以统一对部署信息进行可视化管理。 另外static调度了的是容器, 无需拷贝二进制文件到主机上, 应用封装在镜像里也保证了环境的一致性, 无论是应用的编排文件还是应用的镜像都方便进行版本管理和分发。

实际生产中, static pod可以用来部署kubernetes的kube-proxy, kube-scheduler, kube-controller-manager, kube-apiserver等进程。

当我们要部署一个有状态的应用, 有几种方式:

  1. 使用statefulset
  2. 给主机打上label,只允许主机在这几台主机上调度
  3. 通过挂载ceph盘来存储有状态数据(要求master和node节点上都要安装rbd工具)
  4. 使用static pod ,但是这种方式适合那些无滚动升级需求, 无扩缩容需求,不频繁进行升级的应用

常用的优选算法介绍:

least_requested分值计算方式 (cpu((capacity-sum(requested))10/capacity) + memory((capacity-sum(requested))10/capacity))/2
其cpu和menmory分值各占一半。
balanced_resource_allocation是选用cpu和内存使用最为接近的节点,基于least_requested分值的计算结果判定。

那么schedule里的policy是啥样子的呢:

{
"kind" : "Policy",
"apiVersion" : "v1",
"predicates" : [
    {"name" : "PodFitsPorts"},
    {"name" : "PodFitsResources"},
    {"name" : "NoDiskConflict"},
    {"name" : "MatchNodeSelector"},
    {"name" : "HostName"}
    ],
"priorities" : [
    {"name" : "LeastRequestedPriority", "weight" : 1},
    {"name" : "BalancedResourceAllocation", "weight" : 1},
    {"name" : "ServiceSpreadingPriority", "weight" : 1},
    {"name" : "EqualPriority", "weight" : 1}
    ]
}

*** 4. controller的区别 ***

controller manager作为集群内部的管理控制中心,负责集群内的Node,Pod副本,服务端点(endpoint),命名空间(namespace)等的管理,当某个Node意外宕机,CM会及时发现此故障并执行自动化修复流程,确保集群始终处于预期的工作状态。

controller management包括:replication controller,node controller,rescourseQuota controller,namespaces controller,serviceAccount controller,token controller,service tontroller和endpoint controller。CM是这些controller的核心管理者。

Replication Controller

RC的作用是确保在任何时候集群中一个RC所关联的Pod副本数量保持预设值。

最好不用越过RC而直接创建Pod,因为通过RC管理Pod副本,实现自动创建,补足,替换,删除Pod副本,提供系统的容灾能力。

总结一下RC的职责:

1.确保当前集群中有且仅有N个Pod实例

2.通过调整RC中yaml文件的spec.replicas属性值来实现系统扩容或缩容

3.通过改变RC中的Pod模板来实现系统的滚动升级。

再总结一下RC的典型使用场景,如下

1.重新调度

2.弹性伸缩

3.滚动更新

Node controller

kubelet进程在启动时通过API server注册自身节点信息,并定时向API server汇报状态信息,API server更新这些信息到etcd中。

Node controller通过API server定时获取Node的相关信息,实现管理和监控Node。

endpoint controller 和service controller

endpoint表示了一个service对应的所有pod副本的访问地址,而endpoint controller就是负责生成和维护所有endpoint对象的控制器。负责监听service和对应的Pod副本的变化,若service被删除,则删除与该service同名的endpoint对象,若检测到新的service创建或修改,则先根据该service获取相应的pod列表,然后创建或更新service对应的endpoint对象。

那么endpoint对象如何使用呢。答案是在每个node上的kube-proxy进程,该进程获得每个service的endpoint,实现service的负载均衡功能。

Namespace controller

用户通过API server可以创建新的Namespace并保存在etcd中,namespace controller定时通过API server读取这些namespace信息,若namespace被删除,则NC删除该namespace下的RC,Pod等资源对象。

如果namespace controller观察到namespace设置了删除期限,同时namespace的spec.finalizers域值为空,则NC将通过API server删除该namespace资源。

ReplicaSet

ReplicaSet的目的是在任何时候都maintain一组稳定的pod replicas,常用来确保指定数量的pod replica可用。ReplicaSet具有selector,replicas, podTemplate字段。通过pod的metadata.ownerReferences字段来关联ReplicaSet和Pod。

注意:当创建的pod的label符合ReplicaSet的selector,且该pod不属于任何controller,则该pod会被自动归为该ReplicaSet拥有,导致ReplicaSet下的pod不相同;同时,会影响ReplicaSet本身的replica pod的个数。

建议使用Deployment来管理ReplicaSet,而不是直接使用,除非需要定制化的更新测例或不需要更新。

因为deployment不仅具备了replicaSet的功能,同时还支持事件和状态查看,回滚,版本记录,对于每次升级可以暂停和启动。

Deployment

Deployment对Pod和ReplicaSet提供声明式的更新。在描述预期状态后,Deployment会以可控的频率下使得实际状态符合预期状态。

默认情况下,Deployment保证最多25%的pod不可靠,pod数量最多超出25%。

StatefulSets

StatefulSets主要用来管理有状态的app。跟Deployment一样,StatefulSet用来管理Pod,但不同的是,StatefulSets中的每个pod都维护一个严格的identifier并在reschedule时不变。

StatefulSet具有以下特点:

  • Stable, unique network identifiers.
  • Stable, persistent storage.
  • Ordered, graceful deployment and scaling.
  • Ordered, automated rolling updates.

限制:

  • Pod的storage要么基于请求的storage class由PersistentVolume Provisioner设置,要么由admin提前设置好;
  • 删除或scale down StatefulSet将不会删除相关的volumes,用于保证数据安全;
  • StatefulSets目前需要创建headless service来负责pod的netework identity,用户负责创建该headless service;
  • StatefulSet删除后不保证pod结束,pod会按顺序gracefully的结束;
  • 当使用默认的Pod Management Policy(OrderedReady)作为rollupdate policy,可能需要人工干预来走出broken state。
  • StatefulSet上部署和扩展的规则:创建pod的顺序由0到N,删除的顺序正好相反;扩展时,前面的pod必须是Running和Ready状态,删除时,后续pod必须是terminated。

K8S 1.7之后,指定.spec.updateStrategy来设置更新策略,当.spec.updateStrategy.type为OnDelete时,在pod template改动后将不会自动更新Pods;为RollingUpdate,默认策略,将自动更新pod。RollingUpdate更新策略可以设置partition,通过设置字段 .spec.updateStrategy.rollingUpdate.partition来实现,当pod template更新后,只有ordinal大于等于partition的pod才会更新,小于partition的pod不更新。当.spec.replicas小于partition,所有pod不更新。

Job

Job创建一个或多个pod并确保指定数量的pod成功终止。当指定数量的pod成功终止后,job结束。场景:当创建的pod不能完成时,job会创建新的pod来完成任务。

下面是Job的示例。

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  backoffLimit:6
  activeDeadlineSeconds: 100 #
  ttlSecondsAfterFinished: 100 
  template:
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

restartPolicy只允许Never或OnFailure。

通过设置.spec.completions和.spec.parallelism属性来完成不同的任务,前者表示成功完成的任务数量,后者表示并行任务数量,默认都为1.当.spec.parallelism设置为0时,job将被暂停。

通过.spec.backoffLimit来设置pod失败后的重试次数,默认为6,重试的delay时间指数式增长,最长6分钟。

当Job complete,将不会创建pod,old pod也不会被删除,这样可以查看log。同时,Job也存在,这样可以查看status。可以通过kubectl delete来人工删除。

Job终止可能因为失败次数超过.spec.backoffLimit,或者因为job的运行时间炒超过设置的.spec.activeDeadlineSeconds。当Job的运行时间超过activeDeadlineSeconds,所有运行的pod被终止,Job状态变为Failed,reason: DeadlineExceeded。

-Cron Job

终止的Job不被回收会浪费资源,可以使用cron job来管理job并清理job。

Cron Job创建基于时间调度的job,时区为master node的时区。当Cron job大于100次没有被调度,将不会调度job并打印error信息。Cron job只负责创建符合schedule的job,而job负责pod的管理。

activeDeadlineSeconds

通过指定job存活时间,来结束一个job。当job运行时间达到activeDeadlineSeconds指定的时间后,job会停止由它启动的所有任务(如:pod),并设置job的状态为failed, reason: DeadlineExceeded

TTL Controller提供了一种机制来限制resource object执行完存活的时间,目前只处理Job。

ttlSecondsAfterFinished

使用场景:默认情况下,job异常或者成功结束后,包括job启动的任务(pod),都不会被清理掉,因为你可以依据保存的job和pod,查看状态、日志,以及调试等。这些用户可以手动删除,用户手动删除job,job controller会级联删除对应的pod。

除了手动删除,通过指定参数ttlSecondsAfterFinished也可以实现自动删除job,以及级联的资源,如:pod。如果设置为0,job会被立即删除。如果不指定,job则不会被删除。

你可能感兴趣的:(K8s Scheduler(4-2))