카테고리 없음

NodeSelector를 이용한 Pod Scheduling

pioneerxj 2023. 9. 1. 22:04

Kubernetes Pod Scheduling은 Controlplane node에서 파드 생성을 요청했을때

파드를 적정 노드에 배치하는 것이다.

파드를 어느 노드에 배치할 것인가에 대한 고려사항에는

파드를 생성하기 위한 충분한 리소스(CPU, Memory, Disk)가 있는지

디스크 볼륨을 사용할 경우 attach하려는 디스크 볼륨이 해당 노드에 접근이 가능한지

고려해야한다.

 

파드 생성이 요청되면, 쿠베네티스 스케줄러는 필터를 이용해서

파드가 배포될 수 있는 노드를 고르는 작업을 하며 크게 세 종류의 필터를 사용한다.

  • 볼륨필터
  • 리소스 필터
  • 토폴로지 필터

 

1. 볼륨 필터는 파드가 생성되려는 노드의 디스크 볼륨이 마운트가 될 수 있는지 확인한다.

클라우드를 이용할 경우, 충돌을 일으키지 않고 attach할 수 있는지 확인한다.

Node Affinity를 이용하여 특정 노드에만 지정하는 볼륨 토폴로지 제한이 있는지 확인한다.

 

2. 리소스 필터는 파드를 배포할 수 있는 충분한 리소스(CPU, Memory, Disk)를 가지고 있는지 확인하고

네트워크 포트도 체크한다.

생성하려는 파드에서 노드의 8080 포트를 사용할 경우 이미 노드에서 8080포트를 사용한다면

파드는 해당 노드에서 생성되지 않고 제외된다.

 

3. 토폴로지 필터는 파드가 해당 노드에서 실행될 수 있는지 확인한다.

파드의 Node Selector와 노드의 label이 매치 되는지, taint가 있는 노드에 파드가 tolerate되는지 확인한다.

 

Kubernetes Pod Scheduling에는

아래의 3가지 방법이 있다.

  1. NodeSelector와 Affinity & Anti affinity 
  2. Taint & Toleration 
  3. Cordon & Drain

그 중 NodeSelector와 Affinity & Anti affinity에 대해 알아본다.

 

NodeSelector는 파드가 어떤 노드에서 실행 될지 key-value 형태로 설정하는 방법이다.

해당 파드가 생성되려면 노드에 label을 생성해주어야 한다.

 

$ kubectl label node node01 disktype=nvm2
$ kubectl get nodes --show-labels

$ vi nodeselector.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeSelector:
    disktype: nvm2
  containers:
  - name: nginx-nodeselector
    image: nginx
    ports:
    - containerPort: 8080
$ kubectl apply -f nodeselector.yaml
$ kubectl get pods -o wide

Label 삭제하기

$ kubectl label node node01 disktype-

 

deployment

$ kubectl label node node02 disk=ssd
$ vi deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      nodeSelector:
        disk: ssd
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
$ kubectl apply -f deploy-nginx.yaml
$ kubectl get pods -o wide

spec.selector.matchLabels spec.template.metadata.labels 안에 앱은 엔진엑스라는 레이블이 보인다.

이것은 노드의 레이블이 아니라 파드에 레이블을 설정하는 것이다.

selector app: nginx 레이블을 사용하여 nginx-deployment가 관리하는 파드를 식별하고 관리한다.

  • template은 Deployment가 파드를 생성할 때 사용할 파드 템플릿을 정의한다.
  • metadata 아래의 labels 필드는 파드 템플릿에 적용되는 레이블을 정의한다.
  • template은 app: nginx 레이블을 가진 파드를 생성하며, 이 레이블을 가진 파드는 selector에 의해 관리된다.
  • 이것은 nginx-deployment가 생성하는 파드들이 app: nginx 레이블을 가지도록 하는 것이다.

 

Affinity & Anti-affinity

Node Affinity 

nodeSelector와 같이 Label이 있는 노드에 파드를 생성한다.

  • Anffinity : 조건에 맞는 곳에 배치 (서로 통신이 많은 Pod들은 같은 node에 배치)
  • Anti-affinity : 조건에 반대되는 곳에 배치 (CPU나 네트워크 같은 하드웨어 자원을 많이 소모하는 컨테이너를 여러 노드에 분산)

 

Node Affinity 생성하기

$ kubectl label nodes node01 core=4
$ kubectl label nodes node02 core=8
$ kubectl label nodes node02 disktype=ssd
$ kubectl label nodes node01 disktype=ssd
$ vi node-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nodeaffinity-pod
spec:
  containers:
  - name: nodeaffinity-pod
    image: nginx
    ports:
    - containerPort: 8080
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/os
            operator: In
            values:
            - linux
          - key: disktype
            operator: Exists
          - key: core
            operator: Gt
            values:
            - "5"
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 9
        preference:
          matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - node01.example.com
$ kubectl apply -f node-affinity.yaml
$ kubectl get pods -o wide

requiredDuringSchedulingIgnoredDuringExecution: 강제라는 의미로 반드시 규칙을 충족해야 한다.

preferredDuringSchedulingIgnoredDuringExecution: 충족되는 조건이 있을때 우선 적용하지만 조건이 없을 경우에도 적용이 된다.

 

require 구문의 Gt : Greater than의 의미로 value의 5보다는 커야한다는 의미

Lt: Less than

 

Pod Anti-affinity

$ vi pod-anti-affinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: store
  replicas: 3
  template:
    metadata:
      labels:
        app: store
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: redis-server
        image: redis:3.2-alpine
        
$ kubectl apply -f pod-anti-affinity.yaml
$ kubectl get deploy -o wide
$ kubectl get pods -o wide

파드의 label이 "app=store" 으로 배포된 Pod가 없는 Node에 배포한다.

레플리카셋을 3개로 정했는데 처음 두 노드에는 Pod의 label이 "app=store"로 되어있는 파드가 없기 때문에 생성이 되고

나머지 하나는 중복되므로 파드가 Pending 상태로 남는다.

 

spec.template.spec.affinity 안에 podAntiAffinity와 podAffinity를 동시에 쓸 수 있다.

$ vi web-server.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  selector:
    matchLabels:
      app: web-store
  replicas: 2
  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.12-alpine
$ kubectl apply -f web-server.yaml
$ kubectl get pods