當Pod在運行時,必須要曉得創建時若沒有特別限制Pod的Container只能使用多少記憶體的話,一但容器內的服務突然發生記憶體用量大增的情況,可能會導致整個Node的資源都會吃光光了
所以本節要來探討Pod在記憶體控制的情況是如何,以及要如何在Pod內設置Memory資源,Here we go!
接下來的範例都是透過minikube所建置的
事前準備
確保cluster內的每個node都有300MB記憶體
先在minikube建立metrics-server
1 minikube addons enable metrics-server
會看到以下output
1 2 3 minikube addons enable metrics-server ▪ Using image k8s.gcr.io/metrics-server /metrics-server :v0.4 .2 🌟 The 'metrics-server' addon is enabled
透過 kubectl get apiservices
確認 metrics.k8s.io
是否有在運行
1 2 NAME SERVICE AVAILABLE AGE v1beta1.metrics.k8s.io kube-system/metrics-server True 42s
定義namespace將範例用的pod與其他服務隔離開來
1 kubectl create namespace mem-example
限制Pod的記憶體
在spec
底下以下屬性來限制記憶體資源使用
resources:requests
: 定義Pod需要多少記憶體資源
resources:limits
: 限制Pod運行時最高只能用多少記憶體資源
接下來會使用一個壓測用的容器,來建立Pod,並在 args
中分配這個容器有 150M
的記憶體資源
pods-resource-memory-request-limit.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: v1 kind: Pod metadata: name: memory-demo namespace: mem-example spec: containers: - name: memory-demo-ctr image: polinux/stress resources: limits: memory: "200Mi" requests: memory: "100Mi" command: ["stress"] args: ["--vm", "1" , "--vm-bytes" , "150M" , "--vm-hang" , "1" ]
建立Pod
1 kubectl apply -f pods-resource-memory-request-limit .yml --namespace=mem-example
確認Pod是否有在運作
1 2 3 kubectl get pod memory-demo --namespace=mem-example NAME READY STATUS RESTARTS AGE memory-demo 1 /1 Running 0 27 s
檢視Pod的詳細資訊
1 kubectl get pod memory-demo --output =yaml --namespace =mem-example
可以看到spec.resource
定義了記憶體的限制資訊
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 apiVersion: v1kind: Podmetadata: ... spec: containers: - args: - --vm - "1" - --vm-bytes - 150 M - --vm-hang - "1" command: - stress image: polinux/stress imagePullPolicy: Always name: memory-demo-ctr resources: limits: memory: 200 Mi requests: memory: 100 Mi terminationMessagePath: /dev/ termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /var/ run/secrets/ kubernetes.io/serviceaccount name: default-token-xk6rl readOnly: true ...
接著透過 kubectl top
讀取pod的metrics資訊
1 2 3 4 5 kubectl top pod memory-demo W0523 09:22:58.077337 17272 top_pod.go:140] Using json format to get metrics. Next release will switch to protocol-buffers, switch early by passing NAME CPU(cores) MEMORY (bytes )memory -demo 84 m 150 Mi
可看到剛創建的Pod使用了150 Megabyte的記憶體資源,比原本分配給Pod 100 MB來得高,但還沒超出200MB的限制
超出記憶體的情況
當Container的記憶體耗費超出所限制的話,就會優先列為被終止的對象
接著來創建一個會耗費過多記憶體的範例,直接給容器250MB,大於原本限制的100MB
memory-demo-2-ctr.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion : v1kind : Podmetadata : name : memory-demo-2 namespace : mem-example spec : containers : - name : memory-demo-2 -ctr image : polinux/stress resources : requests : memory : "50Mi" limits : memory : "100Mi" command : ["stress" ] args : ["--vm" , "1" , "--vm-bytes" , "250M" , "--vm-hang" , "1" ]
看一下Pod運行後會怎樣,可看到狀態為 OOMKilled
,表示記憶體溢出,準備被砍掉,且一直被Restart
1 2 3 4 kubectl get pod memory-demo-2 --namespace=mem-example NAME READY STATUS RESTARTS AGE memory-demo-2 0 /1 OOMKilled 0 8 s
在查看Pod的詳細資訊,可看到被終止的原因為記憶體消耗超出限制
1 kubectl get pod memory-demo-2 --output =yaml --namespace =mem-example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 status : conditions : ... containerStatuses : - containerID : docker : image : polinux/stress :latest imageID : docker-pullable : lastState : terminated : # 這裡可以看到終止的原因 containerID : docker : exitCode : 1 finishedAt : "2021-05-23T09:31:03Z" reason : OOMKilled startedAt : "2021-05-23T09:31:03Z"
透過 kubectl describe pod memory-demo-2 --namespace=mem-example
確認pod的運行狀況
1 2 3 4 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning BackOff 3m1s (x7 over 4m14s) kubelet Back-off restarting failed container
接著檢視node資訊 kubectl describe nodes
,會看到該Container的事件訊息
1 Warning OOMKilling Memory cgroup out of memory : Kill process 4481 (stress) score 1994 or sacrifice child
定義一個超過Node的記憶體上限的Pod
若目前Node的記憶體為8GB,直接分配1000GB的記憶體,來看看會發生什麼事
pods-resource-memory-request-limit-3.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion : v1kind : Podmetadata : name : memory-demo-3 namespace : mem-example spec : containers : - name : memory-demo-3 -ctr image : polinux/stress resources : limits : memory : "1000Gi" requests : memory : "1000Gi" command : ["stress" ] args : ["--vm" , "1" , "--vm-bytes" , "150M" , "--vm-hang" , "1" ]
1 kubectl apply -f pods-resource-memory-request-limit -3. yml --namespace=mem-example
檢視Pod資訊,會看到狀態是Pending中
1 2 3 4 kubectl get pod memory-demo-3 --namespace=mem-example NAME READY STATUS RESTARTS AGE memory-demo-3 0 /1 Pending 0 33 s
透過kubectl describe
可以了解到,Pod無法被Scheduler排入創建列表內,因為Node沒有足夠記憶體可以給他
1 2 3 kubectl describe pod memory -demo-3 Warning FailedScheduling 65 s (x2 over 65 s) default -scheduler 0 /1 nodes are available: 1 Insufficient memory.
透過 `kubectl describe`方式可以幫助我們了解一個Pod的執行狀況是如何
若沒有為Pod定義記憶體限制的情況
會有兩種情況:
若有歸類在namespace底下,會根據 LimitRange 來分配預設的限制數目
若單純只是起動起來,那就有可能會遭遇 OOMKilled
,表示記憶體溢出,準備被砍掉,且一直被Restart
參考
Assign Memory Resources to Containers and Pods
Limit Ranges