kubernetes(5) Pod资源管理
Pod的基础概念k8s通过pod的方式去运行容器,pod是容器的外壳,为容器的抽象封装。一个pod内部可以存在一个或多个容器,这些容器将共享网络名称空间。pod在默认情况下,存在基础架构容器:pause。它创建出来后,一直处于暂停状态。它会为加入到pod内的主要容器,提供网络名称空间和存储卷的定义等功能。实际上,pod内的pid,mount,user等名称空间都可以共享。在pod内,也能多个容器共
Pod的基础概念
k8s通过pod的方式去运行容器,pod是容器的外壳,为容器的抽象封装。一个pod内部可以存在一个或多个容器,这些容器将共享网络名称空间。
pod在默认情况下,存在基础架构容器:pause。它创建出来后,一直处于暂停状态。它会为加入到pod内的主要容器,提供网络名称空间和存储卷的定义等功能。实际上,pod内的pid,mount,user等名称空间都可以共享。
在pod内,也能多个容器共享其他名称空间。而mount名称空间很难实现,一般是pause做存储卷,其他容器共享挂在底层pause存储卷。如此组织多个容器的方式,特别像在一个内核之间,运行多个进程。进程间通过lo进行通信。
这很像vm的逻辑,因此pause在某种程度来说,更像把被散割的容器重新成虚拟机的运行逻辑。主要原因在于,容器间可能需要以非常紧密的方式组织起来工作时,这种逻辑非常有用。
当然除非万不得已,不建议pod跑多个容器,如同一个容器不应该跑多个进程。
很多时候,单一进程,很难完成额外的其他任务。比如容器1运行nginx,产生许多日志。如果收集这些日志,比如使用elk时,必须在目标主机部署日志收集代理filebeat或logstash或flumed等,并发送到统一存储检索中心。但一个容器只跑nginx,如何去收集这些日志?为了不违背容器的部署逻辑,将无法在此容器内在部署日志收集代理,因此,必须以紧密的方式在同一pod内跑第二个容器,用于辅助主容器完成此类的管理任务。
不过,不建议在pod内运行nmt这类型组织逻辑的应用。一个pod内一般只有一个主容器,其他辅助容器是为了帮助主容器完成管理任务的,这些辅助容器也称为边车 side car。
或者另外一种应用场景:容器提供了服务,在同一个pod再部署一个容器,所有用户请求到达主容器前,必须经过辅助容器,这个容器就是proxy。以后被访问的容器,都不直接接受客户端的请求,而是前端添加代理容器,再代理给主容器。这也是side car的使用方式。
而istio实现网格化,就是按照这种逻辑,在主容器添加代理容器,为主容器的访问添加非常强大的前端管理功能。前端代理存在监控平面,监控平面会监控每个代理的健康状态,流量状态,按需进行链路检测,流量调度等功能。
Pod发布到互联网环境
如果在机房构建nmt,使用的都是私有地址。访问路径为:n -> t - >m。此时如何将nginx公开给互联网使用?
如果是k8s集群,它存在三种类型的网络
- node network:与外部网络通信的接口;
- service network:IP地址仅出现iptables/ipvs规则,并不配置在任何一个接口,仅用于路由和调度;
- pod network:pod内部网络,相当于机房内的私有网络。每个pod都处于此网络中。因此pod之间无论跑到哪个节点,它们都可相互通信。但由于pod的动态逻辑,因此pod 的IP并不固定,因此借助于service地址通信。
因此,必须在pod前端,添加抽象层services,以固定访问端点。每个service创建后,会表现为所有节点的iptables/ipvs的规则,因此客户端访问 -> services 反代 -> pod。
此时m,n,t都有各自的services。
虽然mnt内部通信都需要service转发,会有性能影响。毕竟动态逻辑当中,必须有机制辅助实现服务注册和服务发现。而service就是这种机制,由coreDNS完成实现在services上实现辅助注册和服务发现。
DNS发展:skyDNS -> kubeDNS -> coreDNS 1.12+)
因此只要是服务性质的pod,不应该以创建自主式pod运行,而是pod控制器来创建pod。
Pod控制器
它是一类k8s标准资源,不同控制器完成不同的功能和任务,它是整个集群的最核心组成部分,是整个集群的大脑。控制器通过和解循环确保用户所定义的对象的当前应用在集群的状态,必须和用户期望状态吻合。如果不吻合则必须执行一定的代码让它们吻合。因此包括了发布,变更,故障处理等都由控制器完成。从某种意义上讲,控制器就是运维。这是一种理想状态,对于无状态应用而言却是已经是如此。
我们只要关注k8s集群自身的运行即可。
Pod network无法被集群之外的客户端访问的,如果公开给互联网的客户端访问,此时如何把集群外部的流量,必要时接入到集群内部以完成客户端访问?
可以使用Service:nodePort。可在集群每个节点上打开端口,访问集群节点的端口时会通过service映射到pod里面来。这种访问逻辑最通透,最直接;但任何节点上都需要生成规则,如果服务使用同一个端口都会导致端口冲突。因此端口是随机选取的,节点端口范围:3000~32767。
此时会有麻烦:nginx对外映射时,比如32001端口。客户端如何得知访问不是80而是32001?此时不得不在k8s之外的前端,人为建立负载均衡器比如haproxy,监听80端口。通过负载均衡器反代和负载均衡到每个节点映射的端口。必要时使用keepalived做高可用。因此需要k8s之外再加映射层:客户端请求 -> 外负载均衡器 -> 节点 -> service -> pod。访问路径较长,性能不是特别好,也不是按需创建,因为需要人为在负载均衡器添加配置。
对于按需服务上,存在一定缺陷。能否在k8s上按需创建?
目前通常把k8s部署于云计算环境中如openstack,aws,aliyun等,利用它们的LBaaS,使用软件实现的负载均衡器。当需要创建负载均衡规则时,会自动启动haproxy进程,并且建立规则生成负载均衡调度功能。
此时k8s上的service并且期望被外部访问时使用标准端口,可以通过触发软件的方式创建负载均衡器。当service删除时也会联动删除此负载负载器。当k8s部署的底层是完整的云计算环境,并支持按命令方式创建负载均衡器的服务时,才有用。
K8s控制器其中一个标准资源:cloud-controller-manager,它的功能就是通过与底层的外部公有云环境的API,交互的组件。用于实现在必要时,触发外围的IaaS云计算环境,完成非K8S自身完成的功能的实现。
注意:Service是ipvs/iptables生成的规则,属于四层功能,无法卸载会话。此时证书等都需要配置在pod,而ingress是七层调度,可以卸载会话。
管理pod时,会存在一种需求。由于pod是动态的,因此,通过service固定接入客户端请求,使用pod控制器管理pod。但service如何识别哪些pod是后端pod,控制器如何识别哪些pod是由此控制器控制?
K8s可划分不同的名称空间,同一类型的资源在同一个名称空间下不能同名。如果测试的nmt和生产的nmt,它们完全不能同名,此时需要精心组织它们的名字。因此,把它们放置在不同的名称空间,类似于目录是文件的名称空间。K8s把内部管理的大的空间,组织为名称空间。
有些资源是名称空间级别,有少数资源是集群级别。比如pv,node,namespace都是集群级别的资源。
因此K8s上,一切皆资源。而不同名称空间,pod可以同名。
标签和标签选择器
在pod的控制器管理下,pod是动态的。控制器如何得知哪些pod是自己管理的?依靠pod地址和名称都不合适,此时,它通过标签和标签选择器结合起来的组件来完成的。
K8s每类资源都有标签。Pod创建时,都可以附加标签。标签是pod的元数据kv类型的数据。它可附加用户需要的,自定义的元数据的kv信息,用于被引用资源的引用者作为过滤资源条件来使用。
此时,就存在这样的选择方式:
- 精确选择
- 范围选择:比如年龄18~20
- 组合逻辑关系选择
标签选择器也是类似逻辑。
标签就是“键值”类型的数据,它们可于资源创建时直接指定,也可随时按需添加于活动对象,而后即可由标签选择器进行匹配度检查从而完成资源挑选。
- 一个对象可拥有不止一个标签,而同一个标签也可被添加至多个资源之上
- 实践中,可以为资源附加多个不同纬度的标签以实现灵活的资源分组管理功能,例如版本标签、环境标签、分层架构标签等,用于交叉标识同一个资源所属的不同版本、环境及架构层级等
- 标签中的键名称通常由键前缀和键名组成,其中键前缀可选,其格式形如“KEY_PREFIX/KEY_NAME”
- 键名至多能使用63个字符,可使用字母、数字、连接号(-)、下划线()、点号(.)等字符,且只能以字母或数字开头
- 键前缀必须为DNS子域名格式,且不能超过253个字符。省略键前缀时,键将被视为用户的私有数据,不过由Kubernetes系统组件或第三方组件自动为用户资源添加的键必须使用键前缀,而“kubernetes.io/”前缀预留给kubernetes的核心组件使用
- 标签中的键值必须不能多于63个字符,它要么为空,要么是以字母或数字开头及结尾,且中间仅使用了字母、数字、连接号(-)、下划线(_)或点号(.)等字符的数据
标签选择器用于表达标签的查询条件或选择标准,Kubernetes API目前支持两个选择器:
- 基于等值关系(equality-based)
- 操作符有=、==和!=三种,其中前两个意义相同,都表示“等值”关系,最后一个表示“不
等”关系
- 操作符有=、==和!=三种,其中前两个意义相同,都表示“等值”关系,最后一个表示“不
- 基于集合关系(set-based)
- KEY in (VALUE1,VALUE2,…)
- KEY not in (VALUE1,VALUE2,…)
- KEY:所有存在此键名标签的资源;
- !KEY:所有不存在此键名标签的资源。
使用标签选择器时还将遵循以下逻辑:
- 同时指定的多个选择器之间的逻辑关系为“与”操作;
- 使用空值的标签选择器意味着每个资源对象都将被选中;
- 空的标签选择器将无法选出任何资源。
定义标签选择器的方式
kubernetes的诸多资源对象必须以标签选择器的方式关联到Pod资源对象,例如Service、Deployment和ReplicaSet类型的资源等,它们在spec字段中嵌套使用嵌套的“selector”字段,通过“matchLabels”来指定标签选择器,有的甚至还支持使用“matchExpressions”构造复杂的标签选择机制。
- matchLabels:通过直接给定键值对指定标签选择器;
- matchExpressions:基于表达式指定的标签选择器列表,每个选择器形如“{key: KEY_NAME, operator: OPERATOR, values: [VALUE1,VALUE2,…]}”,选择器列表间为“逻辑与”关系;
- 使用In或NotIn操作符时,其values非必须为非空的字符串列表,而使用Exists或DostNotExist时,其values必须为空。
查看标签:
- app=myapp
- pod-template-hash:模板标签的hash值
定义标签:在metadata 在元数据处定义即可,labels映射类型,不是数组
metadata:
name: app-demo
namespace: prod
labels:
app: app-demo
version: v0.1.0
ilinux@master:~/manifests/basic$ kubectl get pods -n prod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
app-demo 2/2 Running 3 3h21m app=app-demo,version=v0.1.0
kubectl label 专用于管理标签:
ilinux@master:~/manifests/basic$ kubectl label pods app-demo -n prod tier=frontend
pod/app-demo labeled
ilinux@master:~/manifests/basic$ kubectl label pods app-demo -n prod --overwrite app=myapp
pod/app-demo labeled
ilinux@master:~/manifests/basic$ kubectl get pods -n prod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
app-demo 2/2 Running 3 3h34m app=myapp,tier=frontend,version=v0.1.0
定标签选择器去显示对应的标签的pod:
- -L --label-columns 仅显示对应资源指定的标签
- -l --selector= 基于等值选择器的标签选择器
# 仅显示拥有此标签的app
ilinux@master:~$ kubectl get pods --show-labels -l app=myapp
NAME READY STATUS RESTARTS AGE LABELS
myapp-5d587c4d45-8xzvt 1/1 Running 2 40h app=myapp,pod-template-hash=5d587c4d45
myapp-5d587c4d45-hkrtp 1/1 Running 2 40h app=myapp,pod-template-hash=5d587c4d45
myapp-5d587c4d45-pn858 1/1 Running 2 40h app=myapp,pod-template-hash=5d587c4d45
# 无app,或有app但值非myapp
ilinux@master:~$ kubectl get pods --show-labels -l app!=myapp
NAME READY STATUS RESTARTS AGE LABELS
nginx-dep-6fcd89c765-lqzl9 1/1 Running 2 40h app=nginx-dep,pod-template-hash=6fcd89c765
# 显示app=myapp或app=nginx-dep
ilinux@master:~$ kubectl get pods --show-labels -l "app in (myapp,nginx-dep)"
NAME READY STATUS RESTARTS AGE LABELS
myapp-5d587c4d45-8xzvt 1/1 Running 2 40h app=myapp,pod-template-hash=5d587c4d45
myapp-5d587c4d45-hkrtp 1/1 Running 2 40h app=myapp,pod-template-hash=5d587c4d45
myapp-5d587c4d45-pn858 1/1 Running 2 40h app=myapp,pod-template-hash=5d587c4d45
nginx-dep-6fcd89c765-lqzl9 1/1 Running 2 40h app=nginx-dep,pod-template-hash=6fcd89c765
# 有这个app即可
ilinux@master:~$ kubectl get pods --show-labels -l app
NAME READY STATUS RESTARTS AGE LABELS
myapp-5d587c4d45-8xzvt 1/1 Running 2 40h app=myapp,pod-template-hash=5d587c4d45
myapp-5d587c4d45-hkrtp 1/1 Running 2 40h app=myapp,pod-template-hash=5d587c4d45
myapp-5d587c4d45-pn858 1/1 Running 2 40h app=myapp,pod-template-hash=5d587c4d45
nginx-dep-6fcd89c765-lqzl9 1/1 Running 2 40h app=nginx-dep,pod-template-hash=6fcd89c765
# 使用强引用,因为!对于shell有特殊意义,因此必须逃逸
ilinux@master:~$ kubectl get pods --show-labels -l '!app'
No resources found in default namespace.
一般在上级资源中的资源清单中来表达标签选择器。
资源注解:annotaion
如果希望key长度更长,仅用于保存对应对象的元数据据,而不是用于标签选择器去选择,此时需要另外一个资源属性:资源注解。它也是kv型数据,但不能用于标签表选择器,仅用于为用户提供自定义资源元数据据的接口
注解也是“键值”类型的数据,不过它不能用于标签及挑选kubernetes对象,仅用于为资源提供“元数据”信息
- 注解中的元数据不受字符数量的限制,它可大可小,可以为结构化或非结构化形式,也支持使用在标签中禁止使用的其他字符
- 在kubernetes的新版本中(Alpha或Beta阶段)为某资源引入新字段时,常以注解方式提供以避免其增删等变动给用户带去困扰,一旦确定支持使用它们,这些新增字段再引入到资源中并淘汰相关的注解
- 唯一的限制:注解不能被标签选择器所选择
后期的很多对pod或其他资源的管理软件,通过注解来识别和配置资源。因此它是非常重要的东西。
kubectl annotate 管理命令,它也是属于元数据,因此也必须定义在metadata的内嵌字段中
apiVersion: v1
kind: Pod
metadata:
annotations:
ik8s.io/project: hello
name: app-demo
namespace: prod
labels:
app: app-demo
version: v0.1.0
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
- name: bbox
image: busybox:latest
command: ["/bin/sh","-c","sleep 3600"]
ports:
- protocol: TCP
containerPort: 80
name: http
hostPort: 8080
ilinux@master:~/manifests/basic$ kubectl describe pods/app-demo -n prod
Name: app-demo
Namespace: prod
Priority: 0
Node: node2/192.168.2.12
Start Time: Tue, 18 Aug 2020 13:56:10 +0800
Labels: app=app-demo
tier=frontend
version=v0.1.0
Annotations: ik8s.io/project: hello # 资源注解
声明式配置,apply的工作逻辑
第一次apply时,会把apply命令和内容保存在注解中,如果第二次apply时,对比二者,如果内容改变了,就仅把内容的补丁apply上去了。
此时,annotion指向了apply的补丁内容。对比完毕后,使用diff命令,生成补丁然后补充上去。因此apply命令能执行多次。
这就是annotaion一种典型应用。
Pod生命周期
Pod从创建到退出结束,终止到删除经历的阶段:
pod创建 -> 初始容器init container -> 主容器运行 -》> 容器刚创建完成post start hook -> Liveress probee -> Rediness probe -> 容器即将结束之前:pre stop hook
-
第一阶段:init container
启动主容器之前,可能需要做环境初始化。比如运行nginx主容器启动之前,可先启动一个初始化容器以创建目录,或者从github上pull文件,此时完成初始化使命,它可以退出了。
而初始化容器也可能存在多个,比如第一个条件使用第一个容器完成,第二个条件使用第二个容器完成。因此必须所有初始化容器完成后,主容器才能启动。而多个初始容器必须依次,串行启动结束后,才能启动主容器。
而主容器和sidecar是可以同时运行的,注意二者区别。
-
第二阶段:运行主容器节点。它又分为三个阶段
-
启动之后节点:post start hook 钩子,用户可自定义操作。容器刚刚启动完成后,立即执行命令用于设置
-
主容器运行阶段
-
结束之前阶段:结束之前的设置
-
容器的骨架依靠docker进程支撑,即使容器进程没有停止,容器不一定是健康的,因此需healthcheck,pod也是如此。Pod内的容器依然是running,但无法接收请求,因此需要做健康状态检测。
-
Liverness probe:存活状态探测,标准条件取决于自定义的命令,正常返回则健康,否则不健康。
它是周期性检测的,一旦不健康则重启容器。Pod无需重启。若容器重启失败,则立即重启;再次失败,则使用逐渐递增的时间间隔重启,比如5 10 20 5分钟 5分钟…
-
Readiness probe:就绪状态探测
比如运行java程序,可能需要经过一段时间才能准备好,因此不是pod一旦running就可接入请求,而是需要做就绪状态检测:向服务发请求,直到响应后才接入请求。
它跟service结合特别有用,service是根据就绪状态检测的结果,来评判是否作为后端。默认情况下,没有定义此检测时,只要pod runing就默认为允许。
因此,生产环境必须定义此两项的检测。
它们的配置语法格式是一样的,但功能和触发位置有所不同。
参考:
https://github.com/iKubernetes/Kubernetes_Advanced_Practical
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: ikubernetes/myapp:v1
lifecycle:
postStart:
exec:
command: ["/bin/sh","-c","echo $(hostname) | lifecycle hooks handler > /usr/share/nginx/html/test.html"]
二者都支持三种方法:
- exec:执行自定义命令
- httpGet:发送http请求
- tcpSocket:发请求到host Port
liveness Probe和readiness Probe
二者探测的命令格式是相似的,类似post start和pre stop
-
Liveness Probe
-
exec
命令一定是容器内包含的命令,可以向容器内的服务发请求或者探测容器是否存在某文件来判断容器健康与否。比如netstat查看80监听与否等手段
-
httpGet
发http请求
-
tcpSocket
发tcp 的请求等判断是否健康
-
一般使用其中一种即可
如果第一次探测失败,如果立刻认为失败将过于武断,因此可多加判断,使用字段:
failureThreshold int:失败几次才认为真正失败,错误阈值。它默认为3,min为1。
successThreshold int:连续成功多少次才认为真成功,默认为1,而且只能是1。
periodSeconds:检测周期,检测的时间间隔,默认为10s,min为1s
InitdelaySecounds:延迟多久才检查,如果不定义则一旦启动就检测
timeoutSeconds:一旦请求没响应,则多久超时。默认为1s
就绪状态检测:配置格式和健康状态检测很相像的。一旦未就绪,则不会重启。它没有权利去重启程序。这是二者的重要区别之一。一旦成功,则会添加到service后端中去。一旦未就绪,则从service后端移除,无论pod运行状态与否。
因此它也是周期性工作。
Pod对象的相位
Pod对象总是应该处于其生命进程中以下几个相位(phase)之一
-
Peding:API Server创建了Pod资源对象并已存入etcd中,,但它尚未被调度完成,或仍处于从仓库中下载镜像的过程中。大多数都是未调度成功,资源未能满足目标调度的需求
-
Running:Pod已经被调度到某节点,并且所有容器都已经被kubelet创建完成
-
Succeeded:Pod中的所有容器都已经成功终止并不会被重启
-
Filed:所有哦让其都已经终止,但至少又一个哦让其终止失败,既容器返回了非0值的对出状态或i已经被系统终止
-
Unkonew:API Sever无法正常获取到pod对象的状态信息,通常是由于其无法与所在工作节点的kubelet通信所致
Pod对象的创建过程
- 客户端创建create Pod请求,提交给API Server
- API Server将用户没有指定字段,使用默认字段的默认值补全(准入控制)
- API Server write etcd 存储用户请求。此时资源变动了,watch给调度器
- Scheduler watch到资源变动,则调度器bind Pod:从众多节点中选择最佳的,把结果回馈给api server,api server把结果存储到etcd中,把调度的目标主机值填充并保存
- Watch事件通知对应主机的kubelet,然后kubelet得知需要运行pod任务
- Kubelet通过api server把存储在etcd的所有属性获取过来,然后调用docker引擎来创建容器
- docker的所有容器创建完成,回馈给kubelet。然后kubelet更新结果update pod status把更新结果信息提交给api server
- Api sever把实际状态保存在etcd中,填入到status状态中去
- 然后api sever告诉kubelet保存成功
容器的重启策略
- Always:pod对象终止就重启,默认设定
- OnFailure:尽在pod对象出现错误时方才重启,比如某些备份任务的pod执行任务完毕后会退出。此时就不应该重启
- Never:永不重启
Pod的终止过程
- 客户端把delete pod 提交给api sever
- Api server记录到etcd中,然后设置宽限期 set grace period给pod,然后把结果返回给api server
- api server 标记pod为termianite,通知给kubelet
- Kubelet把send term signal 给docker 引擎
- Docker引擎尝试终止容器,并且run preStop hook
- API server watch pod mark as terminiting,然后通知给endpoint controller,把此pod从service 的endpoint移除pod。(实际上service到endpoint,由端点控制器关联到pod)
- pod移除成功
- 若pod移除不成功,如果超过宽限期,则send sigkill给docker强行终止信号,立即删除pod,把结果反馈给api server
- Api server把pod的信息从etcd中清除
Pod和容器的安全上下文
kubectl explain pod.spec.securityContext
Pod是否可以以管理员身份运行?如果可以,则对Pod具有完全控制权限,为容器的管理员。还能设置映射为节点的管理员,此时容器为特权容器。
如此提权可以威胁其他pod。因此不应该以节点管理员以特权方式运行Pod。
禁止所有的pod都无法提权,则通过安全上下文定义:
FsGroup
RunAsGroup…
在容器级别,也存在securityContext。它和Pod级别的安全上下文的区别是:
Pod级别的安全上下文设定,会对所有容器生效。而单个容器的安全上下文,只对单个容器生效,比如allowPrivilgesEscalation:必要时升级为特权容器
Privileged:是否设定为容器特权
…
Capabilities:功能,能力。定义当前容器能够允许执行或必须放弃的内核能力
Linux用户只有超级管理员和普通用户的角色,非常粗糙。后来为了实现更加精细化的权限控制,Linux在内核级别提供capabilities能力,把管理操作定义为能力。把能力赋予给用户,用户就拥有这一类的管理能力。
比如让用户以管理员身份运行,但不允许执行某些能力则可以drop 某些能力。
# Capabilities:容器能够执行容器内的哪些管理权限:add/drop
ilinux@master:~$ kubectl explain pod.spec.containers.securityContext.capabilities.add
KIND: Pod
VERSION: v1
FIELD: add <[]string>
DESCRIPTION:
Added capabilities
因此,Pod的安全上下文分为两个级别:
- Pod.spec.securityContext
- Pod.spec.containers.[].securityContext
Pod的资源需求与资源限制
如果集群资源紧张,某些pod运行的进程很重要,某些pod运行可有也可无,此时可以为pod设定优先级:pod.spec.priorityClassName
可以在集群级别定义优先级,然后设定pod属于哪些优先级,此时会根据优先级来优先调度。
pod.spec.containers.resources:定义使用的操作系统资源,包括:
- CPU资源
- 内存资源
pod运行容器时,如果没有定义资源范围。如果必要时,它可以抢占计算节点的所有资源。因此生产环境一定要为pod指定资源范围。
它可以指定下限和上限的范围:requests 和 limits,意思为 有下限的资源可以跑,但最多只能使用上限个资源。
容器的计算资源配额
- CPU属于可压缩(compressible)型资源,即资源额度可按需收缩,而内存(当前)则是不可压缩型资源,对其执行收缩操作可能会导致某种程度的问题
- CPU资源的计量方式
- 一个核心相当于1000个微核心,即1=1000m,0.5=500m
- 内存资源的计量方式
- 默认单位为字节,也可以使用E、P、T、G、M和K后缀单位,或Ei、Pi、Ti、Gi、Mi和Ki形式的单位后缀
- 内存也是有下限和上限,属于不可压缩资源。比如下限是1G,上限是3G。进程运行了3G,此时如果再索取内存资源,就会被OOM。因为整个内存都被耗尽了。因为内存是不可压缩资源,一旦不满足,就会内存资源耗尽,会OOM。而CPU不会,如果cpu抢占不到就等待着,cpu属于可压缩资源。
生产环境必须设定这两项配置:设置小了会有问题,设置大了也会影响。
Pod的服务质量类别
根据Pod对象的requests和limits属性,Kubernetes把Pod对象归类到BestEffort、Burstable和Guaranteed三个服务质量类别(Quality of Service,QoS)类别下
- Guaranteed:每个容器都为CPU资源设置了具有相同值的requests和limits属性,以及每个容器都为内存资源设置了具有相同值的requests和limits属性的pod资源会自动归属此类别,这类pod资源具有最高优先级
- Burstable:至少有一个容器设置了CPU或内存资源的requests属性,但不满足Guaranteed类别要求的pod资源自动归属此类别,它们具有中等优先级
- BestEffort:未为任何一个容器设置requests或limits属性的pod资源自动归属此类别,它们的优先级为最低级别
更多推荐
所有评论(0)