Jun 9, 2019 - 写在KubeCon之前

本想在欧洲的KubeCon之前总结一下近期的工作,一直拖到现在;还好中国KubeCon六月底又要开始了,不算太晚。算算这是从2016年开始,参加的第6个KubeCon了;收获与成长都很多,也认识很多朋友。文笔较差,所以就用流水账的形式记录一下;感想建议什么的,后面单独找时间介绍吧。

2016-新起点

2016年的时候IBM Spectrum (前Platform Computing)仍然在重点投入Mesos,并以Kubernetes on Mesos为主体推一款PaaS平台 (今天ICP的前身)。社区方面,开始接手Kubernetes on Mesos项目;该项目最初由Mesosphere在Kubernetes主社区维护,后来由于不再投入,转由IBM进行维护。IBM Spectrum一直比较推崇两级调度,主要是由于内部有一个相似的系统 (EGO)。EGO大概在2005年GA,提供了大量的资源管理及调度功能;但是作为一款商用软件,一直没能开源出来。关于两级调度的优劣及对Mesos社区的感想,后面再单独找时间详细介绍;一些早期的想法可以参考之前的讨论

接手Kubernetes on Mesos后便开始了基本的推广和维护工作,也由此开始了Kubernetes社区的工作。随着在Kubernetes工作的深入,逐渐将所有精力投入到kubernetes中;在Kubernetes on Mesos中仅剩一些宣传的工作;随后产品也转为以Kubernetes为基础的PaaS产品。Kubernetes on Mesos之后便不再参与这种跨多个社区的项目,主要是由于每个社区都有自己的目标、规范以及解决问题的习惯;重叠和互补部分很难达成一致。

在16年年底的时候中了第一个KubeCon的topic,是关于Kuberentes on EGO的 (与 Kubernetes on Mesos类似),介绍了一些EGO的基本功能。那届KubeCon在北美,只有大概 2000 人左右的样子;github的头像也是那时候CoreOS的活动画的。除了第一次与社区的各个贡献者面对面交流,更重要的一点是开始了Kubernetes中Batch作业的相关工作;在做了简单的线下交流后,在主社区open了 Manage multiple applications in Kubernetes ,并开始了差不多半年的讨论。

2017-在路上

在Kubernetes上游社区open了 Manage multiple applications in Kubernetes 之后,开始只是一些简单的讨论,后来由 David 起草了一个设计文档: Resource sharing architecture for batch and serving workloads in Kubernetes 。该设计文档主要包含了两个部分:一部分是最近GA的priority/preemption,另一部分则是如何支持batch workload。Priority/Preemption相对来说比较直接,总体设计很快便达成一致,并开始了相应的开发工作;但 batch workload部分却有很多细节的讨论。在讨论的过程中,发现自己对k8s本身的设计及社区的运营方式有很大的欠缺;因此加大了在kubernetes上游社区贡献,并在同年8月份成功申请Maintainer。

但是关于Batch workload的讨论一直都没有停止,主要是由于Kubernetes在最开始的设计上面以Service workload为主,基本上没有关于Batch workoad的概念及功能。在大概半年之后,大家还是决定创建一个孵化项目 (kube-arbitrator)来继续相应的工作。kube-arbitrator最开始由几个部分组成:1.) quotad:对Quota相关的加强,包括动态分配,资源租借及回收等;2.) batchd:对scheduler的加强,相比于default scheduler,主要支持针对作业级别的调度,包括作业之间的资源共享等;3.) QueueJob:另一部分就是对现在有Job的加强,可以启动一个完成的 AI 作业。由于人力的限制,一直花费了较多的精力在batchd上;quotad一直处于停滞的状态;而QueueJob一直有IBM FfDL维护。

初期的batchd仅包含一层接口,包括资源的分配和回收等;在维护的时候发现很多功能会杂糅在一起,导致新功能很难加入,已有功能很难维护等。在年底时便将整个batchd代码重写,分为action (allocate, preempt等)和plugin (gang, fair-share等)两层,方便新功能的加入和现有功能的维护。

2018-变化中

2018年还在继续着kube-arbitrator的工作;并基于当时的scope,逐渐希望把它做成一个Kubernetes的Batch System。相比于现在的 batch scheduler,batch system涵盖包含scheduler在内的其它部分,例如,作业管理,命令行,异构硬件,数据对接等;即 kube-batch的架构图中排除的部分。

虽然对Batch workload的需求越来越多,但是kube-arbitrator最初只有两个人维护,到18年初则变成我一个人在维护。 在年初的时候,上游社区开放了新的流程,允许各个SIG创建子项目 (kubernetes-sigs)。随着kubernetes-sigs的升温,kubernetes-incubator 逐渐进入废弃的状态;因此申请了将 kube-arbitrator 由 kubernetes-incubator 转入 kubernetes-sigs,并修改名字为 kube-batch。由于 kubernetes-sigs 下的项目仅能属于一个sig,因此在改名的同时,也将 kube-arbitrator/kube-batch的scope 限定在 batch scheduler部分;而将之前关于quota, queuejob 以及 其它与 batch system 相关的功能都排除在 kube-batch 之外。由于scope的变化,将已经有代码迁移到一个个人仓库 (vulcan),算是Volcano的前身。

2018对kube-batch来说是很重要的一年。随着机器学习逐渐被大家关注并用于生产,以及kubeflow的流行,机器学习框架对kubernetes的batch能力的需求也逐渐强烈起来。其中一个最基本的功能就是 gang-scheduling (all-or-nothing)。由于default scheduler还不具备作业级的调度,因此gang-scheduling最终也实现在kube-batch里;并与kubeflow/tf-operator等各个上层社区完成了集成。

2018另外一个比较大的变化是自己最终在11月份入职了华为;有很多因素,感谢在这个过程中的同学们。

2019-在华为

加入华为差不多半年左右的时间,工作紧张有序,没有外界传言的那么夸张;节奏上跟之前我在Platform Computing的时候差不多。在这半年的时间里,最主要的工作就是把 Volcano 作为 Kubernetes Native Batch System开源出来;在参与到Kubernetes社区之后,一直希望可以加强Kubernetes对batch workload的支持,从而使Kubernetes成为一个统一的基础平台;这样方便后续的工作,例如统一的资源调度及资源管理。

Volcano 包含了 Batch System 需要的主要功能,例如作业管理,资源调度,资源管理,和对异构硬件的支持。相比传统的的Batch System,Volcano 还提供不同的使用方式:作业接口 或是 调度器 接口:对于现有的operator,可以直接使用调度器的接口,而对于新的batch workload则可以尝试作业接口来简化开发和维护成本。

2019也已经过去了一半,希望 Volcano 下半年有更多的使用者。

May 11, 2017 - FAQ of k8s, docker and glusterfs

Change Docker Imange location

Edit /etc/docker/daemon.json in Ubuntu:

{
    "live-restore": true,
    "graph": "/data/docker"
}

Kuberentes Errors

In following erro may because of changing docker image location, no solution for now:

3m	3m	1	kubelet, 9.111.143.205		Warning	FailedSync	Error syncing pod, skipping: failed to "StartContainer" for "POD" with RunContainerError: "addNDotsOption: ResolvConfPath \"/data/docker/containers/cdc30b87403ef938964754e34ad3ce5b4c1ceb950a0af72ff1e531c235eaad21/resolv.conf\" does not exist"

Glusterfs Errors

Redirecting to /bin/systemctl status  glusterd.service
glusterd.service - GlusterFS, a clustered file-system server
   Loaded: loaded (/usr/lib/systemd/system/glusterd.service; enabled)
   Active: failed (Result: exit-code) since Fri 2014-09-26 01:47:54 EDT; 5min ago
  Process: 25116 ExecStart=/usr/sbin/glusterd -p /run/glusterd.pid (code=exited, status=1/FAILURE)

Sep 26 01:47:54 datasvr1 systemd[1]: glusterd.service: control process exited, code=exited status=1
Sep 26 01:47:54 datasvr1 systemd[1]: Failed to start GlusterFS, a clustered file-system server.
Sep 26 01:47:54 datasvr1 systemd[1]: Unit glusterd.service entered failed state.

The root cause is glusterfs can not use non-empty working directory; the solution is to clear working-directory in /etc/glusterfs/glusterd.vol.

GlusterFS Errors

Readiness probe failed: ● glusterd.service - GlusterFS, a clustered file-system server
   Loaded: loaded (/usr/lib/systemd/system/glusterd.service; enabled; vendor preset: disabled)
   Active: inactive (dead)

Resolved by: systemctl stop rpcbind.socket

Apr 4, 2017 - Kuberentes中基于策略的资源分配

前言:清明放假,抽空把在社区提的Proposal翻译一下。另外,我们产品的新版本(1.1) 节前也 release 了,有兴趣可以下载试用一下;有问题欢迎随时讨论 (我是传送门,戳我,戳我) 。

===================

原文 传送门,译文如下:

用户场景和要求

作为集群管理员,希望建立一个环境来运行不同的工作负载,例如 “长服务”,大数据。 由于这些应用程序由不同的部门管理,我必须为每个应用程序提供资源保证,如下所示:

长服务(app area)和 大数据(bigdata area)可以共享资源:

  • 定义每个区域的资源使用情况,例如 40%的资源到应用程序区域,60%到大数据区域。
  • 借款/贷款协议:如果资源在一个区域空闲,可以借出并被抢占

在大数据区域运行多个群集:

  • 定义bigdata区域内每个群集的资源使用情况,例如 Spark,Hadoop
  • 在这些大数据集群之间共享资源,例如 借贷方式

以大数据为例,下面是一些要求细节:

  • 运行一组应用程序
  • 提供每个应用程序保证访问一定数量的资源
  • 提供了所有应用程序尽力访问所有未使用的资源,根据某些目标权重(每个应用程序分配一个权重,即如果所有应用程序都想使用所有可用资源,则允许以相对比例的方式执行此操作)
  • 如果一些应用程序A的使用少于其保证,然后如果它决定使用其保证,并且没有足够的可用资源来执行此操作,则应该能够从某些其他应用程序或应用程序(即/使用超过他们的保证)以获得其保证 此外,将“大数据”应用和“服务”应用分成两个桶,提供每个桶(总计)保证访问集群的一小部分,并尽可能地访问整个集群,同时了解上述保证的使用可以随时撤销。 根据这个 mesos-style.md 文档,我们可以建立一个定制的组件来做到这一点;但由于这是资源管理和资源共享等一般性功能要求,最好由Kubernetes提供资源规划。

术语:

  • arbitrator:根据策略分配资源(resource allocation)的新组件;kube-scheduler仍通过现有的策略(亲和等)为Pods指定使用的资源(resource assignment)
  • deserved:arbitrator分配给namespace的资源总数
  • overused:如果使用的资源超过deserved的资源,命名空间将被认为是overused的

背景: 随着Kubernetes的成长,目前可以通过以下几个功能实现资源的共享。

Admission 和 ResourceQuota

在kubernetes中,namespace-level quota定义了命名空间可以使用的最大资源。通过ResourQuotaAdmission 实现,如果超过配额,则拒绝Pod创建。如果总配额大于集群的能力,则不会定义如何在namespace之间共享资源:如果一个namespace使用的资源少于其配额而但其它namespacey的资源请求超出了配额,则不能将这些资源借给其他资源(并在必要时抢占回来)。 Admission Controller是一个一般概念:Kubernetes可以根据任意策略拒绝Pod创建。例如,即使应用程序具有足够的配额来运行pod,如果应用程序在群集中使用的资源超过了比例,它也可以拒绝Pod创建。之前有过关于 “Job”(per-controller)进行Admission Control的讨论;这样就可以像批量任务系统那样进行处理。作为一般概念,可以建立定制的Admission Controller以拒绝Pod创建;但为了达到以下要求,引入了arbitrator:

  • 需要根据namespace的请求(例如挂起的pod)计算每个namespace的deserved资源 (e.g. pending Pods)
  • 如果namespace使用了超过deserved的资源 (overused),需要在指定时间内将部分资源回收以供其它namespace使用
  • 允许超出deserved/quota来创建“高优先级”pod,这样高优先级的pod可以抢占资源(“高优先级”可能是workload customized)

抢占和重新安排

一个Pod可以被杀死然后重启,因为一些其他Pod需要它使用的资源(抢占)。有一个基于优先级的抢占方案(见Borge)的讨论(每个pod都有一个优先级,而具有更高和可能相同优先级的pod可以抢占它;但谁做出决定哪个pod要抢占还不确定:可以是默认的调度程序,rescheduler 和/或 具有调度功能的 customized controller)。抢占总是 graceful 的终止。优先权方案通常意味着一个优先级别基础上的配额分配,以便应用程序可以在最高优先级级别给予一定数量的配额,并且可以给予较低的优先级更大量的配额(甚至是无限的,即集群的整体容量)。并且通过resetuler驱逐pod来重新优化集群级别的策略(目前有一个执行策略的原始调度器: “关键的pod,如Heapster,DNS等不会由于集群中的空闲资源不足也无法运行;但有其他很多政策可以添加并执行)。它通过驱逐一个或多个pod来允许一些待处理的pod(s)进行调度。

抢占需要在namespace之间调度资源;arbitrator 可是定义“优先”的决策者之一。没有满足deserved的namespace的优先级高于overused的namespace。arbitrator将利用eviction功能进行抢占。rescheduler 将会继续为关键Pod抢占资源,也会重新调度Pods来达到更高的资源使用效率。有了arbitrator,kube-system具有无限的deserved资源:deserved的资源总是等于它的请求,其他namespace则共享其余的资源。

Customized Controller和ThirdPartyResource:

ThirdPartyResource是使用新的API对象类型来扩展Kubernetes API的一种方法。新的API类型将被赋予一个API endpoint并支持相应的增、删、改、查操作。您可以使用此API endpoint 创建自定义对象。通过 mesos-style.md 和ThirdPartyResource,开发人员可以使用自定义对象构建workload customized controller。k82cn/kube-arbitrator 有一个例子,它通过ThirdPartyResource功能提供资源共享和抢占功能。

水平/垂直缩放和节点级QoS: 节点级资源使用率的改进,对集群级资源共享并无贡献。

PS: 最近有一个关于”垂直缩放”的讨论/提案,个人感觉可以通过 vpa/hpa 与 arbitrator/scheduler 联动来管理集群资源,从而动态调整集群的资源分配情况来提高资源的使用效率。

解决方案/提案

概述:

为了达到上述要求,引入了一个新的组件(k8s-arbitrator)和两个 ThirdPartyResource(Consumer / Allocation)。

以下yaml文件演示了Consumer的定义:

apiVersion: kuabe-arbitrator.incubator.k8s.io/v1
kind: Consumer
metadata:
  name: defaults
spec:
  hard:
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi
  reserved:
    limits.memory: 1Gi

对于每个Consumer对象,它有两个字段: hardreserved

  • reserved:定义了为namespace保留的资源。它使用与”Compute Resource Quota”和”Storage Resource Quota”相同的资源类型。reserved不能超过hard 定义的资源。 如果启用了ResourceQuota Admission,它还将检查“预留”的总数是否超过了群集中的资源。
  • hard:定义了namespace可以使用的最大资源;它不能超过namespace的Quota.hard

Consumer是由仲裁员为每个命名空间创建的,并且必要时由集群管理员进行更新;仲裁员创建具有无限hard和零reserved的保留的Consumer,因此namespace默认共享集群资源。

arbitrator将创建或更新Allocation中的额外字段: deserved

  • deserved:类似于Quota中的“Used”,它没有在yaml文件中定义,而是由arbitrator更新。它定义了arbitrator分配给命名空间的总资源。它不会走过Quota.hard,也可能因namespace的资源请求而改变。
  • hard/deserved:从Consumer复制;如果Consumer被更新,它也将在下一个调度周期被更新
apiVersion: kuabe-arbitrator.incubator.k8s.io/v1
kind: Allocation
metadata:
  name: defaults
spec:
  deserved:
    cpu: "1.5"
  hard:
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi
  reserved:
    limits.memory: 1Gi

下图显示了Consumer/Allocation中的hardreserveddeserved的关系。

注意:只有”Compute Resource Quota”和”Storage Resource Quota”可用于reserveddeserved

    -------------  <-- hard
    |           |
    |           |
    - - - - - - -  <-- deserved
    |           |
    |           |
    |           |
    -------------  <-- reserved
    |           |
    -------------

k8s-arbitrator 是一个新的组件,它会创建/更新 Consumer 和 Allocation:

  • 基于arbitrator的策略计算 deserved 资源(Allocation.deserved);例如:DRF和namespace的请求(PoC中使用了pending pod)
  • 如果namespace 使用了过多的资源 (used > deserved),arbitrator 通知相应的controller,并在指定时间后有选择的终止Pod

同时,k8s默认调度器仍然根据其策略来分派任务到主机,例如 PodAffinity:k8s-arbitrator 负责 resource allocation, k8s-scheduler 负责 resource assignment

Arbitrator 将DRF作为默认策略。它将从 k8s-apiserver 中取得pod/node,并根据DRF算法计算每个namespace的deserved资源;然后更新相应的配置。默认调度间隔为1s,可配置。arbitrator不会将主机名分配给deserved资源中;它依赖默认的调度器(kube-scheduler)在适当的主机上分派任务。

仲裁员还符合以下要求:

  • namespace的总体deserved资源不能超过群集中的资源
  • deserved资源不能超过消费者的hard资源
  • 如果集群中有足够的资源,deserved资源不能少于reserved资源

抢占

当资源请求/配额发生变化时,每个命名空间的deserved资源也可能会发生变化。 “较高”的优先级Pods将可能触发eviction,下图显示了由于deserved资源变化而引发eviction的情况。

T1:                T2:                              T3:
 --------------    -------------- --------------    -------------- --------------
 | Consumer-1 |    | Consumer-1 | | Consumer-2 |    | Consumer-1 | | Consumer-2 |
 |   cpu:2    | => |   cpu:1    | |   cpu:0    | => |   cpu:1    | |   cpu:1    |
 |   mem:2    |    |   mem:1    | |   mem:0    |    |   mem:1    | |   mem:1    |
 --------------    -------------- --------------    -------------- --------------
  • T1:集群中只有一个namespace:Consumer-1; 所有资源(cpu:2,mem:2)都被分配给它
  • T2:创建一个新的namespace: Consuemr-2; arbitrator 重新计算每个namespace的资源分配,缩小overused的namespace
  • T3:管理overused的namespace的controller必须选择一个Pod来杀死,否则arbitrator将会随机抽取需要杀死的Pods。Evict后,资源会被分配给underused的namespace

Arbitrator使用pod的 “/evict” REST API 来回收资源。但是当arbitrator选择需要被杀死的Pods时,至少有两个要求:

  • Evict后,pods不能少于PodDisruptionBudget
  • Evict后,namespace的资源不能少于reserved

namespace在驱逐后可能会变成underused; arbitrator将尝试从最overused的namespace尝试杀死Pods。 对于资源碎片的问题,暂时不在本文的讨论范围内; 将在抢占实施文档中讨论设计细节。

功能交互

Workload customized controller:

Aribtrator也对workload customized controller 起作用,它会杀死overused的namespace中的Pods。Customized controller不能比Allocation.deserved使用更多的资源,如果Allocation.deserved变小,customized controller 需要选择Pods杀死;否则arbitrator将在grace period后杀死 Pods(例如FCFS)。

Multi-scheduler:

如果使用multi-scheduler,只能启动一个arbitrator以避免竞争条件

Admission Controller:

AribtratorAdmission检查Consumer相对于Quota中”Compute Resource”和”Storage Resource”的定义:Consumer.hard不能超过Quota.hard。 ResourceQuotaAdmission的其他指标将遵循当前行为。对其他Admission插件没有影响。

节点级QoS

在原型中,仅考虑requestlimit会在后面的版本考虑

ReplicaController/ReplicaSet

由于Consumer/Allocation是namespace级别而不是Job/RC级别,k8s-controller-manager不能根据RC的比例创建pod;它需要最终用户在RC之间平衡Pods或在Consumer中请求预留资源。

kubelet:

现在还不涉及kubelet,虽然命名空间的Allocation.deserved也是kubelet中evict的一个因素,例如:

  • 拒绝overused的namespace的请求
  • 如果节点资源耗尽,则选择最overused的namespace里的Pods

目前进展:

  • 基于DRF的arbitrator策略(完成)
  • 由k8s-arbitrator自动创建Consumer/Allocation(持续)
  • 面向 Consumer.reserved 的策略(持续)
  • 其它,例如doc,测试(持续)

路线图和未来:

  • 高级的策略,例如不打破PodDisruptionBudget
  • 使用 “resourceRequest” 来减少 pending pod的使用
  • 加强关于存储策略,例如“PV / PVC”
  • k8s-arbitrator的HA
  • 层级Consumer
  • 无限Allocation用于kube-system
  • 面向 limit 的策略(节点/资源QoS)
  • Consumer / Allocation 客户端库,用于开发新的workload customized controller

引用: