내부 부하 분산용 인그레스 구성

이 페이지에서는 Google Kubernetes Engine(GKE)에서 내부 HTTP(S) 부하 분산을 위해 인그레스를 설정하고 사용하는 방법을 설명합니다. 내부 HTTP(S) 부하 분산을 위한 인그레스는 GKE 인그레스 컨트롤러를 통해 내부 부하 분산을 위한 기본 지원을 제공합니다.

또한 내부 HTTP(S) 부하 분산을 위한 인그레스에서 내부 HTTP(S) 부하 분산을 위한 인그레스 작동 방법을 자세히 알아볼 수 있습니다.

환경 준비

내부 HTTP(S) 부하 분산기를 사용하기 위해 환경을 준비합니다.

  1. 부하 분산기 프록시를 지정된 리전에 배포할 수 있도록 네트워킹 환경을 준비합니다. 프록시 전용 서브넷을 배포하는 단계는 네트워크 및 서브넷 구성에서 설명합니다. GKE 인그레스 컨트롤러로 관리되므로 방화벽 규칙을 수동으로 배포할 필요가 없습니다. 인그레스를 배포하려면 먼저 이 단계를 완료해야 합니다.

  2. Kubernetes Ingress API를 통해 부하 분산기 리소스를 배포합니다. 이를 수행하기 위한 단계는 아래에 나와 있습니다.

내부 HTTP(S) 부하 분산용 인그레스 배포

다음 섹션을 사용하여 인그레스를 배포합니다.

1단계: 클러스터 만들기

이 단계에서는 사용 설정된 별칭 IP를 사용하여 빠른 출시 채널에서 클러스터를 만듭니다.

클러스터를 만들려면 다음 안내를 따르세요.

gcloud

gcloud container clusters create cluster-name \
--release-channel=rapid \
--enable-ip-alias \
--zone=zone-name \
--network=cluster-network

각 항목의 의미는 다음과 같습니다.

  • cluster-name은 클러스터에 대해 선택한 이름입니다.
  • --enable-ip-alias별칭 IP를 사용 설정합니다. 내부 HTTP(S) 부하 분산용 인그레스를 사용하는 클러스터는 VPC 기반(별칭 IP) 모드로 실행되어야 합니다. 자세한 내용은 VPC 기반 클러스터 만들기를 참조하세요.
  • --release-channel=rapid는 빠른 출시 채널에서 클러스터를 만듭니다. 내부 HTTP(S) 부하 분산용 인그레스는 GKE 버전 1.16.5-gke.1 이상에서 사용할 수 있습니다.
  • zone-name은 선택한 영역에 클러스터를 만듭니다. 네트워크 및 서브넷 구성에서 내부 HTTP(S) 부하 분산기에 대해 만든 프록시-서브넷과 동일한 리전에 있는 영역을 선택해야 합니다.
  • cluster-network는 클러스터를 만들려는 네트워크의 이름입니다. 이 네트워크는 프록시-서브넷과 동일한 VPC 네트워크에 있어야 합니다.

이 클러스터에는 HTTP 부하 분산도 사용 설정되어 있어야 합니다. 클러스터에는 기본적으로 HTTP 부하 분산이 사용 설정됩니다. 이를 사용 중지하지 마세요.

2단계: 웹 애플리케이션 배포

이 단계에서는 HTTPS 서버에서 포트 9376을 리슨하는 컨테이너 이미지를 사용하여 배포를 만듭니다. 이 배포는 애플리케이션에 대한 Pod를 관리합니다. 각 Pod는 애플리케이션 서버의 호스트 이름을 응답으로 반환하는 HTTPS 서버에 하나의 애플리케이션 컨테이너를 실행합니다. Pod의 기본 호스트 이름은 Pod의 이름입니다. 또한 컨테이너는 단계적 종료를 처리합니다.

아래에는 예시 배포 파일인 web-deployment.yaml이 표시되어 있습니다.

# web-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: hostname
  name: hostname-server
spec:
  selector:
    matchLabels:
      app: hostname
  minReadySeconds: 60
  replicas: 3
  template:
    metadata:
      labels:
        app: hostname
    spec:
      containers:
      - image: k8s.gcr.io/serve_hostname:v1.4
        name: hostname-server
        ports:
        - containerPort: 9376
          protocol: TCP
      terminationGracePeriodSeconds: 90

배포를 만든 후에는 클러스터에 리소스를 적용합니다.

리소스를 적용하려면 다음 안내를 따르세요.

kubectl apply -f web-deployment.yaml

3단계: 서비스를 네트워크 엔드포인트 그룹(NEG)으로 배포

이 단계에서는 서비스 리소스를 만듭니다. 서비스는 인그레스 컨트롤러가 백엔드 엔드포인트로 프로그래밍할 수 있도록 해당 라벨로 백엔드 컨테이너를 선택합니다. NEG 백엔드가 필요하기 때문에 인그레스를 통해 노출되는 서비스를 배포할 때 NEG 주석을 사용합니다. GKE 클러스터 1.17 이상 및 특정 조건에서는 컨테이너 기반 부하 분산이 기본값이며 명시적인 cloud.google.com/neg: '{"ingress": true}' 서비스 주석이 필요하지 않습니다.

annotations:
    cloud.google.com/neg: '{"ingress": true}'

NEG를 사용하면 인그레스 컨트롤러가 컨테이너 기반 부하 분산을 수행할 수 있습니다. 트래픽은 노드 IP 또는 kube-proxy 네트워킹을 횡단하지 않고 인그레스 프록시에서 Pod IP로 직접 부하 분산됩니다. 또한 Pod 준비 게이트가 구현되어 Kubernetes 준비 및 활성 확인뿐만 아니라 부하 분산기의 관점에서 Pod의 상태를 확인합니다. 이렇게 하면 Pod 시작, Pod 손실 또는 노드 손실과 같은 수명 주기 이벤트 중에 트래픽이 중단되지 않습니다.

NEG 주석이 해제된 상태로 있으면 인그레스 객체에서 내부 HTTP(S) 부하 분산기가 구성되지 않도록 방지하는 경고가 수신됩니다. 이 경우 Kubernetes 이벤트가 인그레스에서 생성됩니다. 다음은 이벤트 메시지의 예시입니다.

Message
-------
error while evaluating the ingress spec: could not find port "8080" in service "default/no-neg-svc"

NEG는 인그레스가 서비스를 참조할 때까지 생성되지 않습니다. NEG는 인그레스 및 해당 참조 서비스가 모두 존재할 때까지 Compute Engine에 표시되지 않습니다. NEG는 영역별 리소스이며, 멀티 영역 클러스터의 경우 영역 및 서비스를 기준으로 생성됩니다.

서비스를 만들려면 YAML 파일을 사용합니다. 아래 표시된 파일은 올바른 주석을 사용하는 예시 파일 web-service.yaml입니다.

# web-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: hostname
  namespace: default
  annotations:
    cloud.google.com/neg: '{"ingress": true}'
spec:
  ports:
  - name: host1
    port: 80
    protocol: TCP
    targetPort: 9376
  selector:
    app: hostname
  type: NodePort

서비스를 만든 후 클러스터에 리소스를 적용합니다.

kubectl apply -f web-service.yaml

4단계: 인그레스 배포

이 단계에서는 인그레스 컨트롤러를 통해 Compute Engine 부하 분산 배포를 트리거하는 인그레스 리소스를 만듭니다. 인그레스 내부 HTTP(S) 부하 분산에는 주석이 필요합니다.

annotations:
    kubernetes.io/ingress.class: "gce-internal"

사용자가 올바른 주석을 실수로 생략하여 애플리케이션을 공개적으로 노출하지 않도록 방지하려면 공개 부하 분산기 만들기에 대해 제한사항을 강제 적용하는 ID 및 액세스 관리(IAM) 정책을 구현합니다. 이렇게 하면 인그레스 및 서비스 리소스를 통해 내부 부하 분산기 만들기를 계속 허용하면서도 클러스터 전반의 공개 부하 분산기 배포가 차단됩니다.

인그레스 리소스를 배포하려면 다음 internal-ingress.yaml 파일을 복사하고 저장합니다.

# internal-ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: ilb-demo-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "gce-internal"
spec:
  backend:
    serviceName: hostname
    servicePort: 80

파일을 복사한 후에는 리소스를 클러스터에 적용합니다.

kubectl apply -f internal-ingress.yaml

5단계: 성공한 인그레스 배포 검사

인그레스 리소스가 완전히 프로비저닝되려면 몇 분 정도 걸릴 수 있습니다. 이 기간 동안 인그레스 컨트롤러는 전달 규칙, 백엔드 서비스, URL 맵, NEG와 같은 항목들을 만듭니다.

인그레스 리소스 상태를 검색하려면 다음 안내를 따르세요.

kubectl get ingress ilb-demo-ingress

다음과 비슷한 출력이 표시됩니다.

NAME               HOSTS    ADDRESS            PORTS     AGE
ilb-demo-ingress   *        10.128.0.58        80        59s

ADDRESS 필드가 채워지면 인그레스가 준비됩니다. 이 필드에 사용된 RFC 1918 주소는 VPC 안의 내부 IP를 나타냅니다. 내부 HTTP(S) 부하 분산기가 리전별 부하 분산기이기 때문에, VIP는 동일한 리전 및 VPC 내의 클라이언트에서만 액세스할 수 있습니다. 부하 분산기 VIP를 검색한 후에는 curl과 같은 도구를 사용하여 VPC 안에서 VIP로 HTTP GET 호출을 수행할 수 있습니다.

VPC 내에서 인그레스 VIP에 연결하려면 클러스터와 동일한 리전 및 네트워크 내에서 VM을 배포합니다.

이 VM을 배포하려면 다음 안내를 따르세요.

gcloud

gcloud compute instances create l7-ilb-client-us-central1-a \
--image-family=debian-9 \
--image-project=debian-cloud \
--network=default \
--subnet=default \
--zone=us-central1-a \
--tags=allow-ssh

VM 내에서 내부 VIP에 액세스하려면 curl을 사용합니다.

  # SSH in to the VM
  gcloud compute ssh l7-ilb-client-us-central1-a \
      --zone=us-central1-a

  # Use curl to access the internal application VIP
  curl 10.128.0.58
  hostname-server-6696cf5fc8-z4788

백엔드 컨테이너 중 하나의 호스트 이름과 성공한 HTTP 응답은 전체 부하 분산 경로가 올바르게 작동함을 나타냅니다.

클라이언트와 부하 분산기 간 HTTPS

내부 부하 분산용 인그레스는 클라이언트에 대한 TLS 인증서 제공을 지원합니다. 이 작업은 Kubernetes 보안 비밀 또는 미리 공유된 Google Cloud의 리전별 SSL 인증서를 통해 수행될 수 있습니다. 또한 인그레스 리소스별로 여러 인증서를 지정할 수도 있습니다.

다음 단계에서는 Google Cloud에서 인증서를 만들고 인그레스를 통해 내부 클라이언트에 제공하는 방법을 설명합니다.

  1. 리전별 인증서를 만듭니다.

    gcloud compute ssl-certificates create ingress-cert \
    --certificate cert-file --private-key key-file --region  region
    
  2. 인그레스를 만듭니다. 다음 ilb-demo-ing.yaml 파일은 만들려는 인그레스 리소스의 샘플입니다.

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: ilb-demo-ing
      namespace: default
      annotations:
        ingress.gcp.kubernetes.io/pre-shared-cert: "ingress-cert"
        kubernetes.io/ingress.class: "gce-internal"
        kubernetes.io/ingress.allow-http: "false"
    spec:
      rules:
      - host: your-domain
        http:
          paths:
          - backend:
              serviceName: hostname
              servicePort: 80
    
  3. 다음 명령어를 실행하여 인그레스를 만듭니다.

    kubectl apply -f ingress-ilb-demo-ing.yaml
    

인그레스 삭제

인그레스 및 서비스 리소스를 삭제하면 이와 연결된 Compute Engine 부하 분산기 리소스도 삭제됩니다. 리소스 누출을 방지하기 위해서는 더 이상 필요하지 않을 때 인그레스 리소스가 삭제되었는지 확인합니다. 클러스터를 삭제하기 전에 인그레스 및 서비스 리소스를 삭제해야 합니다. 그렇지 않으면 Compute Engine 부하 분산 리소스가 고립됩니다.

1단계: 인그레스 삭제

인그레스를 삭제하면 이 인그레스 리소스와 연결된 전달 규칙, 백엔드 서비스, URL 맵이 삭제됩니다.

인그레스를 삭제하려면 다음 안내를 따르세요.

kubectl delete ingress ilb-demo-ing

2단계: 서비스 삭제

서비스를 삭제하면 서비스와 연결된 NEG가 삭제됩니다.

서비스를 삭제하려면 다음 안내를 따르세요.

kubectl delete service hostname

내부 인그레스 주석 요약

인그레스 주석

주석 설명
kubernetes.io/ingress.class 내부 인그레스에 대해 'gce-internal'로 지정됩니다. 클래스가 지정되지 않았으면 기본적으로 인그레스 리소스가 외부 인그레스로 해석됩니다.
kubernetes.io/ingress.allow-http 클라이언트와 HTTP(S) 부하 분산기 간에 HTTP 트래픽을 허용할지 여부를 지정합니다. 가능한 값은 'true', 'false'입니다. 기본값은 'true'이지만, 내부 부하 분산을 위해 HTTPS를 사용하는 경우 'false'로 설정해야 합니다. HTTP 중지를 참조하세요.
ingress.gcp.kubernetes.io/pre-shared-cert Google Cloud 프로젝트에 인증서와 키를 업로드할 수 있습니다. 이 주석을 사용하여 인증서와 키를 참조합니다. HTTP(S) 부하 분산에서 여러 SSL 인증서 사용을 참조하세요.
주석 설명
beta.cloud.google.com/backend-config 이 주석을 사용하여 servicePort와 연결된 백엔드 서비스를 구성합니다. 자세한 내용은 인그레스 기능을 참조하세요.
cloud.google.com/neg 이 주석을 사용하여 부하 분산기에서 네트워크 엔드포인트 그룹을 사용하도록 지정합니다. 컨테이너 기반 부하 분산 사용을 참조하세요.

문제해결

인그레스 상태를 파악하고 관찰하기 위해서는 일반적으로 연관된 리소스를 조사하는 과정이 필요합니다. 자주 발생하는 문제 유형에는 올바르게 생성되지 않은 부하 분산 리소스, 백엔드에 연결되지 않는 트래픽, 정상 상태로 표시되지 않는 백엔드가 있습니다. 일반적인 문제해결 단계는 다음과 같습니다.

  • 클라이언트 트래픽이 부하 분산기와 동일한 리전 및 VPC 내에서 시작되는지 확인합니다.
  • 인그레스를 배포하는 동안 동기화 오류를 방지하기 위해 인그레스를 만들기 전에 프록시 전용 서브넷이 생성되었는지 확인합니다.
  • Pod와 백엔드가 정상 상태인지 확인합니다.
  • 방화벽 규칙으로 차단되지 않았는지 확인하기 위해 VIP에 대한 트래픽 경로를 확인하고 Compute Engine 상태를 검사합니다.
  • 인그레스 리소스 이벤트에 오류가 있는지 확인합니다.
  • 인그레스 리소스 상태를 기술하여 Compute Engine 리소스에 대한 매핑을 확인합니다.
  • Compute Engine LB 리소스가 존재하고, 올바른 구성을 포함하고, 보고된 오류가 없는지 확인합니다.

인그레스 이벤트 필터링

다음 쿼리는 클러스터에 있는 모든 인그레스 이벤트에서 오류를 필터링합니다.

kubectl get events --all-namespaces --field-selector involvedObject.kind=Ingress

또는 객체 또는 객체 이름으로 필터링할 수 있습니다.

kubectl get events --field-selector involvedObject.kind=Ingress,involvedObject.name=hostname-internal-ingress

이 오류에서는 인그레스에서 참조되는 서비스가 존재하지 않는 것을 확인할 수 있습니다.

LAST SEEN   TYPE      REASON      OBJECT                              MESSAGE
0s          Warning   Translate   ingress/hostname-internal-ingress   error while evaluating the ingress spec: could not find service "default/hostname-invalid"

Compute Engine 부하 분산기 리소스 검사

다음 명령어는 인그레스 컨트롤러로 생성되는 Compute Engine 리소스에 대한 매핑을 볼 수 있도록 인그레스 리소스의 전체 출력을 보여줍니다.

$ kubectl get ing ilb-demo-ing -o yaml

apiVersion: v1
items:
- apiVersion: networking.k8s.io/v1beta1
  kind: Ingress
  metadata:
    annotations:
      ingress.kubernetes.io/backends: '{"k8s1-241a2b5c-default-hostname-80-29269aa5":"HEALTHY"}'
      ingress.kubernetes.io/forwarding-rule: k8s-fw-default-ilb-demo-ingress--241a2b5c94b353ec
      ingress.kubernetes.io/target-proxy: k8s-tp-default-ilb-demo-ingress--241a2b5c94b353ec
      ingress.kubernetes.io/url-map: k8s-um-default-ilb-demo-ingress--241a2b5c94b353ec
      kubectl.kubernetes.io/last-applied-configuration: |
       {"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"gce-internal"},"name":"ilb-demo-ingress","namespace":"default"},"spec":{"backend":{"serviceName":"hostname","servicePort":80}}}
      kubernetes.io/ingress.class: gce-internal
    creationTimestamp: "2019-10-15T02:16:18Z"
    finalizers:
    - networking.gke.io/ingress-finalizer
    generation: 1
    name: ilb-demo-ingress
    namespace: default
    resourceVersion: "1538072"
    selfLink: /apis/networking.k8s.io/v1beta1/namespaces/default/ingresses/ilb-demo-ingress
    uid: 0ef024fe-6aea-4ee0-85f6-c2578f554975
  spec:
    backend:
      serviceName: hostname
      servicePort: 80
  status:
    loadBalancer:
      ingress:
      - ip: 10.128.0.127
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

ingress.kubernetes.io/backends 주석에는 백엔드 및 해당 상태가 나열됩니다. 백엔드가 HEALTHY로 나열되는지 확인합니다.

인그레스로 생성된 Compute Engine 리소스를 직접 쿼리하여 해당 상태 및 구성을 확인할 수 있습니다. 이렇게 하면 문제해결에 도움이 될 수 있습니다.

모든 Compute Engine 전달 규칙을 나열하려면 다음 안내를 따르세요.

gcloud compute forwarding-rules list

예상 출력:

NAME                                                        REGION       IP_ADDRESS      IP_PROTOCOL  TARGET
k8s-fw-default-hostname-internal-ingress--42084f6a534c335b  us-central1  10.128.15.225   TCP          us-central1/targetHttpProxies/k8s-tp-default-hostname-internal-ingress--42084f6a534c335b

모든 BackendServices의 상태를 나열하려면 다음 안내를 따르세요.

gcloud compute backend-services list

NAME                                         BACKENDS                                                                                                                                                                                                      PROTOCOL
k8s1-42084f6a-default-hostname-80-98cbc1c1   us-central1-a/networkEndpointGroups/k8s1-42084f6a-default-hostname-80-98cbc1c1                                                                                                                                HTTP
#Query the health of your BackendService
gcloud compute backend-services get-health k8s1-42084f6a-default-hostname-80-98cbc1c1 --region us-central1
---
backend: https://www.googleapis.com/compute/v1/projects/user1-243723/zones/us-central1-a/networkEndpointGroups/k8s1-42084f6a-default-hostname-80-98cbc1c1
status:
  healthStatus:
  - healthState: HEALTHY

다음 단계