본문 바로가기

Container/Kubernetes

[K8S] Pod Resource 할당

Default로는 container는 리소스 할당에 대한 제한이 없다.

No limit, No request : 하나의 파드가 모든 리소스를 사용할 수 있고, 2번째 Pod가 필요한 리소스를 할당받는데 방해한다.

Resource Request

  • 어느 노드가 실행해주면 좋을 지를 scheduler가 판단한다.
  • 컨테이너가 실행되기 위해 최소한으로 필요한 메모리의 양을 정의한다.
  • Kubernetes 스케줄러는 이 값을 기반으로 Pod을 스케줄링할 노드를 결정합니다.
  • Request는 보장된 자원으로, 다른 컨테이너가 이 메모리를 빼앗아 사용할 수 없습니다.
  • Pod이 실행되려면 노드에 Request 값 이상의 사용 가능한 메모리가 있어야 함.
  • 노드가 과부하 상태가 되면, Request가 낮은 Pod이 우선적으로 제거될 수 있음(Eviction).

Resource Limit

  • 컨테이너가 사용할 수 있는 최대 리소스 양(메모리 상한선)을 정의한다.
  • 컨테이너가 이 값을 초과하여 메모리를 사용하려고 하면 OOM(Out Of Memory) 오류가 발생하며, 해당 컨테이너가 재시작될 수 있다.
    • OOM Kill: Pod Limit을 초과한 메모리를 사용 -> Limit 값을 더 높이기
  • Limit을 설정하지 않으면 컨테이너는 필요한 만큼의 메모리를 사용하려고 시도한다.
  • 파드의 node name 속성을 수정할 수 없다.
  • 이미 존재하는 Pod에 노드를 assign하는 방법은 'binding object'나 POST request를 보내는 방법이 있다.
# pod-bind-defintion.yaml
apiVersion: v1
kind: binding
metadata:
  name: nginx
target:
  apiVersion: v1
  kind: Node
  name: <target Node>
  
  # then send a POST request to the pod's binding API
  $ curl --header "Content-type:application/json" --request POST --data '{"apiVersion":"v1", "kind": "Binding" ...}' http://$SERVER/api/v1/namespaces/default/pods

 

동작 원리

(1) Request 기준 스케줄링

  • 스케줄러는 Pod의 Request 값과 노드의 가용 메모리를 비교하여 Pod를 배치한다.
    • 예: Request가 500Mi인 Pod은 가용 메모리가 500Mi 이상인 노드에만 배치

(2) Limit 초과 시 동작

  • 컨테이너가 Limit을 초과하면, OOM Killer가 작동하여 컨테이너를 Restart 시킨다.

(3) Request와 Limit을 모두 설정하지 않은 경우

  • Request와 Limit이 지정되지 않으면, Namespace의 디폴트 값이 사용되거나 제한 없이 메모리를 사용할 수있다
Request < Limit
일반적으로 설정하는 방식으로, Pod이 최소 자원을 보장받으면서 필요 시 더 많은 자원을 사용할 수 있도록 설정.
Request == Limit
고정된 메모리 자원이 필요한 워크로드에 사용.예: 안정적으로 동작해야 하는 데이터베이스 컨테이너.
Request > Limit
잘못된 설정으로, 이 상태에서는 Pod이 스케줄링되지 않음.

 

Memory Request와 Limit의 비교

  Memory Request Memory Limit
역할 최소한으로 보장된 메모리 자원 최대 사용할 수 있는 메모리 자원
스케줄링 영향 노드 선택에 영향을 줌 스케줄링에 영향 없음
초과 사용 시 결과 요청한 양 이상으로 사용할 수 있음 초과 시 컨테이너 종료(OOM Kill)
주요 목적 안정적인 자원 할당 자원 과도 사용 방지

 

 


# 노드 지정 실습

controlplane ~ ➜  cat nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  -  image: nginx
     name: nginx
     
controlplane ~ ➜  kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
nginx   0/1     Pending   0          19s   <none>   <none>   <none>           <none>

controlplane ~ ➜  kubectl describe pod nginx
Name:             nginx
Namespace:        default
Priority:         0
Service Account:  default
Node:             <none>
Labels:           <none>
Annotations:      <none>
Status:           Pending
IP:               
IPs:              <none>
Containers:
  nginx:
    Image:        nginx
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hb55w (ro)
Volumes:
  kube-api-access-hb55w:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:                      <none>

controlplane ~ ➜  kubectl get pods -n kube-system
NAME                                   READY   STATUS    RESTARTS   AGE
coredns-69f9c977-mhmrr                 1/1     Running   0          35m
coredns-69f9c977-prgmd                 1/1     Running   0          35m
etcd-controlplane                      1/1     Running   0          35m
kube-apiserver-controlplane            1/1     Running   0          36m
kube-controller-manager-controlplane   1/1     Running   0          35m
kube-proxy-5v5zd                       1/1     Running   0          35m
kube-proxy-nrhv4                       1/1     Running   0          35m
# 스케줄러가 running중이지 않은 것 확인 가능

controlplane ~ ➜  cat nginx.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: node01 # 이 부분 추가
  containers:
  -  image: nginx
     name: nginx
     
$ kubectl replace --force -f nginx.yaml # 사용하거나 지우고 recreate 하거나
controlplane ~ ➜  kubectl apply -f nginx.yaml 
pod/nginx created

controlplane ~ ➜  kubectl get pods
NAME    READY   STATUS              RESTARTS   AGE
nginx   0/1     ContainerCreating   0          6s

controlplane ~ ➜  kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          8s
# 같은 pod를 controlplane에 재할당하기.

controlplane ~ ➜  cat nginx.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: controlplane
  containers:
  -  image: nginx
     name: nginx


controlplane ~ ➜  kubectl replace --force -f nginx.yaml 
pod "nginx" deleted
pod/nginx replaced

controlplane ~ ➜  kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          38s   10.244.0.4   controlplane   <none>           <none>

 

 

Assign CPU Resources to Containers and Pods

This page shows how to assign a CPU request and a CPU limit to a container. Containers cannot use more CPU than the configured limit. Provided the system has CPU time free, a container is guaranteed to be allocated as much CPU as it requests. Before you be

kubernetes.io

1GB = 1000,000,000 bytes
1GiB =
1KiB = 1,024 bytes
1MB = 1024 kB
1MB = 1000kB
1MiB = 1024 KiB


 
 
 

# Requests

[master manifests]$ cat pod-nginx-resources.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-env
spec:
  containers:
  - name: nginx-container
    image: nginx:1.14
    ports:
    - containerPort: 80
      protocol: TCP
    resources:
      requests:
        memory: 500Mi # 스케줄링 요청
        cpu: 1

[master manifests]$ kubectl create -f pod-nginx-resources.yaml 
pod/nginx-pod-env created

[master manifests]$ kubectl get pods -o wide
NAME                  READY   STATUS    RESTARTS   AGE     IP         NODE    NOMINATED NODE   READINESS GATES
nginx-pod-env         1/1     Running   0          53s     10.5.1.5   node2   <none>           <none>
nginx-pod-env-node1   1/1     Running   0          2m18s   10.5.0.9   node1   <none>           <none>

[master manifests]$ kubectl describe pod nginx-pod-env
Name:             nginx-pod-env
...
Containers:
  nginx-container:
    Container ID:   containerd://ed82eb0fede9588dde97770122f936f3f14df82beb064f47edc527189e5da1cb
    Image:          nginx:1.14
    Image ID:       docker.io/library/nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sun, 18 Feb 2024 16:21:20 +0000
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:        1
      memory:     500Mi

# 기존 파드 삭제
[master manifests]$ kubectl delete pod --all
pod "nginx-pod-env" deleted
pod "nginx-pod-env-node1" deleted

 

# limits

#request 없이 최대 쓸 수 있는 용량 제한
[master ~]$ cat > pod-nginx-resources.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-resources
spec:
  containers:
  - name: nginx-container
    image: nginx:1.14
    ports:
    - containerPort: 80
      protocol: TCP
    resources:
      limits: # 쓸 수 있는 용량 제한
        memory: 500Mi
        cpu: 1
[master ~]$ kubectl create -f pod-nginx-resources.yaml 
pod/nginx-pod-resources created    


[master ~]$ kubectl describe pod nginx-pod-resources 
Name:             nginx-pod-resources
...
Containers:
  nginx-container:
    Container ID:   containerd://c74703db987c7f9a5b60307b01337a7b92e7edcba74ff650c9fe941a28ebc479
    Image:          nginx:1.14
    Image ID:       docker.io/library/nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 19 Feb 2024 03:00:46 +0000
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     1
      memory:  500Mi
    Requests:
      cpu:        1
      memory:     500Mi  # limit만 걸었는데 동일한 값으로 request가 들어간다.

 
✔ requests만 하면 limits가 걸리지 않지만,  limits은 requests도 걸린다.
 

# 각 워커노드의 최대 사용이 cpu 2인데, 2 core를 요청했을 때
[master ~]$ cat pod-nginx-resources.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-resources
spec:
  containers:
  - name: nginx-container
    image: nginx:1.14
    ports:
    - containerPort: 80
      protocol: TCP
    resources:
      requests: 
        memory: 500Mi
        cpu: 2
[master ~]$ kubectl create -f pod-nginx-resources.yaml 
pod/nginx-pod-resources created

[master ~]$ kubectl get pods
NAME                  READY   STATUS    RESTARTS   AGE
nginx-pod-resources   1/1     Pending   0          6s
# Pending : 스케줄링을 아직 받지 못한 상태
# OS, kubelet, 등등의 Pod가 동작중이라 CPU 2core 만큼의 여유가 없기 때문에 Pending이 된다.
# 추후 2core 할당이 가능한 노드가 생기면 바로 실행이 될 수 있다.

 

# requset, limits 둘 다 할당 시 

[master ~]$ cat pod-nginx-resources.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-resources
spec:
  containers:
  - name: nginx-container
    image: nginx:1.14
    ports:
    - containerPort: 80
      protocol: TCP
    resources:
      requests: 
        memory: 500Mi
        cpu: 200m
      limits:
        memory: 1Gi
        cpu: 1
        
[master ~]$ kubectl create -f pod-nginx-resources.yaml 
pod/nginx-pod-resources created
[master ~]$ kubectl get pods
NAME                  READY   STATUS    RESTARTS   AGE
nginx-pod-resources   1/1     Running   0          12s
[master ~]$ kubectl describe pod nginx-pod-resources 
Name:             nginx-pod-resources
...
Containers:
  nginx-container:
    Container ID:   containerd://1638afea35ca5c5a9189ecd0132ff8cf8470437f529f3b6aa6e40f8b637786f4
    Image:          nginx:1.14
    Image ID:       docker.io/library/nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 19 Feb 2024 03:12:57 +0000
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     1
      memory:  1Gi
    Requests:
      cpu:        200m
      memory:     500Mi
    Environment:  <none>

 

# Editing pods and Deployments

기존의 Pod에서는 specifcations(environment variables, service accounts, resource limits)을 edit할 수 없다.

  • spec.containers[*].image
  • spec.initContainers[*].image
  • spec.activeDeadlineSeconds
  • spec.tolerations

 

👩대안 

# command를 사용해서 YAML 포맷 추출
$ kubectl get pods webapp -o yaml > my-new-pod.yaml

# 추출된 YAML파일 수정하기
$ vi my-new-pod.yaml

# 기존의 파드 삭제 및 재생성하기.
$ kubectl delete pod webapp
$ kubectl create -f my-new-pod.yaml

 

+ Deployment 관련 Pod 템플릿은 edit할 수 있다.

change가 발생하면 자동으로 delete 및 create가 된다.

 

# 실습

$  kubectl describe pod elephant
Name:             elephant
Namespace:        default
Priority:         0
Service Account:  default
Node:             controlplane/192.28.33.3
Start Time:       Wed, 24 Apr 2024 14:19:35 +0000
Labels:           <none>
Annotations:      <none>
Status:           Running
IP:               10.42.0.10
IPs:
  IP:  10.42.0.10
Containers:
  mem-stress:
    Container ID:  containerd://205218bf2ec491766a2a136fd3b77e624cecc118614824b725be7474be5c35fd
    Image:         polinux/stress
    Image ID:      docker.io/polinux/stress@sha256:b6144f84f9c15dac80deb48d3a646b55c7043ab1d83ea0a697c09097aaad21aa
    Port:          <none>
    Host Port:     <none>
    Command:
      stress
    Args:
      --vm
      1
      --vm-bytes
      15M        # 15Mi memory를 사용하고 있다. => OOMkill 발생
      --vm-hang
      1
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       OOMKilled
      Exit Code:    1
      Started:      Wed, 24 Apr 2024 14:23:06 +0000
      Finished:     Wed, 24 Apr 2024 14:23:06 +0000
    Ready:          False
    Restart Count:  5
    Limits:
      memory:  10Mi           
    Requests:
      memory:     5Mi
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-d4k4f (ro)

20Mi 로 바꿔준다.
변경 불가능 오류가 발생한다.

$ kubectl edit pod elephant 
error: pods "elephant" is invalid
A copy of your changes has been stored to "/tmp/kubectl-edit-1916738946.yaml" # 임시파일이 저장된다.
error: Edit cancelled, no valid changes were saved.


$ kubectl replace --force -f /tmp/kubectl-edit-1916738946.yaml
pod "elephant" deleted
pod/elephant replaced

$  kubectl get pods
NAME       READY   STATUS    RESTARTS   AGE
elephant   1/1     Running   0          22s

controlplane ~ ➜  kubectl describe pod elephant 
Name:             elephant
Namespace:        default
Priority:         0
Service Account:  default
Node:             controlplane/192.28.33.3
...
    Command:
      stress
    Args:
      --vm
      1
      --vm-bytes
      15M
      --vm-hang
      1
    State:          Running
      Started:      Wed, 24 Apr 2024 14:30:08 +0000
    Ready:          True
    Restart Count:  0
    Limits:
      memory:  20Mi
    Requests:
      memory:     5Mi
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-d4k4f (ro)
반응형

'Container > Kubernetes' 카테고리의 다른 글

[K8S] ReplicationController  (0) 2024.02.19
[K8S] Pod 환경 변수 설정  (0) 2024.02.19
[K8S] pause container / Static container  (0) 2024.02.19
[K8S] init container  (0) 2024.02.18
[K8S] Liveness Probe (Self-healing) Pod  (1) 2024.02.16