[Kubernetes] # 파드 스케줄링

empty·2021년 1월 21일
0

Kubernetes

목록 보기
7/7

쿠버네티스에서는 사용자가 파드를 어떤 노드에 배포할 것인지 아래의 기능을 통해 설정할 수 있다.

  • 노드 셀렉터(NodeSelector)
  • 어피니티(Affinity)
    • 노드 어피니티(Node Affinity)
    • 파드 어피니티(Pod Affinity)
    • 안티 어피니티(Anti Affinity)
  • 테인트& 톨러레이션(Taint)
  • 커든(Cordon)
  • 드레인(Drain)

해당 기능을 자세히 알아보자.

1️⃣ 노드 셀렉터

파드의 .spec 필드에 노드셀렉터를 이용하여 어떤 노드에서 실행될지 설정한다.

  • 가장 간단한 스케줄링 옵션임
  • Key-Value 쌍으로 설정한다.

우선 노드셀렉터를 적용하려면 원하는 노드의 노드레이블에 어떤 Key-Value 쌍이 있는지 확인해야 한다. 해당 명령어로 확인할 수 있다.

> kubectl get nodes --show-lables
NAME      STATUS    ROLES    AGE     VERSION        LABELS
worker0   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker0

사용자가 원하는 노드에 노드레이블을 추가할 수도 있다.

노드에 레이블 추가

> kubectl label nodes docker-desktop disktype=ssd
node/docker-desktop labeled

> kubectl get nodes --show-lables
NAME      STATUS    ROLES    AGE     VERSION        LABELS
worker0   Ready     <none>   1d      v1.13.0        ...,**disktype=ssd**,kubernetes.io/hostname=worker0
  • worker0에 disktype=ssd을 가지는 Key-Value쌍의 레이블 추가한다.

노드셀렉터 사용예제

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd #위에서 추가한 노드레이블의 Key-Value 쌍을 입력

2️⃣ 어피니티

1. 노드 어피니티

노드 어피니티는 노드셀렉터와 비슷하게 노드의 레이블 기반으로 파드를 스케줄링한다.

노드 어피니티노드 셀렉터를 함께 설정할 수도 있는데 이때는 두개의 조건을 모두 만족해야 스케줄링한다.

노드 어피니티에는 두 가지 필드가 존재한다.

  • requiredDuringSchedulingIgnoredDuringExecution

    : 스케줄링하는 동안 꼭 필요한 조건

  • preferredDuringSchedulingIgnoredDuringExecution

    : 스케줄링하는 동안 만족하면 좋은 조건 (굳이 조건을 만족하지 않아도 된다.)

위의 두 조건으로 파드가 이미 스케줄링되어 있는 상태에서는 해당 노드의 조건이 바뀌어도 무시된다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd            
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent

operator의 필드설명

required~필드와 preferred~필드에서 설정할 수 있는 operator 필드의 설명이다.

  • In

    : .values[] 필드에 설정한 값 중 레이블에 있는 값과 일치하는 것이 하나라도 있는지 확인한다.

  • NotIn

    : In과는 반대로 .values[] 필드에 있는 값 모두와 맞지 않는지 확인한다.

  • Exists

    : .key필드에 설정한 값이 레이블에 있는지만 확인한다.

  • DoesNotExist

    : Exists와 반대로 .key 필드 값이 없는지만 확인

  • Gt (Greater than)

    : .values[] 필드에 설정된 값보다 큰 숫자형 데이터인지를 확인한다. (초과)

  • Lt (Lower than)

    : .values[] 필드에 설정된 값보다 작은 숫자형 데이터인지를 확인한다. (미만)

2. 파드 어피니티

파드 어피니티는 서로 자주 통신하는 파드들끼리 같은 노드에 속하게 만들어서 효율을 높이는 역할을 한다.

가장 흔한예로 DB나 캐시같은 서비스와 통신하는 App 컨테이너를 같은 노드에 두어서 네트워크 통신 비용을 줄인다.

3. 안티 어피니티

안티 어피니티는 CPU나 네트워크 같은 하드웨어 자원을 많이 사용하는 App 컨테이너가 있을 때 여러 노드로 파드를 분산하는 역할을 한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  selector:
    matchLabels:
      app: web-store
  replicas: 3
  template:
    metadata:
      labels:
        app: web-store
    spec:
      affinity:
        podAntiAffinity: 
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app    #----------------------------①
                operator: In
                values:
                - web-store #----------------------------②
            topologyKey: "kubernetes.io/hostname"
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app    #----------------------------③
                operator: In
                values:
                - store     #----------------------------④
            topologyKey: "kubernetes.io/hostname" #------⑤
      containers:
      - name: web-app
        image: nginx:1.16-alpine

예시 템플릿 설명

① : 안티어피니티를 설정할 label의 key값으로 app을 설정하였다.

② : ①에서 설정한 key값에 대응되는 value값으로 web-store를 설정하였다.

⇒ 즉 레이블이 app: web-store 로 설정된 파드가 속한 노드를 피해서 파드를 배포한다는 설정이다.

③ : 파드어피니티를 설정할 label의 key값으로 app을 설정하였다.

④ : ③에서 설정한 key값에 대응되는 value값으로 store를 설정하였다.

⇒ 즉 레이블이 app: store 로 설정된 파드가 속한 노드를 찾아서 함께 파드를 배포한다는 설정이다.

⑤ : topologyKey는 노드의 레이블을 이용하여 파드 어피니티와 안티 어피니티를 설정할 수 있는 또 하나의 기준이다.

  • spec.affinity 필드에 podAffinity, podAntiAffinity를 사용한다는 점 외에는 ****노드 어피니티의 설정방법과 거의 같다.

topologyKey

topologyKey는 해당 필드에 설정된 Key:(any value)의 레이블 쌍을 가지는 노드에 대해서만 균등한 분배를 한다.

  • 위의 예제에서는 kubernetes.io/hostname이 Key값에 해당한다. 즉 kubernetes.io/hostname:(any value)로 노드를 찾음.

실제 쿠버네티스 클러스터를 운영하다보면 여러가지 기준으로 스케줄링을 해야할 경우가 생기는데 topologyKey를 이용하여 스케줄링을 쉽게 설정할 수 있다.

3️⃣ 테인트 & 톨러레이션

특정 노드에 테인트를 설정할 수있는데 테인트를 설정하게된 노드에는 파드들을 스케줄링 하지 않는다.

  • 테인트를 설정한 노드에 파드들을 스케줄링 하려면 톨러레이션(toleration)을 설정해야함.

테인트와 톨러레이션은 주로 노드를 특정 역할만 하도록 만들때 자주 사용한다.

테인트는 크게 키, 값, 효과 세가지로 구성할 수 있다.

kubectl taint nodes 노드이름 키=값:효과

# kubectl taint nodes 노드이름 키=값:효과

# 노드에 테인트 설정
> kubectl taint nodes docker-desktop key01=value01:NoSchedule
node/docker-desktop tainted

# 노드의 테인트 확인 
> kubectl describe nodes docker-desktop

테인트 삭제는 아래의 명령어로 할수 있다.

kubectl taint nodes 노드이름 키=값:효과-

테인트가 설정된 노드에 파드를 실행시키려면 톨러레이션을 설정해야 한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubernetes-simple-app
  labels:
    app: kubernetes-simple-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kubernetes-simple-app
  template:
    metadata:
      labels:
        app: kubernetes-simple-app
    spec:
      containers:
      - name: kubernetes-simple-app
        image: arisu1000/simple-container-app:latest
        ports:
        - containerPort: 8080
      tolerations:
      - key: "key01"
        value: "value01"
        operator: "Equal"
        effect: “NoSchedule"
  • tolerations의 필드의 key와 value는 테인트에 설정했던 값을 적어준다.

tolerations필드 설명

톨러레이션에서 설정할수 있는 설정값에 대한 설명이다.

  • key : 테인트를 설정할 때 사용했던 key값을 적어준다.
    • 첫 문자는 영문이나 숫자로 시작해야한다.
    • 최대 253자까지 작성할 수 있다.
  • value : 테인트를 설정할 때 사용했던 value값을 적어준다.
    • 최대 63자까지 작성할 수 있다.
  • operator : 톨러레이션을 어떠한 조건에 의해 설정될 것인지 선택한다.
    • Equal : key, value, effect 필드 값이 테인트의 설정값과 모두 같은지 확인함.
    • Exists : 어떤 테인트 설정이 있든 파드를 스케줄링해서 실행한다.
  • effect : 파드를 스케줄링 할 조건을 설정한다.
    • NoSchedule : 톨러레이션 설정이 없다면 스케줄링 하지 않는다.
    • PreferNoSchedule : 톨러레이션 설정이 없다면 스케줄링 하지 않는다.
      하지만! 클러스터 안의 자원이 부족하다면 테인트를 설정한 노드에서도 파드를 스케줄링 할 수있다.
    • NoExecute : 톨러레이션 설정이 없다면 스케줄링 하지 않고 기존에 배포되어 있는 파드들도 톨러레이션 설정이 없다면 종료시킨다.

4️⃣ 커든

커든(cordon)은 특정 노드에 추가로 파드를 스케줄링하지 않게하는 명령이다.

커든 설정은 아래의 명령어로 설정할 수 있다.

kubectl cordon 노드이름

# docker-desktop노드에 커든설정
> kubectl cordon docker-desktop

# 커든이 설정되었으므로 파드는 Pending 상태로 스케줄링되지 않는다.
> kubectl scale deploy kubernetes-simple-app --replicas2

커든 설정을 제거할면 아래의 명령어로 설정할 수 있다.

kubectl uncordon 노드이름

5️⃣ 드레인

드레인(drain)은 지정된 노드에 있는 모든 파드들을 다른 노드로 이동시키는 명령이다.

  • 드레인 설정은 주로 해당 노드를 유지보수(커널 업그레이드, 하드웨어 유지 관리 등)를 하거나 Managed로 사용중인 경우는 해당 노드를 반납하고자 할 때 주로 사용한다.

드레인의 특징

  • 드레인은 기본적으로 graceful하게 파드들을 종료시킨다. (즉시 종료되는 것이 아니고 기존의 작업을 정리한 후 종료함)
  • DaemonSet으로 실행한 파드들에 드레인 설정을 하려면 --ignore-daemonsets=true 옵션과 함께 명령을 실행해야 한다.
  • 컨트롤러를 이용하지 않는 파드들에도 드레인 설정을 할 수없다. 하려면 --force 옵션과 함께 명령을 실행해야 한다.

드레인 설정은 아래의 명령어로 설정할 수 있다.

kubectl drain 노드이름

  • 드레인 설정을 한 노드의 파드들은 클러스터 안에 존재하는 노드로 스케줄링에 설정되어있는 스코어링에 따라 스케줄링된다.

0개의 댓글