관리 메뉴

진취적 삶

11 고급 스케줄링 본문

개발 도서/핵심만 콕 쿠버네티스

11 고급 스케줄링

hp0724 2023. 11. 17. 10:59

11.1 고가용성 확보 -Pod 레벨

replicaSet ,Deployment 리소스의 replica property 를 이용하는 경우 일정 범위 안의 트래픽에 대해서는 서비스 가용성이 유지되지만 처리량 범위를 넘어서는 트래픽에 대해서는 한계를 가진다.

k8s 에서는 리소스 사용량에 따라 hpa 를 통해 자동으로 scale out 한다.

hpa (HorizontalPodAutoScaler (hpa)

hpa 는 metrics-server 라는 컴포넌트를 사용한다.

metrics-server 는 Pod의 리소스 사용량을 수집하는 서버이다.

이 서버를 통해 Pod의 작업량을 모니터링하다가 사용자가 지정한 일정 수준의 임계값을 넘으면 replica 개수를 동적으로 조절하여 Pod의 개수를 늘린다.

pod별 리소스 사용량을 확인

sudo kubectl top pod 

Node 별 리소스 사용량을 확인

sudo kubectl top node 

11.1.2 자동확장할 pod 생성

자동 확장의 대상될 Pod 생성

# heavy-cal.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: heavy-cal
spec:
  selector:
    matchLabels:
      run: heavy-cal
  replicas: 1
  template:
    metadata:
      labels:
        run: heavy-cal
    spec:
      containers:
      - name: heavy-cal
        image: k8s.gcr.io/hpa-example
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 300m
---
apiVersion: v1
kind: Service
metadata:
  name: heavy-cal
spec:
  ports:
  - port: 80
  selector:
    run: heavy-cal

11.1.3 hpa 생성 -선언형 명령

# hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: heavy-cal
spec:
  maxReplicas: 50
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: heavy-cal
  targetCPUUtilizationPercentage: 50
  • scaleTargetRef : 모니터링할 타깃을 지정
  • targetCPUUtilizationPercentage : 리소스의 임계치를 설정

모니터링 대상의 리소스에 꼭 requests property 가 정의되어 있어야 한다.

hpa가 해당 값을 기준으로 CPU 임계치 계산을 한다.

# heavy-load.yaml
apiVersion: v1
kind: Pod
metadata:
  name: heavy-load
spec:
  containers: 
  - name: busybox
    image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do wget -q -O- <http://heavy-cal>; done"]

해당 부하를 통해 pod 가 생성된다.

11.2 고가용성 확보 -Node 레벨

k8s 는 Pod 뿐만 아니라 cluster 레벨의 Node 또한 자동 수평확장할수 있는 매커니즘을 제공한다.

  1. CPU 사용량을 hpa 가 확인하여 Deployment 의 replica를 증가시킨다
  2. 노드에 새로운 Pod가 추가된다.
  3. 일부 Pod는 클러스토 노드 자원이 부족하여 스케줄링되지 못하고, Pending 상태로 머문다.
  4. cluster autoscaler 가 pending 된 Pod 가 생긴것을 확인
  5. 클라우드 플랫폼에 신규 노드를 요청
  6. 새로운 노드 할당
  7. pending 되어 있던 pod들이 신규 노드에 스케줄링

11.3 Taint & Toleration

11.3.1 Taint

taint : 오염시키다라는 뜻 노드에 Taint를 남기게 되면 Pod들이 오염되어서 쉽게 스케줄링 못한다.

kubectl taint nodes $NODE_NAME <KEY> =<VALUE> :<EFFECT>
  • key: taint의 key 값을 설정한다.
  • value: taint 의 value 값 설정
  • effect : 세가지 종류중에 하나 선택

effect

  1. PreferNoSchedule: taint 된 노드에 새로운 pod를 스케줄링 하는것을 지양 다른 노드에 먼저 스케줄리을 하고 , 더 이상 다른 노드의 가용한 리소스가 없는 경우에 마지막으로 PreferNoSchedule 이 설정된 노드에 스케줄링된다.
  2. NoSchedule : taint 된 노드에 새로운 Pod를 스케줄링 하지 못하게 막는다.
  3. NoExecute: taint 된 노드에 새로운 Pod를 스케줄링 못하게 하고 ,기존에 들고있던 pod도 삭제

11.3.2 Toleration

toleration : 견디다

프로젝트 a 관련된 pod 만 스케줄링하기 위해 NoSchedule 설정

# project=A 라는 taint를 NoSchedule로 설정
kubectl taint node worker project=A:NoSchedule
# node/worker tainted

kubectl get node worker -oyaml | grep -A 4 taints
#  taints:
#  - effect: NoSchedule
#    key: project
#    value: A

pod에 toleration 설정

# tolerate.yaml
apiVersion: v1
kind: Pod
metadata:
  name: tolerate
spec:
  containers:
  - name: nginx
    image: nginx
  tolerations:
  - key: "project"
    value: "A"
    operator: "Equal"
    effect: "NoSchedule"
  • operator : Equal ,Exists 중 하나를 선택
    • Equal 인 경우 key ,value가 항상 동일
    • Exists 인 경우 key 값만 동일
  • effect : taint 에 적용된 effect 에 대해서 tolerate 하겠다는 것을 의미

taint와 toleration을 안정적인 서비스를 운영하는데 활용할수 있다.

특정 노드에 대해 보수 작업을 하거나 ,네트워크 이상이 생긴다거나 노드가 특정 상태에 처해있을때 해당 노드를 taint 시켜 k8s 에게 알리면 ,노드의 상태를 충분히 인지하고 감안할수 있는 Pod에 대해서만 스케줄링 하기 때문에 사용자 입장에서 세밀한 Pod 스케줄링을 수행할수 있다.

11.4 Affinity & AntiAffinity

특정 Node나 Pod와의 거리르 조절하는데 사용된다. 특정 pod끼리 서로 가까이 스케줄링되고 싶은 경우 Affinity 사용하고 서로 멀리 스케줄링 되고 싶은 경우 AntiAffinity 사용

Affinity

  • NodeAffinity : 특정 Node 와 가까이 할당되기 원할때 사용
  • PodAffinity 특정 Pod 끼리 가까이 할당되기 원할때 사용

antiAffinity

  • podAntiAffinity: 특정 pod 끼리 멀리 할당되기 원할때 사용

11.4.1 NodeAffinity

# node-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity
spec:
  containers:
  - name: nginx
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
  • nodeAffinity : affinity 종류를 선택한다
  • requiredDuringSchedulingIgnoredDuringExecution: 특정 노드에 스케줄링 되길 강제한다.
  • preferredDuringSchedulingIgnoreDuringExecution: 특정 노드에 스케줄링 되길 희망한다.
  • nodeSelectorTerms : 선택할 노드의 라벨 정보를 나타낸다.
  • matchExpressions : toleration 과 마찬가지로 key, value , operator 등을 설정한다.
  • operator : 단순히 라벨 매칭이 아닌 in ,Notin, Exists, DoesNotExist , Gt 등등 매칭 정책 선택

11.4.2 PodAffinity

Pod 간의 스케줄링에 관여

matchExpressions 이 매칭되는 Pod가 동일한 노드에서 실행될수 있도록 요청한다.

# pod-affinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-affinity
spec:
  selector:
    matchLabels:
      app: affinity
  replicas: 2
  template:
    metadata:
      labels:
        app: affinity
    spec:
      containers:
      - name: nginx
        image: nginx
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - affinity
            topologyKey: "kubernetes.io/hostname"

podAffinity 는 pod끼리의 스케줄링을 관장하기 때문에 1개의 pod만 이용해서는 무의미

  • podAffinity : nodeAffinity 가 아닌 podAffinity 로 설정
  • labelSelector: 동일한 라벨을 가진 Pod 끼리 묶을때 사용
  • topologyKey: Pod끼리 묶을 기준을 정의

11.4.3 PodAntiAffinity

Pod 끼리 서로 다른 노드에 스케줄링하고 싶을때 PodAntiAffinity 를 사용한다.

# pod-antiaffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-antiaffinity
spec:
  selector:
    matchLabels:
      app: antiaffinity
  replicas: 2
  template:
    metadata:
      labels:
        app: antiaffinity
    spec:
      containers:
      - name: nginx
        image: nginx
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - antiaffinity
            topologyKey: "kubernetes.io/hostname"
  • podAntiAffinity :Pod 끼리 서로 다른 topology 에 스케줄링
  • labelSelector: 서로 다른 곳에 스케줄링 될 pod 선택
  • topologyKey: Pod 끼리 서로 다른 곳에 스케줄링될 기준을 설정

11.4.4 PodAffinity 와 PodAntiAffinity 활용법

웹서비스 뒤에는 cache 서버를 두고 필요한 데이터를 cache 서버에서 꺼내서 사용

서비스 가용성을 위해 1개의 노드가 죽더라도 다른 노드에서 서비스를 지속할수 있도록

web , cache 서버끼리 최대한 서로 다른 노드에 스케줄링

각각의 web 서버와 cache 서버는 네트워크 지연을 최소화하기 위해 최대한 서로 같은 노드에서 실행

  • web 서버별 : 최대한 멀리 스케줄링
  • cache 서버별 : 최대한 멀리 스케줄링
  • web-cache 서버 :최대한 가까이 설정

cache 서버 설정

# redis-cache.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-cache
spec:
  selector:
    matchLabels:
      app: store
  replicas: 2
  template:
    metadata:
      labels:
        app: store
    spec:
      affinity:
        # cache 서버끼리 멀리 스케줄링
        # app=store 라벨을 가진 Pod끼리 멀리 스케줄링
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: redis-server
        image: redis

web 서버 설정

# 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:
        # web 서버끼리 멀리 스케줄링
        # app=web-store 라벨을 가진 Pod끼리 멀리 스케줄링
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web-store
            topologyKey: "kubernetes.io/hostname"
        # web-cache 서버끼리 가까이 스케줄링 
        # app=store 라벨을 가진 Pod끼리 가까이 스케줄링
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: web-app
        image: nginx

'개발 도서 > 핵심만 콕 쿠버네티스' 카테고리의 다른 글

13 접근 제어  (0) 2023.11.17
12 클러스터 관리  (0) 2023.11.17
10 스토리지  (0) 2023.11.17
09 ingress 리소스  (0) 2023.11.17
08 helm 패키지 매니저  (0) 2023.11.17