k8s 学习笔记 - LimitRange 限制范围

简介: k8s 学习笔记 - LimitRange 限制范围

前情提要

  • 在当前工作经验中,从未限制过 namespace 的资源,这次的实施工作中,使用的是第三方定制的 k8s集群,在 namespace 被创建时,因为 yaml 文件没有配置 limits 和 requests 两个参数,当 yaml 文件被 apply 后,自动对 pod 配置了 LimitRange 中定义的 limits 和 requests,结果资源不够使用,导致容器启动过程中出现 OOMKilled 报错
  • 后续在 yaml 中加上 limits 和 requests 依然有报错,导致控制器无法创建 pod,原因是 LimitRange 中的 limits.maxLimitRequestRatio 配置,对于 limits 和 requests 的比例有限制

开始复盘

下面两个是 k8s 官方文档

借用一下官方文档

什么是限制范围

  • LimitRange 是限制 namespace(命名空间)内可为每个适用的对象类别 (例如 Pod 或 PersistentVolumeClaim)指定的资源分配量(limits 和 requests)的策略对象
  • 一个 LimitRange(限制范围)对象提供的限制能够做到:
  • 在一个 namespace(命名空间)中实施对每个 Pod 或 Container 最小和最大的资源使用量的限制。
  • 在一个 namespace(命名空间)中实施对每个 PersistentVolumeClaim 能申请的最小和最大的存储空间大小的限制。
  • 在一个 namespace(命名空间)中实施对一种资源的requests(申请值)和limits(限制值)的比值的控制。
  • 设置一个 namespace(命名空间)中对计算资源的默认 requests(申请值) / limits(限制值),并且自动的在运行时注入到多个 Container 中。
  • 当某namespace(命名空间)中有一个 LimitRange 对象时,将在该namespace(命名空间)中实施 LimitRange 限制
  • LimitRange 的名称必须是合法的 DNS 子域名
资源限制和请求的约束
  1. 管理员在一个namespace(命名空间)内创建一个 LimitRange 对象。
  2. 用户在此namespace(命名空间)内创建(或尝试创建) Pod 和 PersistentVolumeClaim 等对象。
  3. 首先,LimitRanger 准入控制器对所有没有设置计算资源需求的所有 Pod(及其容器)设置默认请求值与限制值。
  4. 其次,LimitRange 跟踪其使用量以保证没有超出命名空间中存在的任意 LimitRange 所定义的最小、最大资源使用量以及使用量比值。
  5. 若尝试创建或更新的对象(Pod 和 PersistentVolumeClaim)违反了 LimitRange 的约束, 向 API 服务器的请求会失败,并返回 HTTP 状态码 403 Forbidden 以及描述哪一项约束被违反的消息。
  6. 若你在namespace(命名空间)中添加 LimitRange 启用了对 cpu 和 memory 等计算相关资源的限制, 你必须指定这些值的请求使用量与限制使用量。否则,系统将会拒绝创建 Pod。
  7. LimitRange 的验证仅在 Pod 准入阶段进行,不对正在运行的 Pod 进行验证。 如果你添加或修改 LimitRange,namespace(命名空间)中已存在的 Pod 将继续不变。
  1. 如果命名空间中存在两个或更多 LimitRange 对象,应用哪个默认值是不确定的

实践出真知

  • 这里图省事,就直接拿 k8s 自带的 default 这个 namespace 来做演示

这里图省事,就直接部署 pod ,没有使用任何控制器(deployment,statefulset,daemonset 这一类)

  • 如果是控制器启动的,以下创建 pod 失败的场景,通过 kubectl get pod 命令会查看不到 pod 被创建的,使用 kubectl describe <控制器名称> 命令能查看到同理的报错
  • 以下的示例都是拿 cpu 做演示,内存是同理的
场景1

pod 配置的 requests 超出了 LimitRange 配置的 limits

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-resource-constraint
spec:
  limits:
  - default: # 此处定义默认限制值(limits)
      cpu: 500m
    defaultRequest: # 此处定义默认请求值(requests)
      cpu: 500m
    type: Container
EOF

可以通过 kubectl get limitrange 命令查看是否创建成功

创建一个 pod 来验证

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - name: busybox
    image: busybox:1.28.3
    command:
      - sleep
      - "36000"
    imagePullPolicy: IfNotPresent
    resources:
      requests:
        cpu: 700m
  restartPolicy: Always
EOF

这个时候就会有报错出现 The Pod "busybox" is invalid: spec.containers[0].resources.requests: Invalid value: "700m": must be less than or equal to cpu limit

  • 只需要把 cpu: 700m 调小一点,低于 limitrange 里面配置的 default 就可以重新运行 pod 了
场景2

继续使用场景1的 limitrange ,但是创建的 pod 同时配置了 limits 和 requests ,并且均超过 limitrange 里面配置的资源限制

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-resource-limits-requests
  namespace: default
spec:
  containers:
  - name: busybox
    image: busybox:1.28.3
    command:
      - sleep
      - "36000"
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        cpu: 700m
      requests:
        cpu: 700m
  restartPolicy: Always
EOF

此时,pod 是可以被创建的

场景3

继续使用场景1的 limitrange ,但是创建的 pod 没有配置 limits 和 requests

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-no-resource-set
  namespace: default
spec:
  containers:
  - name: busybox
    image: busybox:1.28.3
    command:
      - sleep
      - "36000"
    imagePullPolicy: IfNotPresent
  restartPolicy: Always
EOF

pod 是肯定可以创建的,并且会自动给 pod 赋值 limits 和 requests

kubectl get pod busybox-no-resource-set -o yaml | grep 'resources' -A 4

可以看出来,limits 和 requests 都是 limitrange 内配置的 500m

    resources:
      limits:
        cpu: 500m
      requests:
        cpu: 500m
场景4

继续使用场景1的 limitrange ,但是创建的 pod 只配置了 limits ,并且比 limitrange 里面的值要高

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-just-limits
  namespace: default
spec:
  containers:
  - name: busybox
    image: busybox:1.28.3
    command:
      - sleep
      - "36000"
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        cpu: 700m
  restartPolicy: Always
EOF

pod 可以被成功创建,且 requests 被赋值和 limits 的值一致

kubectl get pod busybox-just-limits -o yaml | grep 'resources' -A 4
    resources:
      limits:
        cpu: 700m
      requests:
        cpu: 700m
场景5
  • 这里图省事,就拿内存来做示例了
  • limitrange 配置了 maxLimitRequestRatio,创建的 pod 的 limits/requests 的值不等于 1
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-resource-constraint
spec:
  limits:
  - default: # 此处定义默认限制值(limits)
      memory: 256Mi
    defaultRequest: # 此处定义默认请求值(requests)
      memory: 256Mi
    maxLimitRequestRatio: # 此处定义 limits/requests 的值必须等于 1
      memory: 1
    type: Container
EOF

创建一个 pod 来验证

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: busybox-ratio-ne-one
  namespace: default
spec:
  containers:
  - name: busybox
    image: busybox:1.28.3
    command:
      - sleep
      - "36000"
    imagePullPolicy: IfNotPresent
    resources:
      limits:
        memory: 700Mi
      requests:
        memory: 70Mi
  restartPolicy: Always
EOF

这个 pod 是无法被创建的,会返回 Error from server (Forbidden): error when creating "STDIN": pods "busybox-ratio-ne-one" is forbidden: memory max limit to request ratio per Container is 1, but provided ratio is 10.000000 这样的报错

这个 10.000000 就是 700/70=10 得来的

只需要把 limits 和 requests 的值改成一样的,就可以成功启动 pod 了

学习总结

  • 当 namespace 配置了 limitrange ,并且 pod 创建时没有指明 limits 或/和 requests 时,pod 被创建后由 limitrang 的配置来指明 pod 的 limits 或/和 requests
  • 当 namespace 配置了 limitrange ,并且 pod 创建时的 requests 超出了 limitrange 配置的 limits 时,会有报错 must be less than or equal to xxx limit

当 namespace 配置了 limitrange 以及 maxLimitRequestRatio ,并且 pod 创建时的 limits/requests 值大于 maxLimitRequestRatio 配置的值,会有报错 is forbidden: xxx max limit to request ratio per Container is xxx, but provided ratio is xxx

关于 limits , requests , maxLimitRequestRatio 的取值,主要是围绕 cpu 和 memroy 的单位来的

  • 在 k8s 中,cpu的单位为m,1000m=1核
  • 0.1m 将向上取整为 1m
  • 在 k8s 中,memory 的单位为 k | M | G | T | P | E 或者 Ki | Mi | Gi | Ti | Pi | Ei
  • 区别在于换算不同,一个是1:1000,另一个是1:1024:
  • 1m 表示 1000k
  • 1Mi 表示 1024k
  • 程序员眼中的整数,必须是 1024
  • 最后,大家也可以去验证,当 memory 这里写 1.5 的时候,pod 创建完,再去 get -o yaml,就会发现 1.5 变成了 1500m
相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
Kubernetes Ubuntu Cloud Native
深入剖析Kubernetes学习笔记-05 | 白话容器基础(一):从进程说开去
深入剖析Kubernetes学习笔记-05 | 白话容器基础(一):从进程说开去
377 0
|
Prometheus Kubernetes 网络协议
k8s学习笔记之CoreDNS
k8s学习笔记之CoreDNS
1288 3
|
Kubernetes jenkins 持续交付
jenkins学习笔记之二十一:k8s部署jenkins及动态slave
jenkins学习笔记之二十一:k8s部署jenkins及动态slave
2092 0
|
存储 Kubernetes 数据安全/隐私保护
k8s学习笔记之ConfigMap和Secret
k8s学习笔记之ConfigMap和Secret
|
存储 运维 Kubernetes
k8s学习笔记之StorageClass+NFS
k8s学习笔记之StorageClass+NFS
|
Kubernetes 调度 Docker
Ubantu docker学习笔记(十一)k8s基本操作
Ubantu docker学习笔记(十一)k8s基本操作
|
存储 Kubernetes 负载均衡
k8s学习-思维导图与学习笔记
k8s学习-思维导图与学习笔记
722 1
|
存储 资源调度 Kubernetes
指令很全的K8s学习笔记(三)
指令很全的K8s学习笔记(三)
指令很全的K8s学习笔记(三)
|
存储 Kubernetes 负载均衡
指令很全的K8s学习笔记(二)
指令很全的K8s学习笔记(二)
指令很全的K8s学习笔记(二)
|
Kubernetes 负载均衡 数据中心
K8s学习笔记(3)——Namespace,Pod,Label,Deployment,Service
K8s学习笔记(3)——Namespace,Pod,Label,Deployment,Service
576 1

推荐镜像

更多