이 페이지에서는 Google Distributed Cloud의 Kubernetes 스케줄러(kube-scheduler
) 문제를 해결하는 방법을 설명합니다.
Kubernetes는 항상 동일한 노드 집합에 포드를 예약함
이 오류는 몇 가지 다른 방식으로 관찰될 수 있습니다.
불균형한 클러스터 사용률.
kubectl top nodes
명령어를 사용하여 각 노드의 클러스터 사용률을 조사할 수 있습니다. 다음 예시 출력은 특정 노드의 현저한 사용률을 보여줍니다.NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% XXX.gke.internal 222m 101% 3237Mi 61% YYY.gke.internal 91m 0% 2217Mi 0% ZZZ.gke.internal 512m 0% 8214Mi 0%
요청이 너무 많습니다. 동일한 노드에 한 번에 많은 포드를 예약하고 이러한 포드가 HTTP 요청을 수행하는 경우 노드 비율이 제한될 수 있습니다. 이 시나리오에서 서버가 반환하는 일반적인 오류는
429 Too Many Requests
입니다.서비스를 사용할 수 없습니다. 예를 들어 부하가 높은 노드에서 호스팅되는 웹 서버는 부하가 줄어들 때까지
503 Service Unavailable
오류가 있는 모든 요청에 응답할 수 있습니다.
항상 동일한 노드에 예약된 포드가 있는지 확인하려면 다음 단계를 수행합니다.
다음
kubectl
명령어를 실행하여 포드 상태를 확인합니다.kubectl get pods -o wide -n default
노드 전체의 포드 분포를 보려면 출력에서
NODE
열을 확인합니다. 다음 출력 예시에서 모든 포드는 동일한 노드에 예약됩니다.NAME READY STATUS RESTARTS AGE IP NODE nginx-deployment-84c6674589-cxp55 1/1 Running 0 55s 10.20.152.138 10.128.224.44 nginx-deployment-84c6674589-hzmnn 1/1 Running 0 55s 10.20.155.70 10.128.226.44 nginx-deployment-84c6674589-vq4l2 1/1 Running 0 55s 10.20.225.7 10.128.226.44
포드에는 예약 동작을 미세 조정할 수 있는 여러 기능이 포함되어 있습니다. 이러한 기능에는 토폴로지 분산 제약조건과 안티-어피니티 규칙이 포함됩니다. 이러한 기능 중 하나 또는 조합해 사용할 수 있습니다. 정의한 요구사항은 kube-scheduler
에서 AND와 함께 제공됩니다.
스케줄러 로그는 기본 로깅 세부정보 수준에서 캡처되지 않습니다. 문제 해결을 위해 스케줄러 로그가 필요하면 다음 단계를 수행하여 스케줄러 로그를 캡처합니다.
로깅 세부정보 수준을 늘립니다.
kube-scheduler
배포를 수정합니다.kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG edit deployment kube-scheduler \ -n USER_CLUSTER_NAMESPACE
spec.containers.command
섹션 아래에서--v=5
플래그를 추가합니다.containers: - command: - kube-scheduler - --profiling=false - --kubeconfig=/etc/kubernetes/scheduler.conf - --leader-elect=true - --v=5
문제 해결이 완료되면 세부정보 수준을 다시 기본 수준으로 재설정합니다.
kube-scheduler
배포를 수정합니다.kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG edit deployment kube-scheduler \ -n USER_CLUSTER_NAMESPACE
세부정보 수준을 다시 기본값으로 설정합니다.
containers: - command: - kube-scheduler - --profiling=false - --kubeconfig=/etc/kubernetes/scheduler.conf - --leader-elect=true
토폴로지 분산 제약조건
토폴로지 분산 제약조건은 zones
, regions
, node
또는 기타 맞춤 정의 토폴로지에 따라 노드 전체에 포드를 고르게 배포하는 데 사용할 수 있습니다.
다음 매니페스트 예시에서는 토폴로지 분산 제약조건을 사용하여 예약 가능한 전체 노드에 복제본을 고르게 분산하는 배포를 보여줍니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: topology-spread-deployment
labels:
app: myapp
spec:
replicas: 30
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
topologySpreadConstraints:
- maxSkew: 1 # Default. Spreads evenly. Maximum difference in scheduled Pods per Node.
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule # Default. Alternatively can be ScheduleAnyway
labelSelector:
matchLabels:
app: myapp
matchLabelKeys: # beta in 1.27
- pod-template-hash
containers:
# pause is a lightweight container that simply sleeps
- name: pause
image: registry.k8s.io/pause:3.2
토폴로지 분산 제약조건을 사용할 때는 다음 고려사항이 적용됩니다.
- 포드의
labels.app: myapp
이 제약조건의labelSelector
와 일치합니다. topologyKey
는kubernetes.io/hostname
을 지정합니다. 이 라벨은 모든 노드에 자동으로 연결되고 노드의 호스트 이름으로 채워집니다.matchLabelKeys
는 포드를 예약할 위치를 계산할 때 새 배포의 출시가 이전 버전의 포드를 고려하는 것을 방지합니다.pod-template-hash
라벨은 배포 시 자동으로 채워집니다.
Pod 안티어피니티
포드 안티-어피니티를 사용하면 동일한 노드에 함께 배치될 수 있는 포드의 제약조건을 정의할 수 있습니다.
다음 매니페스트 예시는 안티어피니티를 사용하여 복제본을 노드당 하나의 포드로 제한하는 배포를 보여줍니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-affinity-deployment
labels:
app: myapp
spec:
replicas: 30
selector:
matchLabels:
app: myapp
template:
metadata:
name: with-pod-affinity
labels:
app: myapp
spec:
affinity:
podAntiAffinity:
# requiredDuringSchedulingIgnoredDuringExecution
# prevents Pod from being scheduled on a Node if it
# does not meet criteria.
# Alternatively can use 'preferred' with a weight
# rather than 'required'.
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp
# Your nodes might be configured with other keys
# to use as `topologyKey`. `kubernetes.io/region`
# and `kubernetes.io/zone` are common.
topologyKey: kubernetes.io/hostname
containers:
# pause is a lightweight container that simply sleeps
- name: pause
image: registry.k8s.io/pause:3.2
이 예시 배포는 30
복제본을 지정하지만 클러스터에 사용 가능한 노드 수만큼으로 확장됩니다.
포드 안티-어피니티를 사용하는 경우 다음 고려사항이 적용됩니다.
- 포드의
labels.app: myapp
이 제약조건의labelSelector
와 일치합니다. topologyKey
는kubernetes.io/hostname
을 지정합니다. 이 라벨은 모든 노드에 자동으로 연결되고 노드의 호스트 이름으로 채워집니다. 클러스터에서 지원하는 경우region
또는zone
과 같은 다른 라벨을 사용하도록 선택할 수 있습니다.
컨테이너 이미지 사전 가져오기
다른 제약조건이 없으면 기본적으로 kube-scheduler
는 컨테이너 이미지가 이미 다운로드된 노드에서 포드를 예약하는 것을 선호합니다. 이 동작은 모든 노드에서 이미지를 다운로드할 수 있는 다른 예약 구성이 없는 소규모 클러스터에 중요할 수 있습니다. 하지만 이 개념을 사용하는 것은 최후의 수단으로 간주되어야 합니다. 더 나은 해결책은 nodeSelector
, 토폴로지 분산 제약조건 또는 어피니티/안티-어피니티를 사용하는 것입니다. 자세한 내용은 노드에 포드 할당을 참조하세요.
컨테이너 이미지가 모든 노드로 미리 가져오기 되었는지 확인하려면 다음 예시와 같이 DaemonSet
을 사용하면 됩니다.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: prepulled-images
spec:
selector:
matchLabels:
name: prepulled-images
template:
metadata:
labels:
name: prepulled-images
spec:
initContainers:
- name: prepulled-image
image: IMAGE
# Use a command the terminates immediately
command: ["sh", "-c", "'true'"]
containers:
# pause is a lightweight container that simply sleeps
- name: pause
image: registry.k8s.io/pause:3.2
포드가 모든 노드에서 Running
상태가 되면 포드를 다시 배포하여 컨테이너가 이제 노드 전체에 고르게 분산되는지 확인합니다.