1 2 3 4 5 6 7 作者:李晓辉 联系方式: 1. 微信:Lxh_Chat 2. 邮箱:939958092@qq.com
让用户自己在 Kubernetes 上创建工作负载确实能提高效率。不过呢,集群的资源是有限的,像 CPU、内存和存储这些。如果工作负载太多,超出了集群能提供的资源,那工作负载可能就运行不正常了。好在 Kubernetes 有个厉害的功能,工作负载可以提前预留资源,还能声明资源的上限。这样就能避免资源被过度占用,保证工作负载都能正常运行,工作负载可以指定下列属性:
资源限值
第一招叫“资源限值”,就是给工作负载设个“天花板”,规定它在正常运行时最多能用多少资源。要是工作负载突然出故障或者负载突然变高,这个限值就能防止它把资源全占了,影响到别的工作负载正常运行。
资源请求
第二招是“资源请求”,工作负载可以提前说一声自己最少需要多少资源。Kubernetes 就会按照这些请求去分配资源,要是集群里资源不够,新的工作负载就暂时不能部署。这样一来,就能保证每个工作负载都能拿到自己需要的资源,安稳运行。
pod上的资源配额 说到创建工作负载,可以给每个 Pod 设置资源配额。就像给 Pod 划个“资源小房间”,让它在里面“住”得刚刚好。
比如说,一个 Pod 既设置了 request(请求配额),又设置了 limits(资源限制)。这就好比给 Pod 定了个“最低生活保障”和“最高消费限额”。
至于单位嘛,内存单位挺有意思的:1Mi 等于 1024KB,这是按二进制来的;1M 等于 1000KB,这是按十进制来的。要是啥单位都不带,那就是字节啦。
CPU 单位也很简单:1 等于 1000m,这个还能带小数点,比如 1.5 就等于 1500m。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 cat > quota.yml <<EOF apiVersion: v1 kind: Pod metadata: name: pod-limit labels: name: pod-limit spec: containers: - name: app image: registry.ocp4.example.com:8443/redhattraining/hello-world-nginx:latest imagePullPolicy: IfNotPresent resources: requests: memory: "64Mi" cpu: "100m" limits: memory: "128Mi" cpu: "100m" EOF
创建并确认配额
1 2 3 4 5 6 7 8 [student@workstation ~]$ oc describe -f quota.yml | grep -A 6 Limits Limits: cpu: 100m memory: 128Mi Requests: cpu: 100m memory: 64Mi Environment: <none>
虽然给单个 Pod 设置了资源配额,看起来好像挺合理的,但要是有人“机灵”得很,多创建几个 Pod,那资源不就偷偷被占多了嘛。就像本来给一个 Pod 分了 100m 的 CPU,那要是搞两个 Pod,不就变成 200m 了,三个就是 300m,这要是不限制,资源就被“薅羊毛”了。
所以,为了避免这种情况,就得给整个项目(project)设置个上限,就像给整个“资源池”拉起一道防线,不管对方怎么创建 Pod,总的资源都不会超过这个上限。这样一来,资源分配就更公平、更可控啦,也能防止有人“钻空子”。
项目级别设置资源限额 先创建一个project
1 oc new-project lixiaohui
给lixiaohui整个project设置配额
1 2 3 4 5 6 7 8 9 10 11 12 13 14 cat > project-quota.yml <<EOF apiVersion: v1 kind: ResourceQuota metadata: name: lixiaohuiquota namespace: lixiaohui spec: hard: pods: "1" requests.cpu: "1" requests.memory: "1Gi" limits.cpu: "2" limits.memory: "2Gi" EOF
创建并查看
这样比较直观的显示了我们目前可以申请多少资源
1 2 3 4 5 [student@workstation ~]$ oc create -f project-quota.yml resourcequota/lixiaohuiquota created [student@workstation ~]$ oc get -f project-quota.yml NAME AGE REQUEST LIMIT lixiaohuiquota 8s pods: 0/1, requests.cpu: 0/1, requests.memory: 0/1Gi limits.cpu: 0/2, limits.memory: 0/2Gi
我们试着创建一个超过项目配额的资源请求,看看是否失败
我们申请的内存不超标,但是CPU不管是request还是limit,都是超标的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 cat > exec-pod.yml <<EOF apiVersion: v1 kind: Pod metadata: name: frontend namespace: lixiaohui spec: containers: - name: app image: registry.ocp4.example.com:8443/redhattraining/hello-world-nginx:latest imagePullPolicy: IfNotPresent resources: requests: memory: "64Mi" cpu: "150m" limits: memory: "128Mi" cpu: "150m" EOF
从下面的报错来看,你超过限额就不行,我们通过给project设置限额,杜绝了用多个pod来绕过限额的可能
1 2 [student@workstation ~]$ oc create -f exec-pod.yml Error from server (Forbidden): error when creating "exec-pod.yml" : pods "frontend" is forbidden: exceeded quota: lixiaohuiquota, requested: limits.cpu=15,requests.cpu=15, used: limits.cpu=0,requests.cpu=0, limited: limits.cpu=2,requests.cpu=1
项目级别设置数量限额 在 Kubernetes 中,可以通过 ResourceQuota(资源配额) 来限制一个命名空间(Namespace)内资源的数量和使用情况。这个功能就像是给整个项目设置了一个“资源天花板”,防止资源被过度占用。
为什么需要数量限额?
假设你有一个项目,里面有多个团队在创建 Pod。如果不对数量进行限制,每个团队可能会无限制地创建 Pod,导致整个集群资源被耗尽。比如,一个团队可能为了测试,一口气创建了 100 个 Pod,而其他团队可能只需要 10 个 Pod 就够用了。这样一来,资源分配就会变得很不公平,甚至可能导致集群崩溃。
如何设置数量限额?
数量限额可以通过设置 ResourceQuota 来实现。你可以指定一个命名空间内可以创建的 Pod 数量上限。比如,你可以设置一个项目最多只能创建 50 个 Pod。这样一来,不管团队怎么折腾,Pod 的总数都不会超过 50 个。
我们看下面这个例子,在lixiaohui
的命名空间中只允许创建一个pod
1 2 3 4 5 6 7 8 9 10 cat > number-quota.yml <<-EOF apiVersion: v1 kind: ResourceQuota metadata: name: number-quota namespace: lixiaohui spec: hard: count/pods: "1" EOF
创建并验证
1 2 3 4 5 [student@workstation ~]$ oc create -f number-quota.yml resourcequota/number-quota created [student@workstation ~]$ oc get -f number-quota.yml NAME AGE REQUEST LIMIT number-quota 3s count/pods: 0/1
我们来创建一个3副本的deployment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 cat > deployment.yml <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: lixiaohui labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: registry.ocp4.example.com:8443/redhattraining/hello-world-nginx:latest imagePullPolicy: IfNotPresent ports: - containerPort: 8080 resources: requests: memory: "64Mi" cpu: "150m" limits: memory: "128Mi" cpu: "150m" EOF
创建并验证发现,只有1个在线
1 2 3 4 5 [student@workstation ~]$ oc create -f deployment.yml deployment.apps/nginx-deployment created [student@workstation ~]$ oc get -f deployment.yml NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 1/3 1 1 4s
查询为什么只有一个在线
清晰的看到,是因为超过了pod数量才失败
1 2 3 4 5 6 7 8 9 10 [student@workstation ~]$ oc get replicasets.apps NAME DESIRED CURRENT READY AGE nginx-deployment-577877fb79 3 1 1 48s [student@workstation ~]$ oc describe replicasets.apps nginx-deployment-577877fb79 ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 63s replicaset-controller Created pod: nginx-deployment-577877fb79-2lxp6 Warning FailedCreate 63s replicaset-controller Error creating: pods "nginx-deployment-577877fb79-rtj2j" is forbidden: exceeded quota: lixiaohuiquota, requested: pods=1, used: pods=1, limited: pods=1
跨project的集群级别配额 有时候,一个集群里有好多项目(也就是命名空间),每个项目都有自己的资源配额。但有时候,集群管理员可能需要从更高的层面来控制资源,比如限制某个开发团队管理的所有项目总共能用多少资源。这时候,就得用到集群级别的资源配额啦。
想象一下,有一群开发人员,他们管理着好几个项目(也就是好几个命名空间)。每个项目都有自己的资源配额,比如每个项目最多能用 10GB 的内存。但是,集群管理员可能担心这些项目加起来会用掉太多资源,比如整个集群的内存。这时候,就需要一个更高层次的控制手段。
集群资源配额的作用
集群资源配额就像是给整个集群加了一道“总闸门”。它不仅可以限制单个项目(命名空间)的资源使用,还可以限制一组项目(比如某个开发团队管理的所有项目)的总资源使用量。这样一来,即使每个项目都有自己的配额,整个团队的资源使用也不会超过管理员设定的上限。
如何实现?
集群资源配额的实现方式和命名空间资源配额有点像,但多了一个“选择器”(Selector)。选择器的作用就是告诉 Kubernetes:“嘿,我要对这几个特定的项目(命名空间)应用这个配额。”比如,你可以指定一个开发团队管理的所有项目,然后给这些项目设置一个总的内存使用上限。
集群管理员可能会对资源应用限制,而不限于单个命名空间。例如,一组开发人员管理着许多命名空间。命名空间配额可以限制每个命名空间的 RAM 使用量。但是,集群管理员无法限制该开发人员组管理的所有工作负载的总 RAM 使用量。
这里我们给具有quota=lixiahui标签的所有namespace设置了配额
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cat > cluster-quota.yml <<-EOF apiVersion: quota.openshift.io/v1 kind: ClusterResourceQuota metadata: name: cluster-quota spec: quota: hard: limits.memory: 400Mi selector: annotations: {} labels: matchLabels: quota: lixiahui EOF
创建并确认
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [student@workstation ~]$ oc create -f cluster-quota.yml clusterresourcequota.quota.openshift.io/cluster-quota created [student@workstation ~]$ oc get -f cluster-quota.yml NAME AGE cluster-quota 3s [student@workstation ~]$ oc describe -f cluster-quota.yml Name: cluster-quota Created: 48 seconds ago Labels: <none> Annotations: <none> Namespace Selector: [] Label Selector: quota=lixiahui AnnotationSelector: map[] Resource Used Hard -------- ---- ---- limits.memory 0 400Mi
我们创建一个zhangsan的project,然后给这个project添加上预期的标签,再创建一个名为lixiaohui的pod
1 2 3 4 5 6 7 8 9 10 11 oc new-project zhangsan oc label namespace zhangsan quota=lixiahui oc describe project zhangsan Name: zhangsan Created: 23 seconds ago Labels: kubernetes.io/metadata.name=zhangsan pod-security.kubernetes.io/audit=restricted pod-security.kubernetes.io/audit-version=v1.24 pod-security.kubernetes.io/warn=restricted pod-security.kubernetes.io/warn-version=v1.24 quota=lixiahui
看上去我们预期的quota=lixiahui标签已经存在,先来看看集群配额是否已经选中zhangsan
没问题,已经选中了zhangsan
1 2 3 4 5 6 7 8 9 10 11 [student@workstation ~]$ oc describe clusterresourcequotas.quota.openshift.io cluster-quota Name: cluster-quota Created: 3 minutes ago Labels: <none> Annotations: <none> Namespace Selector: ["zhangsan" ] Label Selector: quota=lixiahui AnnotationSelector: map[] Resource Used Hard -------- ---- ---- limits.cpu 0 400Mi
我们创建一个pod看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 cat > lixiaohui-pod.yml <<EOF apiVersion: v1 kind: Pod metadata: name: lixiaohui namespace: zhangsan spec: containers: - name: app image: registry.ocp4.example.com:8443/redhattraining/hello-world-nginx:latest imagePullPolicy: IfNotPresent resources: requests: memory: "64Mi" cpu: "150m" limits: memory: "128Mi" cpu: "150m" EOF
查看配额,然后创建出来,再看看配额
1 2 [student@workstation ~]$ oc create -f lixiaohui-pod.yml pod/lixiaohui created
再看的时候,就用了128Mi了
1 2 3 4 5 6 7 8 9 10 11 12 [student@workstation ~]$ oc describe clusterresourcequotas.quota.openshift.io cluster-quota Name: cluster-quota Created: 19 minutes ago Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion" :"quota.openshift.io/v1" ,"kind" :"ClusterResourceQuota" ,"metadata" :{"annotations" :{},"name" :"cluster-quota" },"spec" :{"quota" :{"hard" :{"limits.memory" :"400Mi" }},"selector" :{"annotations" :{},"labels" :{"matchLabels" :{"quota" :"lixiahui" }}}}} Namespace Selector: ["zhangsan" ] Label Selector: quota=lixiahui AnnotationSelector: map[] Resource Used Hard -------- ---- ---- limits.memory 128Mi 400Mi
我们再创建一个lisi的project,并分配quota=lixiaohui的标签,然后再创建一个pod,如果集群资源配额又上升,就说明不管你在哪儿创建,都会受到这个限制
1 2 oc new-project lisi oc label namespace lisi quota=lixiahui
我们创建一个pod看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 cat > lixiaohui-pod.yml <<EOF apiVersion: v1 kind: Pod metadata: name: lixiaohui namespace: lisi spec: containers: - name: app image: registry.ocp4.example.com:8443/redhattraining/hello-world-nginx:latest imagePullPolicy: IfNotPresent resources: requests: memory: "64Mi" cpu: "150m" limits: memory: "128Mi" cpu: "150m" EOF
创建并验证配额是否上升,从刚才的128,上升到256,说明不管你在哪个project,都会受到限制
1 2 3 4 5 6 7 8 9 10 11 12 13 [student@workstation ~]$ oc create -f lixiaohui-pod.yml [student@workstation ~]$ oc describe clusterresourcequotas.quota.openshift.io cluster-quota Name: cluster-quota Created: 25 minutes ago Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion" :"quota.openshift.io/v1" ,"kind" :"ClusterResourceQuota" ,"metadata" :{"annotations" :{},"name" :"cluster-quota" },"spec" :{"quota" :{"hard" :{"limits.memory" :"400Mi" }},"selector" :{"annotations" :{},"labels" :{"matchLabels" :{"quota" :"lixiahui" }}}}} Namespace Selector: ["zhangsan" "lisi" ] Label Selector: quota=lixiahui AnnotationSelector: map[] Resource Used Hard -------- ---- ---- limits.memory 256Mi 400Mi