[kubernetes] 쿠버네티스 패턴 - 자동 배치 -2

박원균·2021년 11월 20일
0

Kubernetes

목록 보기
19/24
post-thumbnail

해결

스케줄링 프로세스

파드는 배치 정책에 따라 특정 용량을 가진 노드에 할당됩니다.

위 사진은 파드가 스케줄링될 때 거치는 주요 단계가 무엇인지를 보여줍니다.

노드에 할당되지 않은 파드가 생성되는 즉시, 곧바로 스케줄러는 할당 가능한 모든 노드 그리고 필터링 정택과 우선순위 정책 세트와 함께 해당 파드를 선택합니다.

  1. 스케줄러는 필터링 정책을 적용하고 파드 조건에 기초해 자격 없는 모든 노드를 제거합니다.
  2. 남은 노드는 가중치에 의해 정렬됩니다.
  3. 스케줄링 프로세스의 주요 결과인 파드가 노드에 할당됩니다.

대부분의 경우 파드부터 노드까지의 할당 작업은 스케줄러에 맡기는 것이 좋으며, 배치로직을 세세하게 관리하지 않는 편이 좋습니다. 그러나 일부 경우에서는 파드를 특정 노드나 노드그룹에 강제로 할당하길 원하는 수 있습니다. 이러한 할당은 노드 셀렉터를 사용해 수행할 수 있습니다.

.spec.nodeSelector는 파드의 필드로서, 파드 실행에 적합한 노드가 되도록 노드에 레이블로 존재하는 키-값 쌍의 맵이 지정되어 있어야 합니다.

아래의 yaml파일은 SSD 스토리지를 갖는 노드에 파드를 강제로 실행시키려 합니다

apiVersion: v1
kind: Pod
metadata:
  name: random-generator
spec:
  containers:
    - image: k8spatterns/random-generator:1.0
      name: random-generator
  nodeSelector:
    disktype: ssd # 노드가 이 파드의 노드로 간주되기 위해 반드시 일치해야 하는 노드 레이블 세트

노드에 사용자 정의 레이블을 지정하는 것 외에도 모든 노드에 일부 기본 레이블을 이용할 수 있습니다. 모든 노드는 고유한 kubernetes.io/hostname 레이블을 갖고 있으며 파드를 호스트명으로 노드에 배치할 때 사용할 수 있습니다. OS와 아키텍처, 인스턴스 타입을 나타내는 또 다른 기본 레이블도 배치에 유용하게 사용될 수 있습니다.

노드 어피니티

노드 어피니티는 강력한 스케줄링 방법이므로 nodeSelector로는 충분하지 않을 때 선택해야합니다.

노드 어피니티(node affinity)
파드가 노드와 얼마만큼 친밀감이 있느냐는 의미로, 파드를 스케줄링할 때 노드를 선택하는 방법입니다.

노드 셀렉터 접근 방식을 일반화 하는 것으로 필수 혹은 선호라는 규칙을 지정할 수 있습니다.

  • 필수 규칙은 파드가 노드에 스케줄링되기 위해서 반드시 충족되어야 합니다.
  • 선호 규칙은 반드시 충족되어야 하는 것은 아니며 일치하는 노드의 가중치를 증가시켜 노드가 선택되게 합니다.

아래와 같은 연산자를 활용하여 표현 가능한 제약조건의 종류를 확장시킵니다.

  • In
  • NotIn
  • Exists
  • DoesNotExist
  • Gt
  • Lt
apiVersion: v1
kind: Pod
metadata:
  name: random-generator
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      # 스케줄링 프로세스에서 고려해야 할 노드에 3개가 넘는 코어(노드 레이블에 표시된)가 있어야 한다는 엄격한 요구사항입니다.
      # 노드의 조건이 변경되어도 스케줄링 동안에 이 규칙이 재적용 되지 않습니다.
        nodeSelectorTerms:
          - matchExpressions: # 레이블과 일치할 때
            - key: numberCores
              operator: Gt
              values: ["3"]
     preferredDuringSchedulingIgnoredDuringExecution:
     # 유연한 요구사항, 가중치를 갖는 셀렉터의 목록입니다. 모든 노드에 대해 일치하는 셀렉터들의 모든 가중치 합계를 계산합니다.
     # 엄격한 요구사항과 일치하는 한, 값이 가장 큰 노드가 선택됩니다.
       - weight: 1
         preference:
           matchFields:	# 필드와 일치합니다. 연산자로 In과 NotIn만 사용 가능하며 값 목록에는 하나의 값만 허용합니다.
             - key: metadata.name
               operator: NotIn
               values: ["master"]
  contaimers:
    - image: k8spatterns/random-generator:1.0
      name: random-generator

파드 어피니티와 파드 안티어피니티

노드 어피니티는 레이블이나 필드 일치를 기반으로 파드가 실행할 수 있는 노드를 제한합니다. 또한 하나의 파드가 또 다른 파드의 상대적 위치를 지정하는 파드 간의 의존성을 표한할 수 없습니다.

고가용성을 위해 파드를 분산시키는 방법을 표현하거나, 지연 시간 개선을 위해 파드를 함께 포잘하고 배치하는 방법을 표현하기 위해서, 파드 어피니티와 파드 안티어피니티를 사용합니다.

노드 어피티니는 노드 세분성으로 작동하지만, 파드 어피니티는 노드로 제한되지 않고 다중 토폴리지 레벨에서 규칙을 표현할 수 있습니다.

아래의 yaml에서 보듯 topologyKey 필드와 일치하는 레이블을 사용하면 노드, 랙, 클라우드 제공회사 존, 리전 같은 도메인 규칙과 결합시켜서 더 세분화된 규칙을 적용 시킬 수 있습니다.

apiVersion: v1
kind: Pod
metadata:
  name: random-generator
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      # 대상 노드에서 실행 중인 또 다른 파드와 관련된 파드 배치에 대해 필수 규칙입니다.
        - labelSelector:
        # 합께 배치할 파드를 찾기 위한 레이블 셀렉터 입니다.
            matchLabels:
              confidential: high
          topologyKey: security-zone
          # confidentail=high 레이블을 가진 파드가 실행 중인 노드는 security-zone 레이블이 있어야합니다.
          # 여기에 정의된 파드는 동일한 레이블과 값을 갖는 노드에 스케줄링됩니다.
    podAntiAffinity:
    # 파드가 배치되어서는 안되는 노드를 찾기 위한 안티어피니티 규칙입니다.
      preferredDuringSchedulingIgnoredDuringExecution:
      # 이 파드가 confidential=none 레이블을 가진 파드가 실행 중인 노드에 배치되어서는 안됩니다.(절대적은 아닙니다)
        - weight: 100
          podAffinityTerm:
            labelSelector:
              matchLabels:
                confidential: none
            topologyKey: kubernetes.io/hostname
  containers:
  - image: k8spatterns/random-generator:1.0
    name: random-generator

파드 안티어피니티 규칙은 여러 파드가 동일한 노드에 시행되어서는 안 된다는 규칙입니다.

IgnoreDuringExecution 접미어는 향후 확장성을 위한 것입니다. 현재는 노드의 레이블이 바뀌고 어피니티 규칙이 더 이상 유효하지 않다면 파드가 계속 실행은 되지만 향후에는 런타임으로 변경되는 것도 고려 대상입니다.

테인트와 톨러레이션

노드 어피니티는 파드가 노드를 선택할 수 있는 속성인 반면 테인트톨러레이션은 그 반대입니다.

테인트와 톨러레이션은 파드가 스케줄되어야 하는지 혹은 스케줄되지 말아야 하는지를 노드가 제어하게 허용합니다.

테인트는 노드의 특성으로서 노드에 이 값이 존재할 때 파드가 테인트에 대한 톨러레이션이 없다면 해당 노드에 스케줄링될 수 없습니다. 그런 의미에서 테인트와 톨러레이션은 기본적으로 스케줄링에는 사용할 수 없는 노드에 스케줄링을 허용하는 옵트인이라고 할 수 있습니다.

반면에 어피니티 규칙은 실행할 노드를 명시적으로 선택하여 선택되지 않은 노드를 모두 제외하는 옵트아웃 입니다.

테인트는 kubectl: kubectl taint nodes master node-role.kubernetes.io/master="true": NoSchedule를 사용해 노드에 추가됩니다.

# taint 예시
apiVersion: v1
kind: Node
metadata:
  name: master
spec:
  taints:	
  # 파드가 이 테인트를 톨러에시녀한 경우를 제외하고는 해당 노드에 스케줄링이 불가능하다고 표시하기 위해
  # 노드의 명세에 테인트를 지정합니다.
    - effect: NoSchedule
      key: node-role.kubernetes.io/master
# tolerations 예시
apiVersion: v1
kind: Pod
metadata:
  name: random-generator
spec:
  continers:
  - image: k8spatterns/random-generator:1.0
    name: random-generator
  tolerations:
  - key: node-role.kubernetes.io/master
  # node-role.kubernetes.io/master 키로 테이트된 노드를 톨러레이션합니다.
  # 운영 클러스터에서는 마스터로 파드가 스케줄링되는 것을 막기 위해 마스터 노드에 테인트를 설정하지만 
  # 톨러레이션은 이 파드가 마스터에 스케줄링 될 수 있게 허용합니다.
    operator: Exists
    effect: NoSchedule
  • hard taint : effect=NoSchedule
    노드에 스케줄링을 금지
  • soft taint : effect=PreferNoSchedule
    가능한 한 노드에 스케줄링을 피함
  • taint : effect=NoExecute
    이미 실행중인 파드를 노드로부터 축출

테인트와 톨러레이션은 독점적인 파드 세트를 전용 노드에 배치하는 등의 복장한 사용 예를 허용하거나 문제가 있는 노드에 테인트를 지정해 이 노드에 실행 중인 파드를 강제로 축출할 수 도 있습니다.

애플리케이션의 고가용성과 성능 요구사항에 기초해 배치에 영향을 줄 수는 있지만 스케줄러에 많은 제약을 가해서 파드가 더 이상 스케줄링 되지 못하고 자원을 너무 많이 남겨지는 상황에는 이르지 않도록 조심해야합니다.

다른 컨테이너를 배치할 더 이상의 CPU가 남아 있진 않기 대문에 사용할 수 없는 4GB 메모리가 노드 A에 남겨진 상황을 볼 수 있습니다. 자원 요구사항을 줄여서 컨테이너를 생성하면 이 상황을 개선할 수 있습니다. 또 다른 방법으로는 쿠버네티스 디스케줄러를 사용해 노드 조각 모듬을 수행하고 활용도를 향상 시키는 방법이 있습니다.

일단 파드가 노드에 할당되면 스케줄러 작업은 완료된 것이며 노드의 추가 없이 파드가 삭제 되어 다시 생성되지 않는다면 파드의 배치는 변경되지 않습니다.

잠재적인 문제는 스케줄러의 결정은 새로운 파드가 스케줄링되는 그 시점의 클러스터에 기초한다는 것입니다. 만약 클러스터가 유동적이며 노드의 자원 프로파일이 변하거나 새로운 노드가 추가되더라도, 스케줄러는 이전 파드 배치를 수정하지 않습니다. 노드 용량을 변경하는 것 외에도 노드 레이블을 변경할 수 있지만 이전 배치 역시 수정되지 않습니다.

디스케줄러를 이용하여 이러한 문제점을 해결 할 수 있습니다.

쿠버네티스 디스케줄러

클러스터 어드민이 파드를 다시 스케줄링하여 클러스터를 정리하고 조각 모음을 수행하기에 적절한 시기라고 결졍할 때마다 항상 작업으로서 실행된느 옵션 기능입니다.

디스케줄러는 활성화와 조정이 가능한 또는 비활성화할 수 있는 사전 정의된 정책으로 제공됩니다.

  • RemoveDuplicates
    레플리카세트나 디플로이먼트와 관련된 하나의 파드를 하나의 노드에 실행시킵니다.
    만약 둘 이상의 파드가 있으면 초과 파드는 제거됩니다. 이 전략은 노드가 비정상 상태가 되었을 때, 관리 컨트롤러가 다른 정상 노드에 새로운 파드를 실행히키는 시나리오에 유용합니다.

    비정상 노드가 복구되어 클러스터에 조인될 때 실행 중인 파드의 수는 원하는 수보다 많아지며 디스케줄러는 원하는 replicas 개수로 파드의 수를 되돌립니다.노드 상의 중복 파드를 제거하는 것은 파드를 초기 배치한 이후 스케줄링 정책과 클러스터 토폴리지가 변경될 때 더 많은 노드에 파드를 고르게 분산시키는 데 도움이 됩니다.
  • LowNodeUtilization
    활용률이 낮은 노드를 찾고 활용률이 과도하게 높은 노드의 파드를 제거하면 해당 파드들은 활용률이 낮은 노드에 배치될 것이고 이로써 자원을 더 욱분산시키고 잘 사용할 수 있습니다.
    • 활용률이 낮은 노드 : CPU나 메모리 파드 수가 thresholds 수보다 낮은 노드
    • 활용률이 과도한 노드 : targetThresholds 값보다 큰 값을 갖는 노드
  • RemovePodsViolationInterPodAntiAffinity
    파드 간 안티어피니티 규칙을 위반한 파드를 축출하며 파드가 노드에 배치된 후에 안티어피니티 규칙이 추가될 때 발생할 수 있습니다.
  • RemovePodsViolationNodeAffinity
    노드 어피니티 규칙을 위반한 파드를 축출하기 위한 것입니다.

❕ 사용된 정책에 관계없이 디스케줄러는 다음 파드들을 축출하지 않습니다.

  • scheduler.alpha.kubernetes.io/critical-pod 애노테이션으로 표시된 중요한 파드
  • 레플리카세트, 디플로이먼트, 잡에 의해 관리되지 않는 파드
  • 데몬세트에 의해 관리되지 않는 파드
  • 로컬 스토리지를 갖는 파드
  • 파드를 축출하면 PodDisruptionBudget 규칙을 위반하게 되는 PodDisruptionBudget을 사용한 파드
  • 디스케줄 파드 자신

축출 우선도
최선적 파드 > 확장 가능 파드 > 보장 파드
파드의 서비스 품질을 준수합니다.

profile
함바라기

1개의 댓글

comment-user-thumbnail
2021년 11월 20일

정리도 잘하고 너무 멋있어용 ~

답글 달기