이 페이지에서는 베어메탈용 Google Distributed Cloud Virtual의 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
상태가 되면 포드를 다시 배포하여 컨테이너가 이제 노드 전체에 고르게 분산되는지 확인합니다.