一、测试内存限制
1.1 环境准备
名词说明:

limits: 容器能使用资源的最大值
requests: 容器使用的最小资源需求
LimitRange: 用来给Namespace增加一个资源限制,包括最小、最大和默认资源 LimitRange 的规则限定在 K8S namespace

当前线上业务使用default namespace,且未设置LimitRange

Name:         default
Labels:       <none>
Annotations:  <none>
Status:       Active
No resource quota.
No resource limits.

1.2 测试创建Pod时指定container的limits但不指定requests
pod test-mem

apiVersion: v1
kind: Pod
metadata:
  name: test-mem
  labels:
    app: test-mem
spec:
  containers:
  - name: test-mem
    image: harbor-test.api.com:80/library/ubuntu-16.04-base:190806
    command: ["top","-b"]
    resources:
      limits:
        memory: 100Mi
  tolerations:
    - effect: "NoSchedule"
      operator: "Exists"
    - key: "dedicated"
      operator: "Equal"
      value: "autotest"
  nodeSelector:
    kubernetes.io/hostname: 192.168.1.1

describe pod可发现,pod成功创建,requests和limits的值均为:100Mi
在这里插入图片描述
结论:如果指定pod/container的limits但未指定requests,则创建的pod/container的requests值会取limits的值。

1.3 验证超过limit限制的内存资源后 OOM
实验准备:创建一个pod,内存限制Limits为100Mi
test_mem_pod.yml

apiVersion: v1
kind: Pod
metadata:
  name: test-mem
  labels:
    app: test-mem
spec:
  containers:
  - name: test-mem
    image: harbor-test.api.com:80/library/ubuntu-16.04-base:190806
    command: ["top","-b"]
    resources:
      limits:
        memory: 100Mi
      requests:
        memory: 100Mi
  tolerations:
    - effect: "NoSchedule"
      operator: "Exists"
    - key: "dedicated"
      operator: "Equal"
      value: "autotest"
  nodeSelector:
    kubernetes.io/hostname: 192.168.1.1

压力测试
容器中安装压力测试工具:
#apt update; apt install -y stress
终端一:容器中压力测试,创建第一个压测,限制内存为50M,可以创建成功,继续第二次压力测试,使用51M内存,创建失败。
在这里插入图片描述
终端二:查看宿主机系统日志
在这里插入图片描述
可以看出当内存使用超过limit100Mi时,cgruops 出发 OOM
总论:k8s根据limits限制pod使用资源,当内存超过limits时会触发OOM。
二、超卖内存测试
2.1、环境准备
测试超配场景:按mem 1:3超卖,创建pod时设置container的request: 500Mi, limits:1500Mi (单pod单container)
测试预计效果:pod指定发布在宿主机15G的内存机器,除去kubelet和系统预留3G,可用内存为12G,理论可创建pod 24个(单个requests为500MI),单个pod的最大使用内存为1500Mi;

deployment
#创建deployment,设置container的request为500Mi, limits为1500Mi
#cat test_mem_deployment.yml

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: test-mem-pod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-mem-pod
  template:
    metadata:
      labels:
        app: test-mem-pod
        deployment: test-mem-pod
    spec:
      nodeSelector:
        environment: test
        kubernetes.io/hostname: 192.169.1.1
      containers:
        - image: 'harbor-test.api.com:80/library/ubuntu-16.04-base:190806'
          command: ["top","-b"]
          name: test-mem-pod
          resources:
            limits:
              memory: 1500Mi
            requests:
              memory: 500Mi
      tolerations:
        - effect: "NoSchedule"
          operator: "Exists"
        - key: "dedicated"
          operator: "Equal"
          value: "autotest"

#创建deployment, 数量为1
#kubectl create -f test_mem_deployment.yml
2.2 实验测试验证
2.2.1 确认宿主机空闲内存

#free -g
total used free shared buff/cache available
Mem: 15 0 4 0 10 13
Swap: 0 0 0

2.2.2 验证宿主机最大可创建24个pod
在宿主机上创建pod,扩容至30个;可见24个running,其中6个为pending,因为宿主机内存不足,无法调度。
在这里插入图片描述
2.2.3 单个pod的最大使用内存为1.5G验证
a. 在容器窗口进行压力测试,使用内存 1000M,如下图,可以正常使用,request: 500Mi, limits:1500Mi 在这里插入图片描述
b. 在容器窗口进行压力测试,使用内存 1501M;出现OOM,超过limits1500Mi在这里插入图片描述在这里插入图片描述
结论:k8s调度时根据pod 的requests值计算调度策略,通过limits限制单个pod使用最大资源;

三、 Namespace配置内存的默认值以及超卖最大比例
3.1 准备环境
namespace

创建namespace

$ kubectl create namespace default-mem-example

创建LimitRange

$ cat memory-defaults.yaml

apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
  namespace: default-mem-example
spec:
  limits:
  - default:
      memory: 512Mi      #default limit
    defaultRequest: 
      memory: 256Mi      #default request
    max: 
      memory: 1000Mi     #max limit
    min:
      memory: 10Mi       #min request
    maxLimitRequestRatio:
      memory: 10         #max value for limit / request
    type: Container      #limit type, support: Container / Pod / PersistentVolumeClaim
 

$ kubectl create -f  memory-defaults.yaml --namespace=default-mem-example
验证环境
Name:         default-mem-example
Labels:       <none>
Annotations:  <none>
Status:       Active
No resource quota.
Resource Limits
 Type       Resource  Min   Max     Default Request  Default Limit  Max Limit/Request Ratio
 ----       --------  ---   ---     ---------------  -------------  -----------------------
 Container  memory    10Mi  1000Mi  256Mi            512Mi          10
3.2 验证默认参数LimitRange限制
3.2.1 验证default 配置,创建一个pod,yml文件中不设定requests和limits
deployment.yml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: test-mem-pod
  namespace: default-mem-example
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-mem-pod
  template:
    metadata:
      labels:
        app: test-mem-pod
        deployment: test-mem-pod
    spec:
      nodeSelector:
        environment: test
        kubernetes.io/hostname: 192.168.2.1
      containers:
        - image: 'harbor-test.api.com:80/library/ubuntu-16.04-base:190806'
          command: ["top","-b"]
          name: test-mem-pod

describe pod可发现,pod成功创建,并且使用LimitRange对象定义的默认值设置了requests和limits (default request:256Mi; default limits:512Mi)
在这里插入图片描述
结论:如果没有指定pod的request和limit,则创建的pod会使用LimitRange对象定义的默认值(request和limit)

3.2.2 验证自定义限制,创建一个pod,设定request:80Mi,limit:800Mi;
describe pod可发现,pod成功创建,并且requests和limits的值为yml文件中设定的值(request:80Mi; default limits:800Mi)
在这里插入图片描述
结论:如果指定了pod的request和limit,按自己指定的值创建设定request和limit

3.2.3 验证创建一个pod,yml文件中仅设置limit不设置request(limits:800Mi)
describe pod可发现,pod成功创建,其中limits值为800Mi,request值也为800Mi,而LimitRange对象定义的request默认值为256Mi
在这里插入图片描述
**结论:如果指定container的limits但未指定requests,则创建的container的requests值会取limits的值,而不会取LimitRange对象定义的requests默认值
3.2.4 验证创建一个pod,yml文件中仅设置requests不设置limit (requests:80Mi)
describe pod可发现,pod成功创建,其中request值为80Mi,limits值为512Mi;可见没有指定limits取LimitRange对象定义的limit默认值(默认值limits为512Mi)
在这里插入图片描述
测试创建一个pod,yml文件中仅设置requests不设置limits ,且request值为600Mi(大于LimitRange对象定义的limits默认值512Min)
创建失败,如果仅设置requests,requests的值必须设置小于LimitRange对象定义的limits默认值

kubectl create -f test-mem-pod.yml
The Pod "test-mem" is invalid: spec.containers[0].resources.requests: Invalid value: "600Mi": must be less than or equal to memory limit

结论:如果指定pod的request但未指定limit,则创建的pod的limit值会取LimitRange对象定义的limit默认值,且requests的值必须设置小于LimitRange对象定义的limits默认值。

3.2.5 验证设置的limits大于max limits或者min小于requests
创建一个pod,yml文件中设置limits的值为1001Mi(LimitRange对象定义的max limits为1000Mi);requests同理测试,这里不列出了。
创建失败,超过max limits mem 1000Mi
结论:LimitRange对象可定义的pod/container的max limits和min requests,用来限制pod创建时对limits和requests的误设置

3.2.6 配置超卖比例maxLimitRequestRatio: mem 10(10倍)
创建一个pod,yml文件中设置limits的值为500Mi,requests值为20Mi,(则超卖比例为500/20=25,大于LimitRange对象定义的maxLimitRequestRatio: mem 10)
创建失败,超过内存超卖比例10

#kubectl create -f test-mem-pod.yml
Error from server (Forbidden): error when creating "test.yml": pods "test-mem" is forbidden: memory max limit to request ratio per Container is 10, but provided ratio is 25.000000.

结论:LimitRange对象可定义的pod/container的maxLimitRequestRatio,用来限制pod创建时超卖的最大比例。

整体结论

  1. k8s 调度时根据pod 的requests 值计算调度策略,通过limits 限制单个pod 使用最大资源;
  2. 超卖比例可以设置requests 和 limits 值进行调整;
  3. Namespace 可以通过 LimitRange 限制超卖比例最大值、单个pod 的最大limit和最小 request、以及
    pod 的默认limit 和默认 request 值;
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐