Node隔离与恢复
- cat unschedule_node.yaml
apiVersion:
kind: Node
metadata:
name: k8s-node-1
labels:
kubernetes.io/hostname: k8s-node-1
sepc:
unschedulable: true
- kubectl replace -f unschedule_node.yaml
- kubectl patch node k8s-node-a -p '{"spec":{"unschedulable":"true"}'
- kubectl cordon k8s-node-1(对节点进行隔离)
- kubectl uncordon k8s-node-1(对节点进行恢复)
Node的扩容
在新节点上安装Docker、kubelet、kube-proxy服务,并修改kubelet和kube-proxy的启动参数将Master URL指定为当前集群的Master的地址,最后启动这些服务。
更新资源对象的Label
- kubectl lable pod redis-master-bobr role=backend
- kubectl get pods -Lrole
- kubectl label pod redis-master-bobr0 role-
- kubectl label pod redis-master-bobr0 role=master --overwrite(对标签进行修改的时候需要加上参数--overwrite)
Namespace:集群环境共享与隔离
在一个组织内部,不同的工作组可以在统一个Kubernetes集群中工作,Kubernetes通过命名空间和Context的设置来对不同的工作组进行区分,使得他们既可以共享同一个Kubernetes集群的服务,也能够互不干扰。
创建namespace
- cat namespace-development.yaml(创建namespace)
apiVersion: v1
kind: Namespace
metadata:
name: development
- cat namespace-production.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
- kubectl create -f namespace-development.yaml
- kubectl create -f namespace-production.yaml
- kubectl get namespace
定义Content(运行环境)
接下来需要为这两个工作组分别定义一个Content,即运行环境。这个运行环境将属于某个特定的命名空间。
通过kubectl config set-context命令定义Context,并将Context置于之前创建的命名空间中:
- kubectl config set-cluster kubernetes-cluster --server=https://192.168.1.128:8080
- kubectl config set-context ctx-dev --namespace=development --cluster=kubernetes-cluster --user=dev
- kubectl config set-context ctx-prod --namespace=production --cluster=kubernetes-cluster --user=prod
可使用kubectl config view命令查看已定义的Context
当然也可以通过编辑文件的方式来设置Context:
- cat Context-config.yaml
apiVersion: v1
clusters:
- clusters:
server: http://192.168.1.128:8080
name: kubernetes-cluster
contexts:
- context:
cluster: kubernetes-cluster
namespace: development
name: ctx-dev
- context:
cluster: kubernetes-cluster
namespace: production
name: ctx-prod
current-context: ctx-dev
kind: Config
preference: { }
users: [ ]
设置工作组在特定Context环境中工作
使用kubectl config use-context <context_name>命令来设置当前的运行环境。
- kubectl config use-context ctx-dev(把当前工作环境设置为ctx-dev,进行工作环境的切换)
Kubernetes资源管理
下面将从计算资源管理(Compute Resource)、资源配置范围管理(LimitRange)、服务质量管理(Qos)及资源配额管理(ResourceQuota)等方面,对Kubernetes集群内的资源管理进行详细说明。
计算资源管理(Compute Resources)
- 资源请求(Resource Request)可完全保证的资源量,Request的值会提供给Kubernetes Scheduler便于优化基于资源请求的容器调度;
- 资源限制(Resource Limits)最多能使用到的资源上限,这个上限值会影响发生资源竞争时的解决策略;
- CPU(Cores)(0.1CPU=100m)单独说一下spec.container[].resources.limits.cpu到配置在docker中的实际运行情况:首先会将配置的CPU的值转换成millicore(比如配置的是1,转换成1000,配置的100m转换成100),将此配置的值乘以100000,除以1000,然后再讲结果作为--cpu-quota参数的值传递给docker run命令,docker run命令中另外一个参数是--cpu-period默认值是100000,表示
- Docker重新计量和分配CPU的使用时间间隔100000微妙(100毫秒)。Docker的--cpu-quota参数和--cpu-period参数一起配合完成对容器CPU的使用限制。比如Kubernetes中配置容器的CPU Limits为0.1,那么计算后的--cpu-quota为10000,而--cpu-period为100000,这以为着Docker在100毫秒内最多给该容器分配10毫秒的*core的计算资源用量。其结果与Kubernetes配置的意义是一致的。
- Memory(Bytes)(KiB与MiB是二进制表示的字节单位,常见的KB与MB是十进制表示的字节单位:1KB=1000bytes=8000bits、1KiB=2^10bytes=1024byte=8192bits
- )
- 区别于API资源(API Resources,如Pod和Service等)
尽管Requests和Limits只能设置到容器上,但是设置Pod级别的Reuests和Limits能极大程度上提高我们队Pod管理的便利性和灵活性,因此Kubernetes中提供对Pod级别的Requests和Limits配置。对于CPU和内存而言,Pod的Reusets或Limits是指该Pod中所有容器的Requests或Limits的总和(Pod中没设置Request或Limits的容器,该项的值为0或者按照集群配置的默认值来计算)
计算资源使用情况监控
Pod的资源用量会作为Pod的状态信息一同上报给Master。如果集群中配置了Heapster来监控集群的性能数据,那么还可以从Heapster中查看Pod的资源用量信息。
计算资源相关常见问题分析
- kubectl describe pod frontend | grep -A 3 Events(查看调度失败的原因)
- 若由于资源问题造成的调度失败,则可采用以下几个方案进行解决:
- 添加更多的节点到集群中;
- 停止一些不必要运行中的Pod,释放资源;
- 检查Pod资源的配置有无错误;
- 若由于资源问题造成的调度失败,则可采用以下几个方案进行解决:
- kubectl describe nodes k8s-node-1
- kubectl get pod -o(读取已经终止容器之前的状态信息)
计算资源管理的演进
资源的配置管理范围
对集群内Request和Limits的配置做一个全局的统一的限制:
- 集群中每个节点2GB内存,禁止Pod申请超过2GB内存;
- 为不同的命名空间设置不同的限制来满足要求;
- 集群中每个Pod必须至少使用集群平均资源的值(CPU和内存)的20%。这样集群能够提供更好的资源一致性的调度,从而减少资源的浪费;
- kubectl create namespace limit-example
- cat limits.yaml
apiVersion: V1
kind: LimitRange
metadata:
name: mylimits
spec:
limits:
- max:
cpu: "4"
memory: 2Gi
min:
cpu: 20m
memory: 6Mi
maxLimitRequestRatio:
cpu: 3
memory: 2
type: Pod
- - defaultLimits:
cpu: 300m
memory: 200Mi
defaultRequest:
cpu: 200m
memory: 100Mi
max:
cpu: 2
memory:1Gi
min:
cpu: 100m
memory: 3Mi
maxLimitRequestsRatio:
cpu: 5
memory: 4
type: Container
- kubectl create -f limits.yaml --namespace=limit-example
- kubectl describe limits mylimits --namespace=limit-example
- 不论CPU还是内存,在LimitRange中,Pod和Container都可以设置Min、Max和Max Limit/Request Ratio这三种参数。Container还可以设置Default Request和Default Limit这两种参数,而Pod不能设置Default Request和Default Limit。
- 对Pod和Container的五种参数的解释如下:
- Container的Min是Pod中所由容器的Requests值的下限;Container的Max是Pod中所有容器Limits值的上限;Container的Default Request是Pod中所有未指定Requests值的容器的默认Request;Container的Default Limit是Pod中所有未指定Limits值的容器的默认Limits值。对于同一资源类型Min<=Default Request<=Default Limit<=Max;
- Pod的Min是Pod中所有容器的Requests值的总和的下限;Pod的Max是Pod中所有容器的Limits值的总和的上限。当容器未指定Request值或者Limits,将使用容器的Default Request值或者Default Limit值;
- Container的Max Limit/Request Ratio限制了Pod中所有容器的Limits值与Request值的比例上限;而Pod的Max Limit/Request Ratio限制了Pod中所有容器的Limits值总和与Request值总和的比例上限;
- 如果设置了Container的Max,那么对于该类资源而言,整个集群中的所有容器都必须设置Limits,否则将无法成功创建。Pod中的容器未配置Limits时,将使用Default Limit的值,而如果Default也未配置则无法成功创建;
- 如果设置了Container的Min,那么对于该类资源而言,整个集群中的所有容器都必须设置Requests。如果创建容器时未配置该类资源的Requests,那么创建过程会报验证错误。Pod里的容器的Request在未配置时,可以使用DefaultRequest;而如果又没配置DefaultRequest,那么会默认等同于该容器的Limits;如果此时Limits也未定义,那么就会报错;
- 对于任意一个Pod而言,该Pod中所有容器的Request总和必须大于或等于6Mi,而且所有容器的总和必须小于或等于1Gi;同样所有容器的CPU Request总和必须大于或等于200m,而且所有容器的Limits总和必须小于或等于2;
- Pod里任何容器的Limits与Requests的比例不能超过Container的Max Limit/Requests Ratio;Pod里所有的Limits总和与Request的总和的比例不能超过Pod的Max Limit/Request Ratio;
需要注意的是,CPU Limits强制配置这个选项在Kubernetes集群中默认是开启的,除非集群管理员在部署kubelet时,通过设置参数--cpu-cfs-quota=false来关闭该限制;
- kubelet --cpu-cfs-quota=false
资源的服务质量管理(Resource QoS)
- 可压缩资源(CPU)
- Kubernetes目前支持的可压缩资源是CPU
- 由于目前Kubernetes和Docker的CPU隔离机制都是在容器级别隔离,所以Pod级别的资源配置并不能完全得到保障;(后续版本有无对cgroups的开发实现对Pod级别的资源精确控制)
- 空闲CPU资源按照容器Request值的比例进行分配;
- 如果Pod CPU使用量超过Limits中的值,那么cgroup会对CPU使用进行限流;如果Pod没有配置Limits值,那么Pod会尝试抢占所有空闲的CPU资源(因此默认情况下必须配置Limits)
- 不可压缩资源(内存)
- 如果Pod内存的使用量小于它的Request值,那么这个Pod是可以正常运行的(除非出现操作系统级别的内存不足等严重的问题);如果Pod的内存使用量超过了它的Request值,那么这个Pod有可能会被Kubernetes干掉;比如Pod A使用了超过Request的值而不到Limits的内存量,此时同一个机器上另外一个Pod B向系统申请的总量不超过自己的Request值的内存,那么Kubernetes可能会直接干掉Pod A;如果Pod使用的内存量超过了它的Limits设置,那么操作系统内核会杀掉Pod所有容器的所有进程中使用内存最多的一个,知道内存不超过Limits为止;
- 对调度策略的影响
服务质量等级(QoS Classes)
在一个超用(Over Committed)系统中存在三个QoS等级:
- Guaranteed:Limits值和Request值全部相等;
- Best-Effort:Pod中所有容器都未定义资源配置;
- Burstable:既不是Guaranteed或者Best-Effort;
Kubernetes QoS的工作特点
Pod的CPU Request无法得到满足(比如节点的系统级任务占用较多的CPU导致无法分配给足够的CPU给容器使用)时,容器得到的CPU会被压缩限流;
内存由于是不可压缩资源,所以针对内存资源紧张的情况会按以下逻辑处理:
- Best-Effort Pod
- Burstable Pod
- Guaranteed
OOM计分系统
OOM(Out Of Memory)计分规则包括如下内容:
- OOM计分是进程消耗内存在系统中占的百分比中不含百分号的数字乘以十的结果,这个结果是进程OOM基础分;将进程OOM基础分的分值再加上这进程的OOM分数调整值OOM_SCORE_ADJ的值作为进程OOM最终分值(除root启动的进程外)。在系统发生OOM时,OOM Killer会优先杀掉OOM计分更高的进程;
- 进程的OOM计分的基本分数值的范围0~1000,如果A进程的调整值OOM_SCORE_ADJ减去B进程的调整值结果大于1000,那么A进程的OOM计分最终值必然大于B进程,A进程会比B进程优先被杀死;
- 不论调整值OOM_SCORE_ADJ为多少,任何进程的最终分值范围也是1000;
- Best-Effort Pod设置OOM_SCORE_ADJ调整值为1000,因此Best-Effort Pod中的容器里面的进程OOM最终分值肯定是1000;
- Guaranteed Pod设置OOM_SCORE_ADJ调整值为-998,因此Guaranteed Pod中的容器里面的进程的OOM最终分一般为0或1;
- Burstable Pod规则分情况说明:如果Burstable Pod的内存Requests超过了系统可用内存的99.8%,那么这个Pod的OOM_SCORE_ADJ调整值固定为2;否则OOM_SCORE_ADJ调整值为1000~10(内存Request占系统可用内存的百分比的无百分号的数字部分的值),而如果内存Request为0,那么OOM_SCORE_ADJ调整值固定为999。如果一个Burstable Pod内部有多个进程的多个容器发生内存竞争冲突时,那么此时的OOM评分只能作为参考,不能保证完全按照资源配置的定义来执行OOM Kill;
OOM还有一个特殊的计分规则:
- kubelet进程和Docker进程的调整值OOM_SCORE_ADJ为-998;
- 如果配置进程调整值OOM_SCORE_ADJ为-999,那么这类进程不会被OOM Kill杀掉;
QoS的演进
更丰富的QoS策略
资源的配额管理
- Master中开启资源配额选型
- 配额的作用域(Quota Scopes)
- 在资源配额(ResourceQuota)中设置Request和Limits
- 资源配额定义(ResourceQuota)
例子:
- kubectl create namespace myspace
- cat compute-resource.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
pods: "4"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
- kubectl create -f compute-resources.yaml --namespace=myspace
- cat object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
configmap: "10"
persistentvolumeclaims: "4"
replicationcontrollers: "20"
secrets: "10"
services.loadbalancers: "2"
- kubectl create -f object-counts.yaml
- kubectl describe quota compute-resroutces --namespace=myspace
- kubectl describe quota object-counts --namespace=myspace
资源配额与集群资源总量的关系
资源配额与集群资源总量是完全独立的。资源配额是通过绝对的单位来配置的;意味着集群中节点的添加并不会自动更新资源配额,而资源所对应的命名空间下对象也不能自动的增加资源上限。
我们希望资源配额可以支持更复杂的策略:
- 对于不同的租户,按照比例划分集群的资源;
- 允许每个租户都能按照需要来提高资源用量,但是有一个较宽裕的限制,以防止意外的资源耗尽的情况发生;
- 探测某个命名空间的需求,添加物理节点并扩大资源配额值;
这些策略可以通过将资源配额作为一个控制模块,手动编写一个控制器(controller)来监控资源使用情况,并调整命名空间上的资源配额方式来实现。
资源配额将整个集群中的资源总量做一个静态的划分,但它并没有对集群中的节点(Node)做任何限制,不同命名空间的Pod仍然可以运行在同一个节点之上;
(未完待续)——