《kubernetes in action》学习笔记——14、计算资源管理 (LimitRange ResourceQuota cAdvisor)

一、为Pod中的容器申请资源

1、创建包含资源的requests的pod

apiVersion: v1
kind: Pod
metadate:
  name: requeste-pod
spec:
  containers:
  - name: main
    image: buxybox
    commad: ["dd", "if=/dev/zero", "of=/dev/null"]    
    resources:     // 为容器指定了资源的请求量
      requestes:
        cpu: 200m  // 容器申请200毫核,即一个CPU核心时间的1/5
        memory: 10Mi // 容器申请了10MB的内存
在pod manifest中,我们声明了一个容器需要1/5核的CPU才能正常运行。换句话说,五个同样的pod或容器可以足够快的运行在一个CPU核上。
当我们不指定CPU requests时,表会死我们并不关心系统为容器内的进程分配了多少CPU时间。在最坏的情况下进程可能根本分不到CPU时间(其他进程对CPU需求很大的情况下)。这对一些时间不敏感、低优先级的batch jobs没有问题,但用于处理用户请求的容器,这样的配置就不太合适了。

在pod spec中申请了10MB的内存,说明我们期望容器内的进程最大消耗10MB的RAM。它们可能占用较小,但正常情况下我们并不希望它们占用超过这个值。在后面我们可以看到如果超过了会发生什么。
运行pod,通过“kubecl exec -it requests-pod top”可以查看进程的CPU使用。
我们在容器执行dd命令会消耗尽可能多的CPU,但因为它是单线程运行,所以最多只能跑满一个核。如果宿主机拥有两个核,则会显示占用了50% 的CPU。这是符合我们预期的,虽然超过了我们申请的200M,但是requests不会限制容器可以使用的CPU数量。后面我们可以对其最高占用进行限制。

2、资源requests如何影响调度
通过设置requests指定了pod对资源的最小要求。调度器在调度该节点时可以看到该值,当节点上剩余的资源不符小于需求值时,该pod不会调度到该节点上。
调度器如何判断一个pod是否合适调度到某一个节点上
这里比较重要的是,调度器在调度时并不关注各资源在当前时刻的实际使用量,只会关心节点上部署的所有pod资源申请量总和。尽管现有pods的资源实际使用量小于pod需求,但如果基于实际资源使用量的调度算法将打破系统为这些已部署成功的pods提供足够资源的保证。
调度器如何利用pod requests为其选择最佳节点
调度器在选择节点时,会分为两个过程,预选阶段和优选阶段。预选阶段会将不符合需求的节点先排除掉,然后根据预先配置的优先级函数对其余节点进行排序。其中有两个基于资源请求量的优先级函数:LeastRequestedPriority和MostRequestedPriority。前者优先将pod调度到请求量少的节点(拥有更多未分配资源的节点),后者优先调度到求情量多的节点(拥有更少未分配资源的节点)。需要注意的是,它们只关注资源请求量,而不是实际使用资源量。
通过pod更紧凑地编排,一些节点可以保持空闲并随时可以从集群中移除。由于一般会按照单个几点付费,这样就可以节省一笔开销了。

查看节点资源的总量
调度器要知道每个节点拥有多少COU和内存资源,kubelet会想API服务器报告相关的数据,并通过节点资源对外提供访问。可以使用kubelet describe nodes命令查看,其中的Capacity表示节点资源的总和,Allocatable表示可分配给pod的资源量。资源总量代表节点所有的资源总和,包括那些可能对pod不可用的资源。有些资源会为kubernetes或者系统组件预留。调度器的决策仅仅基于可分配资源量。
部署一个资源请求量大于节点剩余量的pod,可以看到,虽然可以创建,但是pod的状态一直处于pending状态,通过kubectl describe 命令查看pod详情,可看到PodSchedule状态为false,同时事件中也可以看到相关提示。

3、CPU requests 如何影响CPU时间分配
假设有两个pod正在集群中运行(暂时不考虑系统pod,因为它们长时间是处于空余状态的),一个申请了200mCPU一个申请了1个(即1000m)CPU资源。kubernetes对requests和limits会区别对待,我们这没有设置limits,因此每个pod分别可以消耗CPU资源没有限制。那么当每个pod内的进程都尽量消耗CPU时间,每个pod最终能分配到多少CPU时间呢?
CPU requests不仅仅在调度的时候起作用,它还决定着剩余的CPU时间如何在pod之间分配,它会按照申请时的比例(这里是1:5),分配未使用的CPU时间。假设CPU总量为2个核,则第一个pod将获得16.7%的CPU时间,另一个将获得83.3%的CPU时间。
另一方面,如果一个容器能够跑满CPU,而另一个容器在该时段处于空闲,那么前者可以使用整个CPU时间,这样可以提高资源的使用率。当第二个容器需要CPU时间的时候,就能获取到,同时第一个容器会被限制回来。

4、定义和申请自定义资源
kubernetes允许用户为节点添加属于自己的自定义资源,同时支持在pod资源requests里申请该资源。
首先,需要通过将自定义资源加入到节点API对象的capacity属性,让kubernetes知道它的存在。这可以通过执行HTTP的PATCH请求来完成。资源名称可以是不以kubernetes.io域名开头的任意值,数量必须是整数(例如不能设置成100m,因为0.1不是整数,但可以是1000m、2000m或简单的1或2)。这个值将自动从capacity字段复制到alliocatable字段。
然后,创建pod时,只要简单的在容器的resources.requests字段下,或是命令行创建时–requests 参数。调度器就能确保这个pod只能部署到满足自定义资源申请量的节点,同时为每个已部署的pod减少节点的这类可分配资源数量。常见的自定义资源有GPU。

二、限制容器的可用资源

1、设置容器可使用资源量的硬限制
我们之前看到,当其他容器进程处于空闲时,容器可以被允许使用所有CPU资源。我们可以限制一些容器最高使用量,包括CPU核内存。
CPU是一种可压缩资源,意味着我们可以再不对容器产生不利影响的同时,对其使用量进行限制。而内存明显不一样,是一种不可压缩资源,一旦系统为进程分配了一块内存,在该进程主动释放之前将无法被回收。这就是为什么要限制容器最大内存分配量的根本原因。
创建一个带有limits的pod

apiVersion: v1
kind: Pod
metadata: 
  name: limits-pod
spec:
  containers:
  - name: main
    images: busybox
    command: ["dd", "if=/dev/zero", "of=/dev/null"]  
    resources:
      limits:
        cpu: 1       // 这个容器最大只能使用1核CPU
        memory: 20Mi  // 这个容器最多只能占用20MB内存

注意:如果没有指定资源requests,它将被设置为与limits相同的值

可超卖的limits
与资源requests不同的是,资源limits不收节点可分配资源的约束。所有limits总和加起来允许超过节点节点资源总量的100%。换句话说,资源limits可以超卖。如果节点资源使用量超过100%,一些容器将被杀死,这是一个很重要的结果。在后续我们将看到kubernetes如何杀掉那些容器,不过只要单个容器尝试使用比自己制定的limits更多的资源时,也可能被杀掉。

2、超过limits
当容器运行的进程尝试使用比限额更多的资源时会发生什么?
我们已经了解了CPU是可压缩资源,当进程不等待IO操作时,消耗所有的CPU时间是非常常见的。正如我们所知道的,对一个进程的CPU使用率可以限制,因此当为一个容器设置CPU限额时,该进程只会分不到比限额更多的CPU而已。
可内存就所有不同。当进程尝试申请分配比限额还多的内存时会被杀掉(我们会说这个容器被OOMKilled了,OOM是 out of memory的缩写)。如果pod重启策略为Always或OnFailure,进程将会立即重启,因此用户可能察觉不到它被杀死了。但是如果它继续超限被杀死,kubernetes会再次尝试重启,并开始增加下次重启的时间间隔。这种情况下用户会看到pod处于CrashLoopBackOff。
CrashLoopBackOff状态表示kubelet还没有放弃,它意味着在每次崩溃后,kubelet将会增加下次重启之间的时间间隔。随着不断崩溃,延时时间也会按照20、40、80、160秒几何增长,最终收敛在300秒。一旦间隔时间达到300秒,kubelet将以5分钟为间隔时间对容器进行无限重启,直到容器正常运行或删除。
定位容器crash原因,可以通过查看pod日志以及kubectl describe pod命令,可在State.Reason看到为 OOMKilled,查看前一次死掉的原因 Last State.Reason状态
OOMKilled状态告诉我们,容器是因为内存不足而被系统杀掉了,当第一次开始为容器设置限制时,大多数用户会被警惕。
因此,如果你不希望容器被杀掉,重要一点就是不要将内存limits设置得很低。而容器有时即使没有超限也依然会被OOMKilled。会在后续谈到,现在先来讨论一下在大多数用户首次指定limits时需要警惕的地方。

3、容器中的应用如何看待limits
先部署limits-pod.yaml ,然后进入容器运行top 命令,kubectl exec -it limits-pod top 查看输出
查看user和free内存量,这些数值远远的超出我们为容器设置的20MB限额。同样的,我们设置了1个核,即使我们使用dd命令通常会消耗所有的CPU资源,但主进程似乎只用到了一些,这是为什么呢?

在容器内看到的始终是节点的内存,而不是容器本身的内存
即使你为容器设置了最大可用内存的限额,top命令显示的是运行该容器节点的内存数量,而容器无法感知到此限制。
这对任何通过查看系统剩余可用内存数量,并使用这些信息来决定自己该使用多少内存的应用来说都具有非常不利的影响。
对于Java程序来说这是一个很大的问题,尤其是不使用 -Xmx 选项指定虚拟机的最大堆大小时,JVM会将其设置为主机总物理大小的百分值。在kubernetes开发集群运行Java容器应用时,因为内存limits和笔记本电脑中内存差距不是很大,这个问题不是很明显。
但是如果pod部署在拥有更大物理内存的生存系统中,JVM将瞬速超过预先配置的内存限额,然后OOMKilled。
也许你觉得可以简单的设置-Xmx选项就可以解决这个问题,那么你错了,很遗憾-Xmx选项仅仅限制了堆大小,并不管其他off-heap。好在新版本Java会考虑到容器limits以缓解这个问题。

容器内统一可以看到节点所有的CPU核
与内存一样,无论有没有配置CPU limits,容器也会看到节点所有的CPU。将CPU限额为1 ,并不会神奇的只为容器暴露一个核。CPU limits做的只是限制容器使用CPU时间。
如果限额1核的容器运行在64核的节点上,它只能使用1/64的全部CPU时间。而且即使限额为1核,容器进程也不会只在一个核上,不同时刻,代码还是会在多个核上运行。
需要注意的是,有一些程序通过查询系统CPU核数来决定启动工作线程数量,同样在开发环境的笔记本上运行良好,但是部署在拥有更多核的节点上时,程序会快速的启动大量线程,所有线程都会争夺有限的CPU时间,同时每个线程通常需要额外的内存资源,导致应用的内存使用量急剧增加。
不要依赖应用程序从系统获取的CPU数量,你可能需要使用 Downward API将CPU限额传递至容器并使用这个值。也可以通过cgroup系统直接获取配置的CPU限制,请查看下列文件
/sys/fs/cgroup/cpu/cpu.cfs_quota_us
/sys/fs/cgroup/cpu/cpu.cfs_period_us

三、了解pod QoS等级

前面已经说过资源limits可以超卖,也就是说,一个节点不一定能提供比在其上运行pod的资源limits总和还大的资源。
假设当一个pod需要更多内存时,但是节点内存已不够时,这时会发生什么?kubernetes会按照pod的QoS等级,依次删除pod

在kubernetes中将pod划分为三种QoS等级

  • BestEffort
    优先级最低,pod中没有为任何容器设置requests与limits,它没有任何的资源保障。在最坏的情况下,它们分配不到任何CPU时间,同时需要为其他pod释放内存时,它们会被第一个杀死。不过BestEffort
    的 pod没有设置内存limits,当有充足内容资源时,它们可以任意使用。
  • Guaranteed 优先级最高,pod中所有资源的requests和limits相等。它们要满足一下三个条件
    1、CPU和内存都要设置requests和limits
    2、每个容器都要设置资源量
    3、每种资源的requests和limits值都要一样
    如果容器资源的requests没有显示的声明,默认与limits相同。所以只设置所有资源的限制量就可以使pod的QoS等级为Guaranteed。这些容器可以使用它申请的资源,但是也无法消耗更多的资源。
  • Burstable 介于BestEffort与Guaranteed之间,其他所有的pod都属于这个等级,Burstable
    pod可以使用其申请的资源,也可以使用额外的资源(不超过limits)

明白容器的QOS等级
对于单容器而言,容器的QoS等级就是pod的等级。
对于多容器而言,如果所有容器的QoS等级都一样,则该等级就是pod的QoS等级。只要有一个容器的QoS等级与其他容器的等级不一致,则该pod的等级为Burstable。

内存不足时那个进程会被杀死
在一个超卖的系统,QoS等级决定着哪个容器第一个被杀掉,这样释放出的资源提供给高优先级的pod使用。BestEffort等级的pod会被优先杀掉,然后是Burstable pod,最后是 Guaranteed pod。Guaranteed pod只有在系统进程需要内存时才会被杀掉。

如何处理相同等级QoS等级的容器
每个运行中的进程都有一个称为OutOfMemory(OMM)分数的值,系统比较所有运行进程的OMM分数,当需要释放内存时,分数最高的进程会被杀掉。
OMM分数由两个参数计算得出:进程已消耗的内存占可用内存的百分比,与一个基于pod QoS等级和容器内存申请量固定的OMM分数调节因子。对于两个属于Burstable等级的但容器pod,系统会杀掉内存实际使用量占可用比例更高的pod,而不是实际内存使用最多的。这说明不仅要关注requests和limits之间的关系,还要考虑requests和预期实际消耗内存之间的关系。

四、为命名空间中的pod设置默认的requests和limits

已经了解了如何为单个容器设置资源requests和limits,但是集群怎么限制用户创建容器时的资源申请?及怎么默认给容器设置requests和limits?

LimitRange 资源介绍
用户可以创建一个LimitsRange资源来避免必须配置每个容器。LimitRange资源不仅允许用户(为每个命名空间)指定能给容器配置的每种资源的最小值和最大限额,还支持在没有显示指定资源的requests时为容器设置默认值。
LimitRange资源被LimitRange准入控制插件。API服务器接收到带有pod描述信息的POST请求时,LimitRange插件对pod spec进行校验。校验失败将拒绝。因此,LimitRange被广泛应用在阻止用户创建大于节点资源量的pod。如果没有LimitRange,API服务器将欣然接收pod创建请求,但永远无法调度成功。
LimitRange资源中的limits会应用于同一个命名空间中独立的pod、容器,或其他资源对象。它并不会限制这个命名空间中的所有pod可用资源的总量,总量是通过ResourceQuota对象指定的,这将在后续说到。

创建LimitRange对象

apiVersion: v1
kind: LimitRange
metadata:
  name: xxx
spec:
  limits:
  - type: Pod            // 指定整个pod的资源limits
    min:                 // pod中所有容器的CPU和内存的请求量最小值和与最大值
      cpu: 50m
      memory: 5Mi
    max:                // pod中所有容器的CPU和内存的请求量最大值
      cpu: 1
      memory: 1Gi      
  - type: Container    // 指定容器的资源限制
    defaultRequest:    // 容器没有申请资源申请值时的默认值
      cpu: 100m
      memory: 10Mi
    default:           // 容器没有设置资源limits时limits的默认值
      cpu: 200m
      memory: 100Mi
    min:               // 容器申请资源的最小值
      cpu: 50m
      memory: 5Mi
    max:               // 容器申请资源的最大值
      cpu: 1
      memory: 1Gi
    maxLimitRequestRatio:  // 每种资源requests与limits的最大比值
      cpu: 4
      memory: 10
  - type: PersistenVolumeClaim  // 还可以指定请求pvc存储容量的最小及最大值
    min:
      storage: 1Gi
    max:
      storage: 10Gi  
      

如上代码,这个pod资源的最大值与最小值都可以设置,它应用于pod中所有容器的requests和limits之和。
在更低一层的容器级别,用户可以设置最小值和最大值,还可以为没有显示指定容器资源requests(defaultRequests)和limits(default)的默认值。除了这些还可以设置limits和requests的最大比例。例如例子中设置maxLimitsRequestRatio为4,则表示容器的CPU limits不能超过requests的 4 倍。如果容器申请了200m的CPU,则它CPU limits不能大于800,否则不能创建。内存则是十倍。同样也可以对申请pvc的大小时进行限制。
例子中使用一个LimitRange对象,对所有资源进行限制,也可以创建LimitRange对象单独的对pod、容器或pvc进行限制。多个LimitRange对象的限制会在校验时进行合并。
由于LimitRange对象配置的校验信息在API服务器接收到新pod或pvc创建请求时生效,所以之后修改了限制,或已存在的pod和pvc将不会再次校验,新的限制只会限制后续pod或pvc的创建。

五、限制命名空间中的可用资源总量

LimitRange只能限制单个pod,而同样也有一个限制命名空间中的可用资源的总量。这可以通过创建一个ResourceQuota.
ResourceQuota的接纳控制插件会检查将要创建的pod是否会引起总资源量超出ResourceQuota,如果超出,创建请求会被拒绝。因为资源配额在pod创建时进行检查,所以ResourceQuota对象仅仅作用于在其后创建的pod,对已存在的pod并不起作用。
资源配额限制了一个命名空间中pod和PVC存储最多可以使用的资源总量。同时也可以限制用户允许在该命名空间中创建pod、PVC,以及其他API对象的数量。

为CPU和内存创建ResourceQuota
限制命名空间中所有的pod允许使用的CPU和内存总量

apiVersion: v1
kind: ResourceQuota
metadata:
  name: cpu-and-memory-quota
spec:
  requests.cpu: 400m
  requests.memory: 200Mi
  limits.cpu: 600m
  limitis.memory: 500Mi  

为CPU和内存分别定义了requests和limits总量。与LimitRange不同的是,一个限制单独的pod或容器,一个限制的是命名空间的总量。一样的是它们作用域也是命名空间。

可以使用 kubectl describe quota 查看当前命名空间资源使用量
注意:创建ResourceQuota后,一定要创建LimitRange,否则pod中没有显示的设置requests和limits时,pod将创建失败,API服务器会拒绝该pod的请求。

为持久化存储指定配额
ResourceQuota对象同样可以限制命名空间中最多可以声明的持久化存储总量

apiVersion: v1
kind: ResourceQuota
metadata:
  name: storage
spec:
  requests.storage: 500Gi
  ssd.storageclass.storage.k8s.io/requests.storage: 3000Gi
  standard.storageclass.stprage.k8s.io/requests.storage: 1Ti    

在命名空间中所有可申请的PVC总量为500G,动态申请固态存储(以ssd命名的StorageClass)总量为300G,低性能的HDD存储(StorageClass.standard)限制为1T。

限制可创建对象的个数
资源配额同样可以限制单个命名空间中的pod、ReplicationController、Service以及其他对象的个数。集群管理员可以根据比如付费计划限制用户能够创建的对象个数,同时也可以用来限制公司IP或者Service可使用的节点端口个数

apiVersion: v1
kind: ResourceQuota
metadata:
  name: objects
spec:
  hard:
    pods: 10
    replicationcontrollers: 5
    secrets: 10
    conigmaps: 10
    persistentvolumeclaims: 4
    services: 5
    services.loadbalancers: 1
    services.nodeports: 2
    ssd.storageclass.storage.k8s.io/persistentvolumeclaims: 2

上面例子运行用户再一个命名空间中最多创建10个pod,无论是手动创建还是通过rc、rs、DaemonSet或者job创建的。同时限制了rc的个数为5,service个数为5,其中loadbalancer类型为1个,nodeport为2 个。pvc 为4个(该限制同样对storageclass有效)
对象个数配额目前可以为一下对象配额:

  • pod
  • ReplicationController
  • Secret
  • ConfigMap
  • PersistentVolumeClaim

service,以及两种特定的类型LoadBalancer、NodePort
甚至可以为ResourceQuota对象本身设置对象个数配额。其他对象个数,比如rs、job、Deployment、Ingress等暂时不支持(不知道最新的k8s是否支持)

为特定的pod状态或者QoS等级指定配额
目前为止我们创建的ResourceQuota应用于所有的pod,不管pod的当前状态和QoS等级如何。但是ResourceQuota可以被一组quota scopes限制。目前配额作用范围共4种:BestEffort、NotBestEffort、Terminating、NotTerminating。
BestEffort和NotBestEffort范围决定配额是否应用于BestEffortQoS等级或其他两种等级(Burstable、Guaranteed)的pod。
Terminating和NotTerminating名称可能有一些歧义,实际并不是应用于处于(或不处于)停止状态的pod。我们尚未讨论过这个问题,但你可以为每一个pod指定被标记为Failed,然后真正停止之前还有一段时间。这个是在 pod.spec 中配置 activeDeadlineSeconds来实现的。该属性定义了一个pod从开始尝试停止的时间到被标记为Failed然后真正停止之前,允许其在节点上继续运行的秒数。Terminating配额作用范围应用于这些配置了activeDeadlineSeconds的pod。而NotTerminating应用于那些没有该配置的pod。
配额范围也决定了配额可以限制的内容,BestEffort只能限制pod的个数,其他三种除了个数外,还可以限制CPU、内存的requests和limits。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: bestefort-notterminating-pod
spec:
  scopes:
  - BestEffort        // 该quota 只会应用于QoS等级为BestEffort及
  - NotTerminating    // 没有设置有效期的pod
  hard:
    pods: 4    

注意:在进入下一个部分,先删除所有创建的ResourceQuota和LimitsRange。接下来不会用到该资源,而且这些资源会影响下面的例子

六、监控pod的资源使用量

设置合理的资源requests和limits对充分利用Kubernetes集群资源来说十分重要。如果requests设置的太高,洁群节点利用率就会比较低。如果设置的的太低,应用就会处于饥饿状态,甚至很容器引起OOMKiller杀死。如何才能找到requests和limits的最佳配置呢?
可以通过对容器在期望负载下的资源实际使用率进行监控来找到这个最佳配置。当然一旦应用暴露于公网,都应该保持监控,且在需要的时候对其资源的requests和limits进行调节。

收集、获取实际资源使用情况
如何监控一个在kubernetes中运行的应用?kubelet自身就包含了一个名为cAdvisor的agent,它会收集整个节点和节点上运行的所有单独容器的资源消耗情况。集中统计整个集群的监控信息需要运行一个叫做Heapster的附加组件。
Heapster以pod的方式运行在某个节点上,它通过普通的kubernetes service暴露服务。使外部可以通过一固定的IP地址访问。它从集群中所有的cAdvisor收集数据,然后通过一个单独的地址暴露。
pod(或者pod中运行的容器)感知不到cAdvisor 的存在,cAdvisor也感知不到Heapster的存在。Heapster主动请求所有cAdvisor,同时cAdvisor无须通过pod容器内进程通信就可以收集到容器和节点的资源使用数据。

启用Heapster
如果运行在 Google Container Engine 上,则Heapster默认开启
如果是 MiniKube,它可以作为插件使用 “minikube addons enable heapster” 命令开启
如果是其他类型的kubernetes集群中手动运行Heapster,可以参考 https://github.com/kubernetes/heapster 中的介绍

启动Heapster后,需要等待几分钟时间收集足够的指标,才能看到集群资源的使用统计。

显示集群节点的CPU和内存使用量
在集群中运行Heapster可以通过kubectl top命令获得节点和单个pod的资源用量。
查看节点使用了多少CPU和内存: kubectl top node
它显示了节点上运行所有pod当前的CPU和内存的实际使用量,与kubectl describe node 不同的是,后者仅仅显示节点CPU和内存的requests和limits,而不是实际运行时的数据。

显示单独pod的CPU和内存使用量
可通过kubectl top pod查看单独pod的CPU和内存的使用量
需要注意的是,有时候该命令会报以下的错,此时不要急于去排查,等待一会(可能要几分钟)再执行,因为kubectl top命令是从Heapster获取指标,它将几分钟的数据汇总起来,所以不会立即暴露
“error:Metrics not available for pod default/kubiaxxxxx, age 1h20m10.12324s”
如果要查看容器而不是pod,可以使用 --container选项

保存并分析历史资源的使用统计信息
top命令仅展示了当前资源的使用量,它并不会显示过往一段时间到现在pod的CPU和内存使用量。实时上 cAdvisor和Heapster只会保存一个很短时间窗的资源使用量数据。如果需要分析一段时间的pod的资源使用情况,就需要借助额外的工具了。一般使用InfluxDB来存储统计数据,使用Grafana对数据进行可视化分析。

InfluxDB和Grafana介绍
InfluxDB是一个用于存储应用指标,以及其他监控数据的开源的时序数据库。Grafana是一个拥有华丽的web控制台的数据分析和可视化套件,同样也是开源的,它允许用户对InfluxDB中存储的数据进行可视化,同时发现应用程序的资源使用行为是如何随时间变化的。
(数据分析,这一块其实有很多好的工具不断涌现)

(本文章是学习《kubernetes in action》 一书时做的笔记,由于本人是刚学习k8s,且自学方式就是把它敲一遍,然后加一些自己的理解。所以会发现很多内容是跟书中内容一模一样,如果本文是对本书的侵权,敬请谅解,告知后会删除。如果引用或转载,请注明出处——谢谢。这是一本很好的书,极力推荐)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值