이야기박스

Kubernetes. 포드의 계산 리소스 관리 본문

Computer & Data/Orchestration

Kubernetes. 포드의 계산 리소스 관리

박스님 2019. 10. 30. 13:59
반응형

# 개요

  • Resource Request & Limit
  • Pod의 request / limit
  • QoS (우선순위)
  • 플러그인 (LimitRange, ResourceQuota)
  • 모니터링

# 포드 컨테이너의 리소스 요청

포드의 리소스 request(최소) & limit(최대)은 컨테이너에서 정의

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: db
    image: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  - name: wp
    image: wordpress
    resources:
      requests:
        memory: "64Mi" <-- 메비바이트
        cpu: "250m" <-- 밀리코어
      limits:
        memory: "128Mi"
        cpu: "500m"

위 리소스 조건을 충족하는 노드에서만 Pod가 생성 가능

 

# Request

## 스케줄러 시점

노드의 개별 리소스를 보는게 아니라 노드에 배포된 기존 포드가 요청한 리소스의 합계만 봄

 

스케줄러가 포드의 요청에 응답하는 방법

  1. 스케줄러는 포드에 맞지 않는 노드 목록부터 제거
  2. 남은 노드 목록 중, 우선순위 지정 방식에 따라 결정

## 우선순위 지정 방식

LeastRequestedPriority

리소스가 많이 남아있는 노드에 배포

 

MostRequestedPriority

리소스가 적게 남아 있는 노드에 배포

  • 리소스를 균등하게 분배할 필요가 없는 클라우드 인프라 서비스 같은 곳에서 사용
  • 노드를 적게 쓰는 장점
Note. Fit 하게 리소스를 분배
예를 들어, 1000의 CPU 리소스를 가진 노드에 배포를 진행하려고 함
* A Pod : 400
* B Pod : 300
두 Pod를 배포하였고, 이후 새로운 Pod를 배포하려고 한다.
* C Pod : 300
세 Pod 리소스의 합은 1000이니까 실행이 되어야 하지만, 실제로는 안됨.
kube-system과 같은 프로세스에서 사용하고 있기 때문

반드시 C Pod를 스케줄링 하고 싶으면, A나 B Pod를 삭제하여야 함

 

* CPU 리소스 제한이 없는 경우, 남은 리소스를 Pod의 비율 만큼 나눠갖게 됨

 

 

 

# Limit

CPU보다는 Memory에 치명적, 메모리는 압축이 안되기 때문에 다른 서비스에 영향 줄 수 있음

만약 Requests를 설정하지 않으면 limit과 동일하게 설정됨

## Overcommit

Request와 다르게 Limit은 노드의 리소스에 영향받지 않음

즉, 노드 리소스보다 크게 잡는게 가능

이렇게 100% 초과하면 특정 컨테이너가 강제 종료됨

 

==> 한계초과

 

## 한계초과

주로 메모리에서 이슈가 발생. (CPU는 I/O wait 등 사용량 조절이 가능함)

빈번히 실패하면 아래 상태를 표시 (책에서는 쿠버네티스를 다시 시작한다고 나옴, 번역 오류인가?)

$ kubectl get po
NAME        READY     STATUS             RESTARTS   AGE
memoryhog   0/1       CrashLoopBackOff   3          1m

==> CrashLoopBackoff이 Pod를 포기한걸 의미하는게 아니라, 재시작을 시도하는 대기시간이 길어졌다는걸 의미.

20, 40, 80.. 이런식으로 배수로 늘어나다가 최대 300초로 설정됨.

 

원인 분석

$ kubectl describe pod
Name:       memoryhog
...
Containers:
  main:
    ...
    State:          Terminated
      Reason:       OOMKilled
      Exit Code:    137
      Started:      Tue, 27 Dec 2016 14:55:53 +0100
      Finished:     Tue, 27 Dec 2016 14:55:58 +0100
    Last State:     Terminated
      Reason:       OOMKilled
      Exit Code:    137
      Started:      Tue, 27 Dec 2016 14:55:37 +0100
      Finished:     Tue, 27 Dec 2016 14:55:50 +0100
    Ready:          False
...

OOMKilled => 메모리가 부족해 종료

Note. Pod 종료
OOMKilled 이외에도 리소스가 부족하여 프로세스를 강제 종료시키는 경우가 있음.
뒤 QoS 파트에서 다시 설명

 

## 컨테이너 top

컨테이너는 항상 노드 전체의 메모리를 봄.

컨테이너가 사용 가능한 메모리 양의 한계를 설정해도 컨테이너는 이 한계를 인식하지 못함.

 

자바 애플리케이션 사용할 때, -Xmx 옵션을 사용해 힙을 지정하지 않으면 문제가 발생.

JVM에서 호스트의 총 메모리를 기반으로 동작하기 때문

단, -Xmx 옵션도 자바 off heap에는 영향을 주지 못함

 

마찬가지로 CPU도 영향이 있을 수 있음

예를들어 CPU나 메모리 리소스를 검색하여 실행하는 애플리케이션을 가정.

컨테이너에 제한된 리소스만 보는게 아니라 전체 리소스를 검색하게 될 것임

==> 치명적인 문제가 될 수도 있음

 

대안

  • Downward API 사용 --> 컨테이너에 리소스 한계 전달
  • cgroups 시스템에서 정보를 얻어올 것

# QoS

포드에 대하여 3가지 Qos 클래스 분류

  • BestEffort (최하위 우선순위)
  • Burstable (버스트 가능)
  • Guranteed (최우선)

포드에 Qos 정의는 메니페스트 파일로 하는게 아니라, 리소스 Request + Limit 조합으로 파생됨

 

## BestEffort

우선순위가 가장 낮은 클래스

Request, Limit 모두 설정되지 않은 경우

단, 리소스가 충분하면 마음껏 쓸 수 있음 (다른 포드가 없다면)

 

## Guranteed

리소스 Request = Limit (둘 다 반드시 설정되어야 함)

각 컨테이너마다 설정

 

## Burstable

위 두 개를 제외한 나머지 케이스가 속함

## 다수의 컨테이너를 포함한 포드의 QoS

컨테이너 간의 클래스가 동일 한 경우 --> Pod의 클래스가 됨

컨테이너 간의 클래스가 다른 경우 --> Burstable

 

## 종료

앞에서 나왔던 OOMKilled 이외에 프로세스가 강제 종료되는 케이스

기본적으로 BestEffort --> Burstable --> Guranteed 순서로 종료.

 

만약 동일한 클래스를 가진다면?

OOM 점수를 토대로 종료

Note. OOM 점수의 계산
1. 가용 메모리 비율
2. 고정된 OOM 점수 조정

가용 메모리 = Pod의 사용중인 메모리 / 한계 메모리 * 100 %

 

# Plugin 1. LimitRange

Namespace 단위로 리소스 Request/Limit 지정하는 것

 

## 생성

apiVersion: v1
kind: LimitRange
metadata:
  name: example
spec:
  limits:
  - type: Pod
    min:
      cpu: 50m
      memory: 5Mi
    max:
      cpu: 1
      memory: 1Gi
  - type: Container
    defaultRequest:
      cpu: 100m
      memory: 10Mi
    default:
      cpu: 200m
      memory: 100Mi
    min:
      cpu: 50m
      memory: 5Mi
    max:
      cpu: 1
      memory: 1Gi
    maxLimitRequestRatio:
      cpu: 4
      memory: 10
  - type: PersistentVolumeClaim
    min:
      storage: 1Gi
    max:
      storage: 10Gi

 

# Plugin2. ResourceQuota

k8s 플러그인 중 하나

네임스페이스에서 사용할 수 있는 총 리소스 양을 제한하는 방법

 

## 생성

apiVersion: v1
kind: ResourceQuota
metadata:
  name: cpu-and-mem
spec:
  hard:
    requests.cpu: 400m
    requests.memory: 200Mi
    limits.cpu: 600m
    limits.memory: 500Mi

LimitRange와 같이 네임스페이스에 적용되지만, ResourceQuota는 개별 포드에 적용되지는 않는다.

 

## Persistent Storage

apiVersion: v1
kind: ResourceQuota
metadata:
  name: storage
spec:
  hard:
    requests.storage: 500Gi
    ssd.storageclass.storage.k8s.io/requests.storage: 300Gi
    standard.storageclass.storage.k8s.io/requests.storage: 1Ti

쿠버네티스는 동적 PV 요청도 받을 수 있도록, 개별 할당량 정의할 수 있도록 구성되어 있음

 

## 객체 수 제한

리소스 뿐 아니라, 객체 수 제한도 가능함

apiVersion: v1
kind: ResourceQuota
metadata:
  name: objects
spec:
  hard:
    pods: 10
    replicationcontrollers: 5
    secrets: 10
    configmaps: 10
    persistentvolumeclaims: 4
    services: 5
    services.loadbalancers: 1
    services.nodeports: 2
    ssd.storageclass.storage.k8s.io/persistentvolumeclaims: 2

 

## 특정 Scope의 할당량 지정

apiVersion: v1
kind: ResourceQuota
metadata:
  name: besteffort-notterminating-pods
spec:
  scopes:
  - BestEffort
  - NotTerminating
  hard:
    pods: 4

QoS 또는 파드의 상태를 통해서 ResourceQuota의 범위를 지정할 수 있음.

 

# 모니터링

Kubelet은 cAdvisor라는 에이전트를 포함하고 있음. 이 에이전트를 통하여 노드 전체의 리소스 소비 데이터를 수집함.

이후, 전체 클러스터의 통계를 중앙에서 수집하기 위하여 "힙스터"라는 컴포넌트가 필요

힙스터는 노드 중 하나에서 포드 형태로 실행되며, IP 형태로 접근 가능

 

 

## 실제 사용 조회

$ kubectl top node
NAME       CPU(cores)   CPU%      MEMORY(bytes)   MEMORY%
minikube   170m         8%        556Mi           27%
$ kubectl top pod --all-namespaces
NAMESPACE      NAME                             CPU(cores)   MEMORY(bytes)
kube-system    influxdb-grafana-2r2w9           1m           32Mi
kube-system    heapster-40j6d                   0m           18Mi
default        kubia-3773182134-63bmb           0m           9Mi
kube-system    kube-dns-v20-z0hq6               1m           11Mi
kube-system    kubernetes-dashboard-r53mc       0m           14Mi
kube-system    kube-addon-manager-minikube      7m           33Mi

 

## 에러 메시지

$ kubectl top pod
W0312 22:12:58.021885   15126 top_pod.go:186] Metrics not available for pod default/kubia-3773182134-63bmb, age: 1h24m19.021873823s
error: Metrics not available for pod default/kubia-3773182134-63bmb, age: 1h24m19.021873823s

이거 발생한 경우, 잠시 기다렸다가 다시 시도 (몇분)

 

## Grafana

influxDB를 이용

 

등록된 그라파나 클러스트 등록을 확인하려면

$ kubectl cluster-info
...
monitoring-grafana is running at
     https://192.168.99.100:8443/api/v1/proxy/namespaces/kube-
     system/services/monitoring-grafana

 

반응형