When you describe a Pod, you can optionally specify how much CPU and memory (RAM) each Container needs. When containers have resource requests specified, the scheduler can make better decisions about which nodes to place Pods on. And when Containers have their limits specified, contention for resources on a node can be handled in a specified manner.
Requests are what the container is guaranteed to get. A pod will always be scheduled to a node that has the resources available to meet the request. Limits, on the other hand, make sure a container never goes above a certain value. The container is only allowed to go up to the limit, and then it is restricted.
CPU and memory are each a resource type. A resource type has a base unit. CPU is specified in units of cores, and memory is specified in units of bytes.
CPU and memory are collectively referred to as compute resources, or just resources. Compute resources are measurable quantities that can be requested, allocated, and consumed. They are distinct from API resources. API resources, such as Pods and Services are objects that can be read and modified through the Kubernetes API server.
Fractional requests are allowed. A Container with spec.containers[].resources.requests.cpu of 0.5 is guaranteed half as much CPU as one that asks for 1 CPU. The expression 0.1 is equivalent to the expression 100m, which can be read as “one hundred millicpu”. Some people say “one hundred millicores”, and this is understood to mean the same thing.
So basicly cpu: "500m" means 0.5 cpu, and cpu: "2000m" means 2 cpu's.
Limits and requests for memory are measured in bytes. You can express memory as a plain integer or as a fixed-point integer using one of these suffixes: E, P, T, G, M, K. You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. For example, the following represent roughly the same value:
128974848, 129e6, 129M, 123Mi
Create a namespace for this lab:
kubectl create ns lab-15
---
namespace/lab-15 created
Create a file named lab-15-limited-pod.yml
with the following content.
apiVersion: v1
kind: Pod
metadata:
name: container-info
spec:
containers:
- name: container-info
image: gluobe/container-info:blue
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
kubectl apply -f lab-15-limited-pod.yml -n lab-15
---
pod/container-info created
Now the container-info container will be scheduled on a node that has 64Mi of memory available and 0.25 cpu's. It’s when it comes to CPU limits that things get interesting. CPU is considered a “compressible” resource. If your app starts hitting your CPU limits, Kubernetes starts throttling your container. This means the CPU will be artificially restricted, giving your app potentially worse performance! However, it won’t be terminated or evicted. Unlike CPU resources, memory cannot be compressed. Because there is no way to throttle memory usage, if a container goes past its memory limit it will be terminated. If your pod is managed by a Deployment, StatefulSet, DaemonSet, or another type of controller, then the controller spins up a replacement.
Because sometimes same teams work on the same kubernetes cluster but in a different namespace, it is important to limit people from taking more than their fair share of the cluster.
To prevent these scenarios, you can set up ResourceQuotas and LimitRanges at the Namespace level.
After creating Namespaces, you can lock them down using ResourceQuotas. ResourceQuotas are very powerful, but let’s just look at how you can use them to restrict CPU and Memory resource usage.
Create the following file named lab-15-resource-quota.yml
.
apiVersion: v1
kind: ResourceQuota
metadata:
name: "demo"
spec:
hard:
requests.cpu: "500m"
requests.memory: "100Mi"
limits.cpu: "700m"
limits.memory: "500Mi"
kubectl apply -f lab-15-resource-quota.yml -n lab-15
This will have created a ResourceQuota which on the namespace lab-15. If we try and create a pod which exceeds the limits from the ResourceQuota we will get an error. Edit the file from our limited pod into this file:
apiVersion: v1
kind: Pod
metadata:
name: container-info
spec:
containers:
- name: container-info
image: gluobe/container-info:blue
resources:
requests:
memory: "600Mi"
cpu: "1m"
limits:
memory: "1000Mi"
cpu: "1.5m"
kubectl apply -f lab-15-limited-pod.yml -n lab-15`
---
Error from server (Forbidden): error when creating "lab15-limited-pod.yml": pods "container-info" is forbidden: exceeded quota: demo, requested: limits.memory=1000Mi,requests.memory=600Mi, used: limits.memory=0,requests.memory=0, limited: limits.memory=500Mi,requests.memory=100Mi
kubectl delete resourcequota demo -n lab-15
---
resourcequota "demo" deleted
You can also create a LimitRange in your namespace. Unlike a Quota, which looks at the namespace as a whole, a LimitRange applies to an individual container. This can help prevent people from creating super tiny or super large containers inside the namespace.
Create a file named lab-15-limitrange.yml
with the following content:
apiVersion: v1
kind: LimitRange
metadata:
name: limit-mem-cpu-per-container
spec:
limits:
- max:
cpu: "800m"
memory: "1Gi"
min:
cpu: "100m"
memory: "99Mi"
default:
cpu: "700m"
memory: "900Mi"
defaultRequest:
cpu: "110m"
memory: "111Mi"
type: Container
kubectl apply -f lab-15-limitrange.yml -n lab-15
---
limitrange/limit-mem-cpu-per-container created
As you can see the yaml file has 4 sections:
The max section will set up the maximum limits that a container in a Pod can set. The default section cannot be higher than this value. Likewise, limits set on a container cannot be higher than this value.
The min section sets up the minimum Requests that a container in a Pod can set. The defaultRequest section cannot be lower than this value. Likewise, requests set on a container cannot be lower than this value either.
The default section sets up the default limits for a container in a pod. If you set these values in the limitRange, any containers that don’t explicitly set these themselves will get assigned the default values.
The defaultRequest section sets up the default requests for a container in a pod. If you set these values in the limitRange, any containers that don’t explicitly set these themselves will get assigned the default values.
kubectl apply -f lab-15-limited-pod.yml -n lab-15
---
Error from server (Forbidden): error when creating "lab15-limited-pod.yml": pods "container-info" is forbidden: minimum cpu usage per Container is 100m, but request is 1m
kubectl delete namespace lab-15
---
namespace "lab-15" deleted