이 페이지에서는 Google Kubernetes Engine(GKE)에서 컨테이너 기반 부하 분산을 사용하는 방법을 설명합니다. 부하 분산기는 컨테이너 기반 부하 분산을 통해 Kubernetes 포드를 직접 대상으로 지정하고 트래픽을 포드에 균일하게 분산시킬 수 있습니다.
컨테이너 기반 부하 분산의 이점, 요구사항, 제한사항에 대한 자세한 내용은 컨테이너 기반 부하 분산을 참조하세요.
시작하기 전에
시작하기 전에 다음 태스크를 수행했는지 확인합니다.
- Google Kubernetes Engine API를 사용 설정합니다. Google Kubernetes Engine API 사용 설정
- 이 태스크에 Google Cloud CLI를 사용하려면 gcloud CLI를 설치한 후 초기화합니다. 이전에 gcloud CLI를 설치한 경우
gcloud components update
를 실행하여 최신 버전을 가져옵니다.
컨테이너 기반 부하 분산 사용
다음 섹션에서는 GKE의 컨테이너 기반 부하 분산 구성을 설명합니다. 버전 1.17 이상을 실행하는 GKE 클러스터 및 특정 조건에서는 컨테이너 기반 부하 분산이 기본값이며, 명시적인 cloud.google.com/neg: '{"ingress": true}'
서비스 주석이 필요하지 않습니다.
VPC 기반 클러스터 만들기
컨테이너 기반 부하 분산을 사용하려면 GKE 클러스터에 별칭 IP가 사용 설정되어 있어야 합니다.
예를 들어 다음 명령어는 자동 프로비저닝된 서브네트워크를 사용해서 neg-demo-cluster
라는 GKE 클러스터를 만듭니다.
Autopilot 모드의 경우 별칭 IP 주소가 기본적으로 사용 설정됩니다.
gcloud container clusters create-auto neg-demo-cluster \ --location=COMPUTE_LOCATION
COMPUTE_LOCATION
을 클러스터의 Compute Engine 위치로 바꿉니다.
표준 모드의 경우 클러스터를 만들 때 별칭 IP 주소를 사용 설정합니다.
gcloud container clusters create neg-demo-cluster \ --enable-ip-alias \ --create-subnetwork="" \ --network=default \ --zone=us-central1-a
배포 만들기
다음 샘플 배포 neg-demo-app
은 컨테이너화된 HTTP 서버의 단일 인스턴스를 실행합니다. 포드 준비 피드백을 사용하는 워크로드를 사용하는 것이 좋습니다.
포드 준비 상태 피드백 사용
apiVersion: apps/v1 kind: Deployment metadata: labels: run: neg-demo-app # Label for the Deployment name: neg-demo-app # Name of Deployment spec: selector: matchLabels: run: neg-demo-app template: # Pod template metadata: labels: run: neg-demo-app # Labels Pods from this Deployment spec: # Pod specification; each Pod created by this Deployment has this specification containers: - image: registry.k8s.io/serve_hostname:v1.4 # Application to run in Deployment's Pods name: hostname # Container name ports: - containerPort: 9376 protocol: TCP
하드코딩된 지연 사용
apiVersion: apps/v1 kind: Deployment metadata: labels: run: neg-demo-app # Label for the Deployment name: neg-demo-app # Name of Deployment spec: minReadySeconds: 60 # Number of seconds to wait after a Pod is created and its status is Ready selector: matchLabels: run: neg-demo-app template: # Pod template metadata: labels: run: neg-demo-app # Labels Pods from this Deployment spec: # Pod specification; each Pod created by this Deployment has this specification containers: - image: registry.k8s.io/serve_hostname:v1.4 # Application to run in Deployment's Pods name: hostname # Container name # Note: The following line is necessary only on clusters running GKE v1.11 and lower. # For details, see https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing#align_rollouts ports: - containerPort: 9376 protocol: TCP terminationGracePeriodSeconds: 60 # Number of seconds to wait for connections to terminate before shutting down Pods
이 배포에서 각 컨테이너는 HTTP 서버를 실행합니다. HTTP 서버는 애플리케이션 서버의 호스트 이름(서버가 실행되는 포드의 이름)을 응답으로 반환합니다.
이 매니페스트를 neg-demo-app.yaml
로 저장한 후 배포를 만듭니다.
kubectl apply -f neg-demo-app.yaml
컨테이너 기반 부하 분산기용 서비스 만들기
배포를 만든 후에 배포의 포드를 서비스로 그룹화해야 합니다.
다음 샘플 서비스 neg-demo-svc
는 이전 섹션에서 만든 샘플 배포를 대상으로 합니다.
apiVersion: v1
kind: Service
metadata:
name: neg-demo-svc # Name of Service
annotations:
cloud.google.com/neg: '{"ingress": true}' # Creates a NEG after an Ingress is created
spec: # Service's specification
type: ClusterIP
selector:
run: neg-demo-app # Selects Pods labelled run: neg-demo-app
ports:
- name: http
port: 80 # Service's port
protocol: TCP
targetPort: 9376
서비스 주석인 cloud.google.com/neg: '{"ingress": true}'
는 컨테이너 기반 부하 분산을 사용 설정합니다. 하지만 부하 분산기는 서비스용 인그레스를 만들 때까지 만들어지지 않습니다.
이 매니페스트를 neg-demo-svc.yaml
로 저장한 후 서비스를 만듭니다.
kubectl apply -f neg-demo-svc.yaml
서비스에 대한 인그레스 만들기
다음 샘플 인그레스 neg-demo-ing
는 만든 서비스를 대상으로 합니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: neg-demo-ing
spec:
defaultBackend:
service:
name: neg-demo-svc # Name of the Service targeted by the Ingress
port:
number: 80 # Should match the port used by the Service
이 매니페스트를 neg-demo-ing.yaml
로 저장한 후 인그레스를 만듭니다.
kubectl apply -f neg-demo-ing.yaml
인그레스를 만들면 프로젝트에 애플리케이션 부하 분산기가 생성되고 클러스터가 실행되는 각 영역에 네트워크 엔드포인트 그룹(NEG)이 생성됩니다. NEG의 엔드포인트와 서비스의 엔드포인트는 동기화 상태로 유지됩니다.
인그레스 확인
워크로드를 배포하고 포드를 서비스로 그룹화하고 서비스용 인그레스를 만든 후 인그레스가 컨테이너 기본 부하 분산기를 성공적으로 프로비저닝했는지 확인해야 합니다.
인그레스의 상태를 검색합니다.
kubectl describe ingress neg-demo-ing
출력에는 ADD
및 CREATE
이벤트가 포함됩니다.
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 16m loadbalancer-controller default/neg-demo-ing
Normal Service 4s loadbalancer-controller default backend set to neg-demo-svc:32524
Normal CREATE 2s loadbalancer-controller ip: 192.0.2.0
부하 분산기 테스트
다음 섹션에서는 컨테이너 기본 부하 분산기의 기능을 테스트하는 방법을 설명합니다.
인그레스 IP 주소 방문
애플리케이션 부하 분산기가 구성될 때까지 몇 분 정도 기다립니다.
인그레스의 IP 주소를 방문하여 컨테이너 기본 부하 분산기가 작동하는지 확인할 수 있습니다.
인그레스 IP 주소를 얻으려면 다음 명령어를 실행하세요.
kubectl get ingress neg-demo-ing
명령어 결과의 ADDRESS
열에 인그레스의 IP 주소가 표시됩니다. 웹브라우저에서 이 IP 주소를 방문합니다.
백엔드 서비스 상태 확인
부하 분산기의 백엔드 서비스 상태를 확인할 수도 있습니다.
프로젝트에서 실행되는 백엔드 서비스의 목록을 가져옵니다.
gcloud compute backend-services list
neg-demo-svc
와 같은 서비스 이름이 포함된 백엔드 서비스의 이름을 기록합니다.백엔드 서비스 상태를 확인합니다.
gcloud compute backend-services get-health BACKEND_SERVICE_NAME --global
BACKEND_SERVICE_NAME
을 백엔드 서비스 이름으로 바꿉니다.
인그레스 테스트
부하 분산기가 예상대로 작동하는지 테스트하는 또 다른 방법은 샘플 배포를 확장하고 테스트 요청을 인그레스에 전송하여 올바른 수의 복제본이 응답하는지 확인하는 것입니다.
neg-demo-app
배포를 인스턴스 한 개에서 인스턴스 두 개로 확장합니다.kubectl scale deployment neg-demo-app --replicas 2
이 작업을 완료하는 데 몇 분이 소요될 수 있습니다.
출시가 완료되었는지 확인합니다.
kubectl get deployment neg-demo-app
출력에는 사용 가능한 복제본 2개가 포함되어야 합니다.
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE neg-demo-app 2 2 2 2 26m
인그레스 IP 주소를 가져옵니다.
kubectl describe ingress neg-demo-ing
이 명령어가 404 오류를 반환하면 부하 분산기가 시작될 때까지 몇 분 정도 기다린 후 다시 시도합니다.
부하 분산기에서 고유 응답 수를 계산합니다.
for i in `seq 1 100`; do \ curl --connect-timeout 1 -s IP_ADDRESS && echo; \ done | sort | uniq -c
IP_ADDRESS
를 인그레스 IP 주소로 바꿉니다.출력은 다음과 비슷합니다.
44 neg-demo-app-7f7dfd7bc6-dcn95 56 neg-demo-app-7f7dfd7bc6-jrmzf
이 출력에서 고유 응답 수는 복제본 수와 동일합니다. 이는 모든 백엔드 포드가 트래픽을 처리하고 있음을 나타냅니다.
삭제
이 페이지의 작업을 완료한 후에는 다음 단계에 따라 리소스를 제거하여 계정에서 원치 않는 요금이 부과되지 않도록 합니다.
클러스터 삭제
gcloud
gcloud container clusters delete neg-demo-cluster
콘솔
Google Cloud 콘솔에서 Google Kubernetes Engine 페이지로 이동합니다.
neg-demo-cluster를 선택하고 delete 삭제를 클릭합니다.
확인 메시지가 나타나면 삭제를 클릭합니다.
문제해결
아래 기법을 사용하여 네트워킹 구성을 확인하세요. 다음 섹션에서는 컨테이너 기본 부하 분산과 관련된 구체적인 문제를 해결하는 방법을 설명합니다.
네트워크 엔드포인트 그룹을 나열하는 방법은 부하 분산 문서를 참조하세요.
서비스의
neg-status
주석에서 서비스에 해당하는 NEG의 이름과 영역을 확인할 수 있습니다. 다음을 사용하여 서비스 사양을 가져옵니다.kubectl get svc SVC_NAME -o yaml
metadata:annotations:cloud.google.com/neg-status
주석에는 서비스의 해당 NEG 이름과 NEG 영역이 있습니다.다음 명령어를 사용하여 NEG에 해당하는 백엔드 서비스의 상태를 확인할 수 있습니다.
gcloud compute backend-services --project PROJECT_NAME \ get-health BACKEND_SERVICE_NAME --global
백엔드 서비스 이름은 NEG 이름과 동일합니다.
서비스의 이벤트 로그를 인쇄하려면 다음 명령어를 실행합니다.
kubectl describe svc SERVICE_NAME
서비스의 이름 문자열에는 해당 GKE 서비스의 이름과 네임스페이스가 포함됩니다.
별칭 IP로 클러스터를 만들 수 없음
- 증상
별칭 IP를 사용하여 클러스터를 만들려고 할 때 다음과 같은 오류가 나타날 수 있습니다.
ResponseError: code=400, message=IP aliases cannot be used with a legacy network.
- 가능한 원인
이전 네트워크도 사용하는 별칭 IP로 클러스터를 만들려고 하면 이 오류가 발생합니다.
- 해결 방법
별칭 IP와 기존 네트워크가 동시에 사용 설정된 상태로 클러스터를 만들지 않아야 합니다. 별칭 IP 사용에 대한 자세한 내용은 VPC 기반 클러스터 만들기를 참조하세요.
트래픽이 엔드포인트에 도달하지 않음
- 증상
- 502/503 오류가 표시되거나 연결이 거부됩니다.
- 가능한 원인
새 엔드포인트는 일반적으로 부하 분산기에 연결한 후에 도달 가능합니다. 단, 엔드포인트가 상태 확인에 응답해야 합니다. 트래픽이 엔드포인트에 도달할 수 없으면 502 오류가 발생하거나 연결이 거부될 수 있습니다.
502 오류 및 연결 거부는
SIGTERM
을 처리하지 않는 컨테이너로 인해 발생할 수도 있습니다. 컨테이너가 명시적으로SIGTERM
을 처리하지 않으면 즉시 종료되고 요청 처리가 중지됩니다. 부하 분산기는 수신 트래픽을 종료된 컨테이너에 계속 전송하므로 오류가 발생합니다.컨테이너 기반 부하 분산기에는 백엔드 엔드포인트가 하나만 있습니다. 순차적 업데이트 중에 이전 엔드포인트는 새 엔드포인트가 프로그래밍되기 전에 디프로그래밍됩니다.
컨테이너 기반 부하 분산기가 프로비저닝된 후 백엔드 포드가 새로운 영역에 처음으로 배포됩니다. 부하 분산기 인프라는 영역에 최소 하나 이상의 엔드포인트가 있는 경우 한 영역에서 프로그래밍됩니다. 새 엔드포인트가 영역에 추가되면 부하 분산기 인프라가 프로그래밍되어 서비스가 중단됩니다.
- 해결 방법
SIGTERM
을 처리하고 종료 유예 기간(기본적으로 30초) 동안 요청에 계속 응답하도록 컨테이너를 구성합니다.SIGTERM
을 수신할 때 상태 확인을 실패하도록 포드를 구성합니다. 그러면 엔드포인트 디프로그래밍이 진행되는 동안 부하 분산기가 포드로 트래픽 전송을 중지합니다.애플리케이션이 정상적으로 종료되지 않고
SIGTERM
수신 시 요청에 응답하지 않으면 엔드포인트의 디프로그래밍이 진행되는 동안 사전 중지 후크를 사용하여SIGTERM
을 처리하고 트래픽을 계속 처리할 수 있습니다.lifecycle: preStop: exec: # if SIGTERM triggers a quick exit; keep serving traffic instead command: ["sleep","60"]
포드 종료 문서를 참조하세요.
부하 분산기 백엔드에 인스턴스가 한 개만 있다면 새 인스턴스가 완전히 프로그래밍되기 전에 유일한 인스턴스가 손상되지 않도록 배포 전략을 구성하세요.
Deployment
워크로드에서 관리하는 애플리케이션 포드의 경우,0
과 동일한maxUnavailable
매개변수를 사용하여 롤아웃 전략을 구성하면 됩니다.strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0
엔드포인트에 도달하지 않는 트래픽 문제를 해결하려면 방화벽 규칙이
130.211.0.0/22
및35.191.0.0/16
범위에서 엔드포인트로 들어오는 TCP 트래픽을 허용하는지 확인합니다. 자세한 내용은 Cloud Load Balancing 문서의 상태 점검 추가를 참조하세요.프로젝트의 백엔드 서비스를 확인합니다. 관련 백엔드 서비스의 이름 문자열에는 해당 GKE 서비스의 이름 및 네임스페이스가 포함됩니다.
gcloud compute backend-services list
백엔드 서비스에서 백엔드 상태를 검색합니다.
gcloud compute backend-services get-health BACKEND_SERVICE_NAME
모든 백엔드가 비정상이라면 방화벽, 인그레스 또는 서비스가 잘못 구성되었을 수 있습니다.
일부 백엔드가 잠깐 동안 비정상이라면 네트워크 프로그래밍 지연 시간이 원인일 수 있습니다.
일부 백엔드가 백엔드 서비스 목록에 나타나지 않으면 프로그래밍 지연 시간이 원인일 수 있습니다. 이것은 다음 명령어를 실행하여 확인할 수 있습니다. 여기서
NEG_NAME
는 백엔드 서비스의 이름입니다. (NEG와 백엔드 서비스는 이름이 같습니다).gcloud compute network-endpoint-groups list-network-endpoints NEG_NAME
예상되는 모든 엔드포인트가 NEG에 있는지 확인하세요.
컨테이너 기반 부하 분산기에서 소수의 백엔드(예: 포드 1개)가 선택된 경우 복제본 수를 늘리고 GKE 클러스터가 사용하는 모든 영역에 백엔드 포드를 배포하는 것이 좋습니다. 이렇게 하면 기본 부하 분산기 인프라가 완전히 프로그래밍됩니다. 그렇지 않으면 백엔드 포드를 단일 영역으로 제한하는 것이 좋습니다.
엔드포인트에 대한 네트워크 정책을 구성하는 경우 프록시 전용 서브넷의 인그레스가 허용되는지 확인합니다.
출시 중단
- 증상
- 업데이트된 배포 롤아웃이 중단되고 최신 복제본 수가 원하는 복제본 수와 일치하지 않습니다.
- 가능한 원인
배포 상태 확인이 실패합니다. 컨테이너 이미지가 손상되었거나 상태 확인이 잘못 구성되었을 수 있습니다. 포드의 순차적 교체는 새로 시작된 포드가 포드 준비 게이트를 통과할 때까지 대기합니다. 이는 포드가 부하 분산기 상태 확인에 응답하는 경우에만 발생합니다. 포드가 응답하지 않거나 상태 확인이 잘못 구성된 경우 준비 게이트 조건을 충족할 수 없으며 롤아웃을 계속할 수 없습니다.
kubectl
1.13 이상을 사용하는 경우 다음 명령어를 사용하여 포드의 준비 게이트 상태를 확인할 수 있습니다.kubectl get pod POD_NAME -o wide
READINESS GATES
열을 확인합니다.kubectl
1.12 이하에는 이 열이 존재하지 않습니다.READY
상태로 표시된 포드에서는 준비 게이트가 실패했을 수 있습니다. 이를 확인하려면 다음 명령어를 사용합니다.kubectl get pod POD_NAME -o yaml
준비 게이트와 해당 상태가 출력에 나열됩니다.
- 해결 방법
배포 포드 사양의 컨테이너 이미지가 제대로 작동하고 있고 상태 확인에 응답할 수 있는지 확인합니다. 상태 확인이 올바르게 구성되어 있는지 확인합니다.
성능 저하 모드 오류
- 증상
GKE 버전 1.29.2-gke.1643000부터는 NEG가 업데이트될 때 로그 탐색기에서 서비스에 대한 다음과 같은 경고가 표시될 수 있습니다.
Entering degraded mode for NEG <service-namespace>/<service-name>-<neg-name>... due to sync err: endpoint has missing nodeName field
- 가능한 원인
이러한 경고는
EndpointSlice
객체를 기반으로 NEG 업데이트 중 GKE에서 엔드포인트 구성 오류가 감지되어 성능 저하 모드라고 부르는 보다 심도 깊은 계산 프로세스가 트리거되었음을 나타냅니다. GKE는 구성 오류를 수정하거나 NEG 업데이트에서 잘못된 엔드포인트를 제외하는 방식으로 최선에 따라 NEG 업데이트를 계속합니다.일반적인 오류는 다음과 같습니다.
endpoint has missing pod/nodeName field
endpoint corresponds to an non-existing pod/node
endpoint information for attach/detach operation is incorrect
- 해결 방법
일반적으로 이러한 이벤트는 일시적인 상태로 인해 발생하며 자체적으로 해결됩니다. 그러나 커스텀
EndpointSlice
객체에서 구성 오류로 인해 발생한 이벤트는 해결되지 않은 상태로 유지됩니다. 구성 오류를 이해하기 위해서는 서비스에 해당하는EndpointSlice
객체를 검사합니다.kubectl get endpointslice -l kubernetes.io/service-name=<service-name>
이벤트의 오류를 기준으로 각 엔드포인트를 검증합니다.
이 문제를 해결하려면
EndpointSlice
객체를 수동으로 수정해야 합니다. 이 업데이트는 NEG가 다시 업데이트되도록 트리거합니다. 구성 오류가 더 이상 없으면 다음과 비슷한 출력이 표시됩니다.NEG <service-namespace>/<service-name>-<neg-name>... is no longer in degraded mode
알려진 문제
GKE에서 컨테이너 기반 부하 분산에는 다음과 같은 알려진 문제가 있습니다.
불완전한 가비지 컬렉션
GKE는 컨테이너 기반 부하 분산을 2분 간격으로 가비지 수집합니다. 부하 분산기가 완전히 제거되기 전에 클러스터가 삭제되면 부하 분산기의 NEG를 수동으로 삭제해야 합니다.
프로젝트의 NEG를 보려면 다음 명령어를 실행합니다.
gcloud compute network-endpoint-groups list
명령어 결과에서 관련 NEG를 찾습니다.
NEG를 삭제하려면 다음 명령어를 실행하여 NEG_NAME
을 NEG 이름으로 바꿉니다.
gcloud compute network-endpoint-groups delete NEG_NAME
워크로드 롤아웃을 엔드포인트 전파에 정렬
워크로드를 클러스터에 배포하거나 기존 워크로드를 업데이트할 때 컨테이너 기반 부하 분산기가 새 엔드포인트를 전파하는 시간이 워크로드 롤아웃을 완료하는 시간보다 길어질 수 있습니다. 이 가이드에서 배포하는 샘플 배포는 terminationGracePeriodSeconds
필드와 minReadySeconds
필드를 사용하여 롤아웃을 엔드포인트 전파에 맞춥니다.
terminationGracePeriodSeconds
는 포드 삭제 예약 후 연결이 종료될 때까지 기다려 포드가 정상적으로 종료되도록 합니다.
minReadySeconds
는 포드가 생성된 후 지연 시간을 추가합니다. 컨테이너의 비정상 종료 없이 포드가 사용 가능한 것으로 간주될 수 있도록 새 포드가 Ready
상태로 있어야 하는 최소 시간(초)을 지정합니다.
워크로드 롤아웃으로 인해 서비스가 중단되지 않도록 하려면 워크로드의 minReadySeconds
값과 terminationGracePeriodSeconds
값을 60초 이상으로 구성해야 합니다.
terminationGracePeriodSeconds
는 모든 포드 사양에서 사용될 수 있으며, minReadySeconds
는 배포와 DaemonSet에 사용될 수 있습니다.
롤아웃 미세 조정에 대한 자세한 내용은 RollingUpdateStrategy를 참조하세요.
readinessProbe
포드의 initialDelaySeconds
가 반영되지 않음
포드의 readinessProbe
에 있는 initialDelaySeconds
구성이 컨테이너 기반 부하 분산기에 반영될 것으로 기대할 수도 있겠지만, readinessProbe
는 kubelet에 의해 구현되며 initialDelaySeconds
구성은 컨테이너 기반 부하 분산기가 아닌 kubelet 상태 점검을 제어합니다. 컨테이너 기반 부하 분산은 자체 부하 분산 상태 점검을 가집니다.
다음 단계
- NEG에 대해 자세히 알아보기
- VPC 기반 클러스터 자세히 알아보기