본문 바로가기
킷도우의 클라우드, 쿠버네티스/CKA 자격증

[CKA 자격증 준비] 쿠버네티스 핵심 개념 3탄(kubectl 명령어 위주 정리, kubectl 명령어 모음집) - kubernetes Scheduling

by 킷도우 2024. 1. 19.
반응형

안녕하세요. IT 윈도우 킷도우입니다.

CKA 자격증 준비 2탄 쿠버네티스 클러스터에 이어서 계속해서 3탄 Scheduling에 대해서 알아보겠습니다.

 

본 내용은 CKA 강의로 유명한 Udemy CKA with practice tests의 내용을 토대로 정리한 것입니다.

 

kube-scheduler는 파드를 어떤 노드에 할당할지 결정하는 주체이다. 만약 이 kube-scheduler가 없다면 어떻게 수동으로 파드를 배포할 수 있을까? 바로 아래와 같이 nodeName 속성을 추가해 주면 된다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 8080
  nodeName: node1 // 원래는 스케줄러에 의해 자동할당되는 영역임.

 

이렇게 하고 파드를 생성하면 내가 지정한 노드에 파드를 생성할 수 있다. 

 

Taints & Tolerations

Taints는 더러운 가스, 때를 NODE에 묻힌다고 생가하면 된다. NODE에 설정하는 값이다. Toleration은 Taints(가스, 때) 설정을 감수,인내하겠다는 의미로 보면된다. POD에 설정하는 값이다.

 

Taint를 노드에 설정하는 방법은 아래와 같다.

kubectl taint nodes node1 app=value:taint-effect

여기서 taint-effect의 종류는 아래와 같이 3가지가 있다.

1. NoSchedule: 파드를 노드에 올릴 예정이 없다는 뜻

2. PreferNoSchedule: 파드에 노드를 올리지 않는 것을 선호하나 보장할 수 없다는 뜻

3. NoExecute: 파드를 노드에 배치할 수 없고, 노드 내부에 해당 파드가 있다면 퇴거해야한다는 뜻

 

Taint를 노드에서 제거하는 방법은 아래와 같다.

kubectl taint nodes node1 key1=value1:NoSchedule- 
# '-' 문자를 마지막에 명시해주면 제거된다

 

Toleration을 POD에 설정하는 방법은 아래와 같다.

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx
  tolerations:
  - key: app
    operator: "Equal"
    value: blue
    effect: NoSchedule

 

 이렇게 파드를 설정한다고 반드시 Taint 설정이 있는 노드로 가라는 뜻은 아니다. 다른 노드로도 배치할 수 있다. 다만 node01의 경우만 해당 toleration 설정이 있는 파드만 받아드릴 수 있는 것 뿐이다.

kube-scheduler는 마스터 노드의 어떤 파드에도 스케줄링하지 못한다. 바로 k8s cluster를 구축하면서, 마스터 노드에 테인트 설정이 자동으로 설정 돼기 때문이다.

 

Node Selector

Node Selector는 하드웨어적으로 적절한 리소스의 노드로 알맞게 최적화된 사이즈의 파드가 노드에 안착하도록 합니다.

pod-definition.yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers
  - name: data-processor
    image: data-processor
  nodeSelector
    size: Large # 여기서 size: Large는 Node에 선언한 Label을 의미한다.

 

Node에 어떻게 라벨링을할까?

kubectl label nodes node01 size=Large
#kubectl label nodes <node-name> <label-key>=<label-value>

 

 

하지만 이러한 선언에는 한계가 있다. 예를들어 Not small 한곳에 파드를 배치해야하는 요구사항이 있다면 어떻게 될까?

여기서 Node Affinity의 개념이 등장한다.

 

Node Affinity

Node Affinity 의 목적은 파드가 특정 노드에 호스트될 수 있도록 돕는다. 복잡한 설정을 모두 지원하는 만큼 설정하는 것도 다소 복잡하다. Node가 Large인 곳에 파드를 넣고 싶은 경우 아래와 같이 설정한다.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: data-processor
    image: data-processor
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: size
            operator: In
            values:
            - Large

 

Node가 Large이자 Medium인 곳에 파드를 할당하고 싶을 경우 아래와 같이 할당한다.

kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: data-processor
    image: data-processor
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: size
            operator: In
            values:
            - Large
            - Medium

 

Node가 Small이 아닌 곳에 파드를 할당하고 싶을 경우 아래와 같이 할당한다.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: data-processor
    image: data-processor
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: size
            operator: Not In
            values:
            - Small

 

해당 Node에 Key값이 존재하는지 여부에 따라 할당하고 싶다면?

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: data-processor
    image: data-processor
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: size
            operator: Exists

 

Node Affinity Types

- requiredDuringSchedulingIgnoredDuringExecution : 파드가 생성될 때 적용되는 RULE,  이미 실행중이면  적용 안됨

- preferredDuringSchedulingIgnoredDuringExecution : 파드가 생성될 때 적용되는 RULE,  이미 실행중이면  적용 안됨  

여기서 preferred는 nodeAffinity규칙에 맞는게 있으면 해당 노드에 할당하지만, 없다면 아무데나 넣으라는 의미이다.

만약 실행중인 파드에 적용하고 싶다면 아래 Type을 적용한다.

Planed : 

  requiredDuringSchdulingRequiredDuringExecution

 

마지막으로,

Combination with 'Taints and Tolerations' and 'Node Affinity'

위 두가지를 활용해 정확히 파드를 어떤 노드에 배치할지를 완벽히 통제할 수 있다.

 

Resource Requirements

 kube-scheduler는 파드가 갈 노드를 결정한다. 파드에 요구되는 리소스양을 고려한다. 여기서 리소스는 노드에서 사용 가능한 리소스를 의미한다. 그리고 포드를 설치할 최적의 노드를 찾는다.

 kube-scheduler는 만약 파드를 할당하려는 노드에 cpu/ram 이 충분하지 않고 full 상태라면 해당 노드에 파드를 두는 것을 피하고 대신 충분한 리소스가 사용 가능한 곳에 파드를 배치시킨다. 만약 모든 노드의 리소스가 full이라면 새로운 파드의 생성 일정을 억제한다.

컨테이너에 cpu/mem 할당량을 아래와 같이 지정할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: simple-webapp-color
  labels:
    name: simple-webapp-color
spec:
  containers:
  - name: simple-webapp-color
    image: simple-webapp-color
    ports:
    - containerPort: 8080
    resources:
      requests:
        memory: "1Gi"
        cpu: 1
      limits:
        memory: "2Gi"
        cpu: 2

 

반응형

여기서 만약 제한한 자원을 초과하는 일이 발생하면 어떻게될까?

컨테이너는 CPU 리소스를 쓸 수 없게된다. 메모리는 OUT OF MEMORY 에러가 나게 된다. 따라서 이상적으로는 limit을 안해두는게 좋다.

만약 limit을 반드시 해야하는 상황이라면 LimitRange 개체를 쓴다. 모든 컨테이너에 적용된다.

apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-resource-constraint
spec:
  limits:
  - default:
      cpu: 500m
    defaultRequest:
      cpu: 500m
    max:
      cpu: "1"
    min:
      cpu: 100m
    type: Container

 

이것은 컨테이너에 적용하는 제한이다. 네임스페이스 차원에서 제한하고 싶을 경우 ResourceQuota 개체를 이용한다.

resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: my-resource-quota
spec:
  hard:
    requests.cpu: 4
    requests.memory: 4Gi
    limits.cpu: 10
    limits.memory: 10Gi

 

Daemonsets

Replicaset과 유사하나, 차이점은 노드마다 파드를 하나씩 실행시키는 특징을 가진다. 클러스터에 새 노드가 추가될 때마다 파드 복제본이 자동으로 해당 노드에 추가된다. 노드가 제거되면 마찬가지로 해당 노드에 있는 파드도 제거된다. 선언하는 방법은 아래와 같다.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: monitoring-daemon
spec:
  selector:
    matchLabels:
      app: monitoring-agent
  template:
    metadata: 
      app:monitoring-agent
    spec:
      containers
      - name: monitoring-agent
        image: monitoring-agent

 

Static Pod

kube-apiserver의 개입없이 kubelet이 단독으로 만들어낸 파드이다. 따라서 이 파드는 레플리카셋이나 디플로이먼트로 만들 수 없다. yaml 파일을 임의로 만들어서 생성하지 않는다. /etc/kubernetes/manifests 에 yaml파일이 위치하고 해당 yaml에서 설정을 변경해줘야한다. application이 다운되도 kubelet이 다시 살린다.

 

Deamonset vs Static Pod

Kubelet -> Deamonset으로 만듦

kube-apiserver, kube-scheduler 등 controlplane pod들 -> StaticPod로 만듦

 

Normal Pod vs Static Pod

Pod의 이름 끝에 node이름이 자동으로 할당된다. Pod의 속성 중 ownerReferences 속성에 Kind: Node라면 Static Pod라고 한다.

 

Static Pod의 정의 위치

1. /etc/kubernetes/manifests 에 정의됐는지 본다.

2. /var/lib/kubelet/config.yml 의 staticpodpath를 본다.

 

Scheduler profile

여러 개의 파드가 scheduler에 의해서 노드에 배치되는 과정을 면밀히 살펴보자.

1. 우선 순위 정하기

아래와 같이 prirority class를 만든다.

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for XYZ service pods only"

 

파드는 아래와 같이 선언한다.

apiVersion: v1
kind: Pod
metadata:
  name: simple-webapp-color
spec:
  priorityClassName: high-priority
  containers:
  - name: simple-webapp-color
    image: simple-webapp-color
    resource:
      requests:
        memory: "1Gi"
        cpu: 10

 

2. 필터링하기

우선순위로 POD를 나열한 뒤 NODE에 들어갈 수 있는 것들과 없는 것들을 필터링한다. resource 크기로 필터링할 수 있다. 

ex) cpu가 10보다 작은 노드는 스케줄링 대상에서 제외시키는 것이다.

 

3. 점수 매기기

파드를 할당하기에 좀 더 적합한 노드가 높은 점수를 얻게 된다.

ex) cpu가 10보다 크면서 가장 작은 노드가 적합하겠다.

 

4. Binding

점수가 높은 노드로 바인딩된다.

Scheduling Quere  PrioritySort          
Filtering NodeResourcesFit NodeName NodeUnschedulable
  노드 필터링 해당 노드로가도록 unschedulable true명 해당 설정된 노드를 필터링한다. 난 필터링해줘! 이거다
Scoring NodeResourcesFit ImageLocality    
Binding DefaultBinder          

 

 

Multi Scheduler

스케줄러마다 각자 자기의 기준이 있다. 여러개의 스케줄을 만들고 이를 멀티로 구성함으로써, 단독으로 스케줄러를 구성했을 때 발생하는 동시성 이슈, 작업 충돌들을 해결한다.

아래와 같은 예제를 만든다.

#my-scheduler-config.yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler
#my-scheduler-2-config.yaml
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: my-scheduler-2

...

multi scheduler 만들기

apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerCoonfiguration
profiles:
- schedulerName: my-scheduler-2
  plugins:
    score:
      disabled:
      - name: TaintToleration
      enabled:
      - name: MyCustomPluginA
      - name: MyCustomPluginB
- schedulerName: my-scheduelr-3
  plugins:
    preScore:
      disabled:
        - name: '*'
    score:
      disabled:
      - name: '*'
- schedulerName: my-scheduler-4

 

멀티 스케줄링을 구성하는 것은 다소 개념이 복잡한 것 같다. 개인적으로 좀 더 실습이 필요할 것 같습니다.

 

★킷도우 웹 개발 기초 강의가 오픈됐습니다!

궁금하신 분들은 아래 링크를 참고해 주세요~

https://kitdow.tistory.com/31

 

킷도우의 첫 강의! - 웹 개발 기초 (프론트엔드, 백엔드, DB까지 총 10시간에 걸쳐 주문 게시판 만

안녕하세요. IT Window 킷도우입니다. 드디어 고대하고 고대하던 웹 개발 강의를 완성했습니다. VOD(동영상)는 인프런에서만!(전자책 포함) https://inf.run/BqmE 실무 환경 그대로 주문게시판 만들기 웹

kitdow.tistory.com

감사합니다! 

반응형

댓글