에지에서 메시로: GKE 인그레스를 통해 서비스 메시 애플리케이션 노출

이 가이드에서는 Anthos Service Mesh와 Cloud Load Balancing을 결합하여 서비스 메시의 애플리케이션을 인터넷 클라이언트에 노출하는 방법을 보여줍니다.

Anthos Service Mesh는 Istio 기반의 관리형 서비스 메시로, 보안이 강화되고 관측 가능성이 높은 표준화된 애플리케이션 통신 레이어를 제공합니다. Anthos Service Mesh, Traffic Director, Istio 중 무엇을 사용하든 서비스 메시는 메시에서 통신 중인 클라이언트를 위한 종합적인 통신 플랫폼을 제공합니다. 그러나 메시 외부에 있는 클라이언트를 메시에서 호스팅된 애플리케이션에 연결하는 방법은 여전히 해결해야 할 문제입니다.

클라이언트 위치에 따라 여러 가지 방법으로 클라이언트에 애플리케이션을 노출할 수 있습니다. 이 가이드에서는 부하 분산기를 서비스 메시에 통합하기 위해 Cloud Load Balancing을 Anthos Service Mesh와 결합하여 클라이언트에 애플리케이션을 노출하는 방법을 보여줍니다. 이 튜토리얼은 Anthos Service Mesh를 실행하는 고급 실무자를 대상으로 하지만 Google Kubernetes Engine의 Istio에도 적용됩니다.

메시 인그레스 게이트웨이

Istio 0.8은 서비스 메시의 외부에서 들어오는 트래픽에 포트가 노출되는 전용 프록시 집합을 제공하는 메시 인그레스 게이트웨이를 도입했습니다. 이러한 메시 인그레스 프록시를 사용하면 L4 노출 동작과 애플리케이션 라우팅 동작을 별도로 제어할 수 있습니다. 또한 프록시를 사용하면 트래픽이 애플리케이션 사이드카에 도달하기 전에 라우팅 및 정책을 메시 외부에 있는 트래픽에 적용할 수 있습니다. 메시 인그레스는 메시의 모드에 도착한 트래픽 처리를 정의하지만 외부 구성요소는 트래픽이 처음 메시에 도착하는 방법을 정의해야 합니다.

이 외부 트래픽을 관리하려면 메시 외부에 부하 분산기가 있어야 합니다. 이 가이드에서는 GKE 인그레스 리소스를 통해 프로비저닝된 Google Cloud Load Balancing을 사용하여 배포를 자동화합니다. 이 설정의 표준 예시는 Google Cloud의 경우 공용 TCP/UDP 부하 분산기를 배포하는 외부 부하 분산 서비스입니다. 이 부하 분산기는 GKE 클러스터의 NodePort를 가리킵니다. 이러한 NodePort는 트래픽을 다운스트림 메시 사이드카 프록시로 라우팅하는 Istio 인그레스 게이트웨이 pod를 노출합니다. 이 토폴로지를 다이어그램으로 나타내면 다음과 같습니다. 내부 비공개 트래픽의 부하 분산은 이 아키텍처와 유사하지만 내부 TCP/UDP 부하 분산기를 배포한다는 점이 다릅니다.

외부 부하 분산기는 외부 클라이언트를 인그레스 게이트웨이 프록시를 통해 메시로 라우팅합니다.

메시 인그레스 게이트웨이를 통해 투명한 L4 부하 분산을 사용하면 다음과 같은 이점이 있습니다.

  • 이 설정은 부하 분산기의 배포를 간소화합니다.
  • 부하 분산기는 클러스터 변경, 노드 중단 또는 프로세스 중단이 발생할 때 안정적인 가상 IP(VIP), 상태 확인, 안정적인 트래픽 분산을 제공합니다.
  • 모든 라우팅 규칙, TLS 종료, 트래픽 정책은 메시 인그레스 게이트웨이의 단일 위치에서 처리됩니다.

GKE 인그레스 및 서비스

클러스터 외부에 있는 클라이언트의 애플리케이션에 대한 액세스 권한을 여러 가지 방법으로 제공할 수 있습니다. 다음 표에는 Google Cloud에서 부하 분산기를 배포하는 데 사용할 수 있는 Kubernetes 기본 요소가 나와 있습니다. 클라이언트에 애플리케이션을 노출하는 데 사용된 부하 분산기의 유형은 클라이언트가 외부에 있는지 또는 내부에 있는지, 필요한 프로토콜 지원 유형이 무엇인지, 서비스 메시가 여러 GKE 클러스터에 걸쳐 있는지 또는 단일 클러스터에 포함되어 있는지에 따라 달라집니다.

다음 표에 나와 있는 모든 부하 분산기 유형은 사용 사례에 따라 메시에서 호스팅된 애플리케이션에 노출될 수 있습니다.

GKE 리소스 클라우드 기반 부하 분산기 특성
외부 HTTP(S) 부하 분산용 인그레스 외부 HTTP(S) 부하 분산기

Google 에지 접속 지점(PoP)의 L7 프록시

공개 VIP

전역 범위

단일 클러스터

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

Virtual Private Cloud(VPC) 네트워크 내의 L7 프록시

비공개 VIP

리전 범위

단일 클러스터

외부 LoadBalancer 서비스 외부 TCP/UDP 부하 분산기

Google 에지 PoP에서 L4 패스스루

공개 VIP

리전 범위

단일 클러스터

내부 LoadBalancer 서비스 내부 TCP/UDP 부하 분산기

VPC 라우팅 네트워크에서 L4 패스스루

비공개 VIP

리전 범위

단일 클러스터

멀티 클러스터 인그레스(멀티 클러스터, 외부 인그레스) 외부 HTTP(S) 부하 분산기

Google 에지 PoP에서 L7 프록시

공개 VIP

전역 범위

멀티 클러스터

Anthos Service Mesh의 기본 부하 분산기를 외부 TCP/UDP 부하 분산기이지만, 이 가이드에서는 외부 HTTP(S) 부하 분산을 사용하여 배포하는 외부 HTTP(S) 부하 분산기에 중점을 둡니다. 외부 HTTP(S) 부하 분산기는 IAP(Identity-Aware Proxy), Google Cloud Armor, Cloud CDN과 같은 에지 서비스는 물론 전 세계에 분산된 에지 프록시의 네트워크에 통합될 수 있습니다. 다음 섹션에서는 두 레이어의 HTTP 부하 분산을 사용하는 경우의 아키텍처와 이점을 설명합니다.

클라우드 인그레스 및 메시 인그레스

외부 L7 부하 분산을 메시 인그레스 레이어와 함께 메시 외부에 배포하면 인터넷 트래픽에 상당한 이점을 제공합니다. Anthos Service Mesh 및 Istio 인그레스 게이트웨이는 메시에서 고급 라우팅 및 트래픽 관리를 제공하지만 일부 기능은 네트워크 에지에 보다 효과적으로 제공됩니다. Google Cloud의 외부 HTTP(S) 부하 분산을 통해 인터넷 에지 네트워킹을 활용하면 메시 기반 인그레스에 비해 성능과 안정성이 대폭 향상되고 보안 관련 이점을 제공할 수 있습니다. 이점은 다음과 같습니다.

이 L7 부하 분산의 외부 레이어는 메시 인그레스에 사용되는 자체 호스팅 프록시 대신 클라우드 관리 부하 분산기를 기반으로 빌드되기 때문에 클라우드 인그레스라고 합니다. 클라우드 인그레스와 메시 인그레스의 조합은 Google Cloud 인프라와 메시를 상호 보완하는 기능을 활용합니다. 다음 다이어그램은 클라우드 인그레스와 메시 인그레스를 결합하여 인터넷 트래픽을 위한 두 가지 부하 분산 레이어로 사용하는 방법을 보여줍니다.

클라우드 인그레스는 VPC 네트워크를 통해 메시에 대한 외부 트래픽의 게이트웨이 역할을 합니다.

이 토폴로지에서 클라우드 인그레스 레이어는 서비스 메시 외부에서 유입되는 트래픽을 수집하고 이 트래픽을 메시 인그레스 레이어로 전달합니다. 그러면 메시 인그레스 레이어가 메시에서 호스팅된 애플리케이션 백엔드로 트래픽을 전달합니다.

클라우드 및 메시 인그레스 토폴로지

이 섹션에서는 각 인그레스 레이어를 함께 사용할 때 충족되는 보완 역할을 설명합니다. 이러한 역할은 구체적인 규칙이 아니라 각 레이어의 이점을 사용하는 가이드라인입니다. 사용 사례에 따라 이 패턴이 달라질 수 있습니다.

  • 클라우드 인그레스. 메시 인그레스와 함께 사용하는 클라우드 인그레스는 에지 보안과 글로벌 부하 분산에 가장 적합합니다. 클라우드 인그레스 레이어는 에지의 DDoS 보호, 클라우드 방화벽, 인증, 암호화 제품과 통합되므로 메시 외부에서 이러한 서비스를 실행하는 데 진가를 발휘합니다. 일반적으로 라우팅 로직은 간단하지만 멀티 클러스터 및 멀티 리전 환경에서는 더 복잡합니다. 인터넷 연결용 부하 분산기의 중요한 기능 때문에 클라우드 인그레스 레이어는 인터넷에서 애플리케이션을 노출하고 보호하는 방법을 독점적으로 제어하는 인프라 팀에 의해 관리될 가능성이 높습니다. 또한 이러한 제어 기능으로 인해 이 레이어는 개발자 중심의 인프라보다 동적 유연성이 저하되므로 이 레이어에 대한 관리 액세스를 제공하는 사용자와 방법에 영향을 미칠 수 있습니다.
  • 메시 인그레스. 메시 인그레스는 클라우드 인그레스와 함께 사용할 경우 애플리케이션에 가까운 유연한 라우팅을 제공합니다. 이러한 유연성 덕분에 메시 인그레스는 클라우드 인그레스보다 복잡한 라우팅 로직과 애플리케이션 수준 가시성에 더 적합합니다. 또한 인그레스 레이어를 분리할 경우 애플리케이션 소유자는 다른 팀에 영향을 미치지 않고도 이 레이어를 직접 더 쉽게 제어할 수 있습니다. L7 부하 분산기 대신 L4 부하 분산기를 통해 서비스 메시 애플리케이션을 노출하는 경우 애플리케이션을 보호하기 위해 메시 내부의 메시 인그레스 레이어에서 클라이언트 TLS를 종료해야 합니다.

상태 확인

L7 부하 분산의 두 레이어를 사용하는 경우의 한 가지 복잡성은 상태 확인입니다. 다음 레이어에서 트래픽을 수신할 수 있는지 상태를 확인하도록 각 부하 분산기를 구성해야 합니다. 다음 다이어그램의 토폴로지는 클라우드 인그레스에서 메시 인그레스 프록시의 상태를 확인하고 메시에서 애플리케이션 백엔드의 상태를 확인하는 방법을 보여줍니다.

클라우드 인그레스에서 메시 인그레스의 상태를 확인하고 메시 인그레스는 애플리케이션 백엔드의 상태를 확인합니다.

이 토폴로지에서는 다음을 고려해야 합니다.

  • 클라우드 인그레스. 이 가이드에서는 인그레스를 통해 노출된 상태 확인 포트에서 메시 인그레스 프록시의 상태를 확인하도록 Google Cloud 부하 분산기를 구성합니다. 메시 프록시가 중단되거나 클러스터, 메시 또는 리전을 사용할 수 없는 경우 Googld Cloud 부하 분산기가 이 상태를 감지하여 트래픽을 메시 프록시로 전송하지 않습니다.
  • 메시 인그레스. 메시 애플리케이션에서는 로컬로 부하 분산 및 트래픽 관리를 실행할 수 있도록 백엔드에서 직접 상태 검사를 수행합니다.

보안

위 토폴로지에는 보안의 여러 요소가 포함되어 있습니다. 가장 중요한 요소 중 하나는 암호화를 구성하고 인증서를 배포하는 방법입니다. 외부 HTTP(S) 부하 분산용 인그레스Google 관리 인증서와 긴밀하게 통합됩니다. 이 통합은 공개 인증서를 자동으로 프로비저닝한 후 부하 분산기에 연결하고 선언적 GKE 인그레스 인터페이스를 통해 인증서를 모두 갱신하고 순환합니다. 인터넷 클라이언트는 공개 인증서로 인증하고 Virtual Private Cloud(VPC)에서 첫 번째 홉으로 외부 부하 분산기에 연결합니다.

Google 프런트엔드(GFE)와 메시 인그레스 프록시 사이에 있는 다음 홉은 기본적으로 암호화됩니다. GFE와 백엔드 간의 네트워크 수준 암호화는 자동으로 적용됩니다. 그러나 보안 요구사항에 따라 플랫폼 소유자가 암호화 키의 소유권을 보유해야 할 경우 클러스터 인그레스(GFE)와 메시 인그레스(envoy 프록시 인스턴스) 간에 TLS 암호화로 HTTP/2를 사용 설정할 수 있습니다. 이 경로에 대해 TLS 암호화로 HTTP/2를 사용 설정하는 경우 GFE가 인증을 이에 대해 수행하지 않기 때문에 자체 서명 또는 공개 인증서를 사용하여 트래픽을 암호화할 수 있습니다. 이 가이드에서 추가 암호화 레이어에 대해 설명합니다. 인증서의 잘못된 처리를 방지하기 위해 다른 곳에서 공용 부사 분산기의 공개 인증서를 사용하지 마세요. 대신 서비스 메시에는 별도의 인증서를 사용하는 것이 좋습니다.

서비스 메시에 TLS가 필요한 경우 모든 트래픽이 사이드카 프록시 간과 메시 인그레스로 암호화됩니다. 다음 다이어그램은 클라이언트에서 Google Cloud 부하 분산기, 부하 분산기에서 메시 인그레스 프록시, 인그레스 프록시에서 사이드카 프록시로 HTTPS 암호화를 보여줍니다.

메시 외부의 관리형 인증서와 메시 내부의 내부 인증서를 사용하여 보안이 구현됩니다.

목표

  • Google Cloud에 Google Kubernetes Engine(GKE) 클러스터를 배포합니다.
  • GKE 클러스터에 Istio 기반 Anthos Service Mesh를 배포합니다.
  • 공개 HTTPS 트래픽을 종료한 후 이 트래픽이 서비스 메시에서 호스팅되는 애플리케이션으로 전달되도록 GKE 인그레스를 구성합니다.
  • 인터넷에서 클라이언트에 노출되는 GKE 클러스터에 Online Boutique 애플리케이션을 배포합니다.

비용

이 가이드에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

이 튜토리얼을 마치면 만든 리소스를 삭제하여 비용이 계속 청구되지 않게 할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

  1. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  2. Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요.

  3. 콘솔에서 Cloud Shell을 활성화합니다.

    Cloud Shell 활성화

    이 가이드의 모든 터미널 명령어는 Cloud Shell에서 실행됩니다.

  4. Google Cloud CLI를 최신 버전으로 업그레이드합니다.

    gcloud components update
    
  5. 기본 Google Cloud 프로젝트를 설정합니다.

    export PROJECT=$(gcloud info --format='value(config.project)')
    export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT} --format="value(projectNumber)")
    gcloud config set project ${PROJECT}
    
  6. 작업 디렉터리를 만듭니다.

    mkdir -p ${HOME}/edge-to-mesh
    cd ${HOME}/edge-to-mesh
    export WORKDIR=`pwd`
    

    가이드를 마친 후 작업 디렉터리를 삭제할 수 있습니다.

GKE 클러스터 만들기

이 가이드에서 설명하는 기능에는 GKE 클러스터 버전 1.16 이상이 필요합니다.

  1. Cloud Shell에서 새 kubeconfig 파일을 만듭니다. 이 단계를 수행하면 기존의 기본 kubeconfig 파일과 충돌이 발생하지 않습니다.

    touch edge2mesh_kubeconfig
    export KUBECONFIG=${WORKDIR}/edge2mesh_kubeconfig
    
  2. GKE 클러스터의 환경 변수를 정의합니다.

    export CLUSTER_NAME=edge-to-mesh
    export CLUSTER_LOCATION=us-west1-a
    
  3. Google Kubernetes Engine API를 사용 설정합니다.

    gcloud services enable container.googleapis.com
    
  4. GKE 클러스터 만들기

    gcloud container clusters create ${CLUSTER_NAME} \
        --machine-type=e2-standard-4 \
        --num-nodes=4 \
        --zone ${CLUSTER_LOCATION} \
        --enable-ip-alias \
        --workload-pool=${PROJECT}.svc.id.goog \
        --release-channel rapid \
        --addons HttpLoadBalancing \
        --labels mesh_id=proj-${PROJECT_NUMBER}
    

    클라우드 인그레스를 사용하려면 HTTP 부하 분산 부가기능을 사용 설정해야 합니다. GKE 클러스터에는 기본적으로 HTTP 부하 분산이 사용 설정되어 있으며 사용 중지하면 안 됩니다.

    관리형 Anthos Service Mesh를 사용하려면 클러스터에 mesh_id 라벨을 적용해야 합니다.

  5. 클러스터가 실행 중인지 확인합니다.

    gcloud container clusters list
    

    출력은 다음과 비슷합니다.

    NAME          LOCATION    MASTER_VERSION    MASTER_IP      MACHINE_TYPE   NODE_VERSION      NUM_NODES  STATUS
    edge-to-mesh  us-west1-a  v1.22.6-gke.300   35.233.195.59  e2-standard-4  v1.22.6-gke.300   4          RUNNING
    
  6. 클러스터에 연결합니다.

    gcloud container clusters get-credentials ${CLUSTER_NAME} \
        --zone ${CLUSTER_LOCATION} \
        --project ${PROJECT}
    

서비스 메시 설치

이 섹션에서는 Fleet API로 관리형 Anthos Service Mesh를 구성합니다.

  1. 필요한 API를 사용 설정합니다.

    gcloud services enable \
        gkehub.googleapis.com \
        mesh.googleapis.com
    

    또한 Google Cloud Console에서 Anthos Service Mesh 기능을 사용하려면 anthos.googleapis.com API를 사용 설정해야 합니다. 이 API를 사용 설정하면 Anthos Service Mesh 가격 책정이 독립형에서 Anthos로 변경됩니다.

  2. Fleet에서 Anthos Service Mesh를 사용 설정합니다.

    gcloud container fleet mesh enable
    
  3. Fleet에 클러스터를 등록합니다.

    gcloud container fleet memberships register ${CLUSTER_NAME} \
        --gke-cluster ${CLUSTER_LOCATION}/${CLUSTER_NAME} \
        --enable-workload-identity
    
  4. 자동 제어 영역 관리를 사용 설정합니다.

    gcloud container fleet mesh update \
        --control-plane automatic \
        --memberships ${CLUSTER_NAME}
    
  5. 몇 분 후 제어 영역 상태가 ACTIVE인지 확인합니다.

    gcloud container fleet mesh describe
    

    출력은 다음과 비슷합니다.

    ...
    membershipSpecs:
      projects/746296320118/locations/global/memberships/edge-to-mesh:
        mesh:
          controlPlane: AUTOMATIC
    membershipStates:
      projects/746296320118/locations/global/memberships/edge-to-mesh:
        servicemesh:
          controlPlaneManagement:
            details:
            - code: REVISION_READY
              details: 'Ready: asm-managed-rapid'
            state: ACTIVE
        state:
          code: OK
          description: |-
            Revision(s) ready for use: asm-managed-rapid.
            All Canonical Services have been reconciled successfully.
          updateTime: '2022-03-09T02:47:51.187247972Z'
    name: projects/your-project/locations/global/features/servicemesh
    resourceState:
      state: ACTIVE
    ...
    

GKE 인그레스 배포

다음 단계에서는 GKE의 인그레스 컨트롤러를 통해 외부 HTTP(S) 부하 분산기를 배포합니다. 인그레스 리소스는 부하 분산기, 관련 TLS 인증서, 백엔드 상태 확인을 자동으로 프로비저닝합니다. 또한 Cloud Endpoints를 사용하여 애플리케이션의 공개 DNS 이름을 자동으로 프로비저닝합니다.

인그레스 게이트웨이 설치

보안 권장사항으로 제어 영역과 다른 네임스페이스에 인그레스 게이트웨이를 배포하는 것이 좋습니다.

  1. Cloud Shell에서 전용 asm-ingress 네임스페이스를 만듭니다.

    kubectl create namespace asm-ingress
    
  2. 네임스페이스 라벨을 asm-ingress 네임스페이스에 추가합니다.

    kubectl label namespace asm-ingress istio-injection=enabled
    

    출력은 다음과 비슷합니다.

    namespace/asm-ingress labeled
    

    asm-ingress 네임스페이스에 istio-injection=enabled 라벨을 지정하면 애플리케이션이 배포될 때 Anthos Service Mesh가 Envoy 사이드카 프록시를 자동으로 삽입합니다.

  3. 다음 명령어를 실행하여 Deployment 매니페스트를 ingress-deployment.yaml로 만듭니다.

    cat <<EOF > ingress-deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      selector:
        matchLabels:
          asm: ingressgateway
      template:
        metadata:
          annotations:
            # This is required to tell Anthos Service Mesh to inject the gateway with the
            # required configuration.
            inject.istio.io/templates: gateway
          labels:
            asm: ingressgateway
        spec:
          containers:
          - name: istio-proxy
            image: auto # The image will automatically update each time the pod starts.
            resources:
              limits:
                cpu: 2000m
                memory: 1024Mi
              requests:
                cpu: 100m
                memory: 128Mi
          serviceAccountName: asm-ingressgateway
    ---
    apiVersion: autoscaling/v2beta1
    kind: HorizontalPodAutoscaler
    metadata:
      name: asm-ingressgateway
    spec:
      maxReplicas: 5
      metrics:
      - resource:
          name: cpu
          targetAverageUtilization: 80
        type: Resource
      minReplicas: 3
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: asm-ingressgateway
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: asm-ingressgateway
    subjects:
      - kind: ServiceAccount
        name: asm-ingressgateway
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    EOF
    

    Deployment에는 게이트웨이가 인증서에 액세스할 수 있도록 연결된 RoleRoleBinding이 포함된 자체 ServiceAccount가 있습니다.

  4. 클러스터에 ingress-deployment.yaml을 배포하여 Deployment 리소스를 만듭니다.

    kubectl apply -f ingress-deployment.yaml
    

    출력은 다음과 비슷합니다.

    deployment.apps/asm-ingressgateway configured
    role.rbac.authorization.k8s.io/asm-ingressgateway configured
    rolebinding.rbac.authorization.k8s.io/asm-ingressgateway configured
    serviceaccount/asm-ingressgateway created
    

    모든 배포가 실행 중인지 확인합니다.

    kubectl wait --for=condition=available --timeout=600s deployment --all -n asm-ingress
    

    출력은 다음과 비슷합니다.

    deployment.apps/asm-ingressgateway condition met
    
  5. 다음 명령어를 실행하여 Service 매니페스트를 ingress-service.yaml로 만듭니다.

    cat <<EOF > ingress-service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
      annotations:
        cloud.google.com/neg: '{"ingress": true}'
        cloud.google.com/backend-config: '{"default": "ingress-backendconfig"}'
        cloud.google.com/app-protocols: '{"https":"HTTP2"}' # HTTP/2 with TLS encryption
      labels:
        asm: ingressgateway
    spec:
      ports:
      # status-port exposes a /healthz/ready endpoint that can be used with GKE Ingress health checks
      - name: status-port
        port: 15021
        protocol: TCP
        targetPort: 15021
      # Any ports exposed in Gateway resources should be exposed here.
      - name: http2
        port: 80
      - name: https
        port: 443
      selector:
        asm: ingressgateway
      type: ClusterIP
    EOF
    

    Service에는 배포된 인그레스 부하 분산기의 매개변수를 설정하는 다음과 같은 주석이 있습니다.

    • cloud.google.com/backend-configBackendConfig라는 커스텀 리소스의 이름을 나타냅니다. 인그레스 컨트롤러는 BackendConfig를 사용하여 Google Cloud BackendService 리소스에서 매개변수를 설정합니다. 다음 단계에서 이 리소스를 사용하여 Google Cloud 상태 확인의 커스텀 매개변수를 정의합니다.
    • cloud.google.com/neg: '{"ingress": true}'는 컨테이너 기반 부하 분산에 인그레스 백엔드(이 경우 메시 인그레스 프록시)를 사용 설정합니다. 보다 효율적이고 안정적인 부하 분산을 위해 이러한 백엔드는 인스턴스 그룹 대신 네트워크 엔드포인트 그룹(NEG)을 사용합니다.
    • cloud.google.com/app-protocols: '{"https":"HTTP2"}'는 추가 암호화 레이어를 위해 외부 HTTP(S) 부하 분산용 인그레스외부 HTTP(S) 부하 분산 개요에 설명된 대로 TLS와 HTTP2를 사용하여 서비스 메시의 인그레스 게이트웨이에 연결하도록 GFE에 지시합니다.
  6. 클러스터에 ingress-service.yaml을 배포하여 Service 리소스를 만듭니다.

    kubectl apply -f ingress-service.yaml
    

    출력은 다음과 비슷합니다.

    service/asm-ingressgateway created
    

백엔드 서비스 설정 적용

  1. Cloud Shell에서 다음 명령어를 실행하여 BackendConfig 매니페스트를 ingress-backendconfig.yaml로 만듭니다.

    cat <<EOF > ingress-backendconfig.yaml
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: ingress-backendconfig
      namespace: asm-ingress
    spec:
      healthCheck:
        requestPath: /healthz/ready
        port: 15021
        type: HTTP
      securityPolicy:
        name: edge-fw-policy
    EOF
    

    BackendConfig는 인그레스 부하 분산의 백엔드 매개변수를 정의하는 커스텀 리소스 정의(CRD)입니다. GKE 인그레스를 통해 구성할 수 있는 백엔드 및 프런트엔드 매개변수의 전체 목록은 인그레스 기능을 참조하세요.

    이 가이드에서 BackendConfig 매니페스트는 메시 인그레스 프록시의 커스텀 상태 확인을 지정합니다. Anthos Service Mesh 및 Istio는 /healthz/ready 경로의 포트 15021에서 사이드카 프록시 상태 확인을 노출합니다. 메시 인그레스 프록시의 제공 포트(443)가 상태 확인 포트(15021)와 다르기 때문에 커스텀 상태 확인 매개변수가 필요합니다. GKE 인그레스는 BackendConfig에서 다음 상태 확인 매개변수를 사용하여 Google Cloud 부하 분산기 상태 확인을 구성합니다. 다양한 종류의 네트워크 공격으로부터 부하 분산 트래픽을 보호하는 데 도움이 되는 보안 정책도 참조됩니다.

    • healthCheck.port는 각 pod의 IP 주소에서 Google Cloud 부하 분산기로 상태 확인을 수신하는 포트를 정의합니다.
    • healthCheck.requestPath는 지정된 포트에서 상태 확인을 수신하는 HTTP 경로를 정의합니다.
    • type은 상태 확인에 사용되는 프로토콜을 정의합니다(이 경우 HTTP).
    • securityPolicy.nameCloud Armor 보안 정책의 이름을 나타냅니다.
  2. 클러스터에 ingress-backendconfig.yaml을 배포하여 BackendConfig 리소스를 만듭니다.

    kubectl apply -f ingress-backendconfig.yaml
    

    출력은 다음과 비슷합니다.

    backendconfig.cloud.google.com/ingress-backendconfig created
    

    BackendConfig 매개변수와 asm-ingressgateway 서비스 주석은 인그레스 리소스가 배포될 때까지 Google Cloud 부하 분산기에 적용되지 않습니다. 인그레스 배포는 이러한 모든 리소스를 하나로 결합합니다.

보안 정책 정의

Google Cloud Armor는 인그레스 리소스를 통해 부하 분산기에 연결할 수 있는 DDoS 방어 및 맞춤설정 가능한 보안 정책을 제공합니다. 다음 단계에서는 사전 구성된 규칙을 사용하여 교차 사이트 스크립팅(XSS) 공격을 차단하는 보안 정책을 만듭니다. 이 규칙은 알려진 공격 서명과 일치하지만 다른 모든 트래픽을 허용하는 트래픽을 차단합니다. 환경에 적용되는 규칙은 워크로드에 따라 달라질 수 있습니다.

  1. Cloud Shell에서 edge-fw-policy라는 보안 정책을 만듭니다.

    gcloud compute security-policies create edge-fw-policy \
        --description "Block XSS attacks"
    
  2. 사전 구성된 XSS 필터를 사용하는 보안 정책 규칙을 만듭니다.

    gcloud compute security-policies rules create 1000 \
        --security-policy edge-fw-policy \
        --expression "evaluatePreconfiguredExpr('xss-stable')" \
        --action "deny-403" \
        --description "XSS attack filtering"
    

edge-fw-policy는 이전 섹션의 ingress-backendconfig에서 참조되었습니다. 배포된 인그레스 리소스는 이 보안 정책을 부하 분산기와 결합하여 asm-ingressgateway 서비스의 백엔드를 보호합니다.

IP 주소 지정 및 DNS 구성

  1. Cloud Shell에서 Google Cloud 부하 분산기의 전역 고정 IP를 만듭니다.

    gcloud compute addresses create ingress-ip --global
    

    이 고정 IP는 인그레스 리소스에서 사용되며 외부 부하 분산기가 변경되더라도 IP가 동일하게 유지됩니다.

  2. 고정 IP 주소를 가져옵니다.

    export GCLB_IP=$(gcloud compute addresses describe ingress-ip --global --format "value(address)")
    echo ${GCLB_IP}
    

    인그레스 IP에 대해 사용자 친화적이고 안정적인 매핑을 만들려면 공개 DNS 레코드가 있어야 합니다. 원하는 DNS 제공업체 및 자동화를 사용할 수 있습니다. 이 가이드에서는 관리형 DNS 영역을 만드는 대신 Endpoints를 사용합니다. Endpoints는 공개 IP에 무료 Google 관리 DNS 레코드를 제공합니다.

  3. 다음 명령어를 실행하여 dns-spec.yaml이라는 YAML 사양 파일을 만듭니다.

    cat <<EOF > dns-spec.yaml
    swagger: "2.0"
    info:
      description: "Cloud Endpoints DNS"
      title: "Cloud Endpoints DNS"
      version: "1.0.0"
    paths: {}
    host: "frontend.endpoints.${PROJECT}.cloud.goog"
    x-google-endpoints:
    - name: "frontend.endpoints.${PROJECT}.cloud.goog"
      target: "${GCLB_IP}"
    EOF
    

    YAML 사양은 공개 DNS 레코드를 frontend.endpoints.${PROJECT}.cloud.goog 형식으로 정의합니다. 여기서 ${PROJECT}는 고유한 프로젝트 번호입니다.

  4. Cloud 프로젝트에 dns-spec.yaml 파일을 배포합니다.

    gcloud endpoints services deploy dns-spec.yaml
    

    출력은 다음과 비슷합니다.

    Operation finished successfully. The following command can describe the Operation details:
     gcloud endpoints operations describe operations/rollouts.frontend.endpoints.edge2mesh.cloud.goog:442b2b38-4aee-4c60-b9fc-28731657ee08
    
    Service Configuration [2021-11-14r0] uploaded for service [frontend.endpoints.edge2mesh.cloud.goog]
    

    이제 IP와 DNS가 구성되었으므로 공개 인증서를 생성하여 인그레스 프런트엔드를 보호할 수 있습니다. GKE 인그레스는 선언적 방식을 통해 인증서를 프로비저닝할 수 있도록 Kubernetes 리소스로 Google 관리 인증서를 지원합니다.

TLS 인증서 프로비저닝

  1. Cloud Shell에서 다음 명령어를 실행하여 ManagedCertificate 매니페스트를 managed-cert.yaml로 만듭니다.

    cat <<EOF > managed-cert.yaml
    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: gke-ingress-cert
      namespace: asm-ingress
    spec:
      domains:
        - "frontend.endpoints.${PROJECT}.cloud.goog"
    EOF
    

    이 YAML 파일은 Endpoints를 통해 생성된 DNS 이름이 공개 인증서를 프로비저닝하는 데 사용되도록 지정합니다. Google은 이러한 공개 인증서의 수명 주기를 완벽하게 관리하므로 공개 인증서는 사용자의 직접적인 개입 없이도 정기적으로 자동 생성되고 순환됩니다.

  2. GKE 클러스터에 managed-cert.yaml 파일을 배포합니다.

    kubectl apply -f managed-cert.yaml
    

    출력은 다음과 비슷합니다.

    managedcertificate.networking.gke.io/gke-ingress-cert created
    
  3. ManagedCertificate 리소스를 검사하여 인증서 생성 진행 상황을 확인합니다.

    kubectl describe managedcertificate gke-ingress-cert -n asm-ingress
    

    출력은 다음과 비슷합니다.

    Name:         gke-ingress-cert
    Namespace:    asm-ingress
    Labels:       <none>
    Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                    {"apiVersion":"networking.gke.io/v1","kind":"ManagedCertificate","metadata":{"annotations":{},"name":"gke-ingress-cert","namespace":"...
    API Version:  networking.gke.io/v1
    Kind:         ManagedCertificate
    Metadata:
      Creation Timestamp:  2020-08-05T20:44:49Z
      Generation:          2
      Resource Version:    1389781
      Self Link:           /apis/networking.gke.io/v1/namespaces/asm-ingress/managedcertificates/gke-ingress-cert
      UID:                 d74ec346-ced9-47a8-988a-6e6e9ddc4019
    Spec:
      Domains:
        frontend.endpoints.edge2mesh.cloud.goog
    Status:
      Certificate Name:    mcrt-306c779e-8439-408a-9634-163664ca6ced
      Certificate Status:  Provisioning
      Domain Status:
        Domain:  frontend.endpoints.edge2mesh.cloud.goog
        Status:  Provisioning
    Events:
      Type    Reason  Age   From                            Message
      ----    ------  ----  ----                            -------
      Normal  Create  44s   managed-certificate-controller  Create SslCertificate mcrt-306c779e-8439-408a-9634-163664ca6ced
    

    인증서가 준비되면 Certificate StatusActive입니다.

인그레스 리소스 배포

  1. Cloud Shell에서 다음 명령어를 실행하여 Ingress 매니페스트를 ingress.yaml로 만듭니다.

    cat <<EOF > ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: gke-ingress
      namespace: asm-ingress
      annotations:
        kubernetes.io/ingress.allow-http: "false"
        kubernetes.io/ingress.global-static-ip-name: "ingress-ip"
        networking.gke.io/managed-certificates: "gke-ingress-cert"
        kubernetes.io/ingress.class: "gce"
    spec:
      defaultBackend:
        service:
          name: asm-ingressgateway
          port:
            number: 443
      rules:
      - http:
          paths:
          - path: /*
            pathType: ImplementationSpecific
            backend:
              service:
                name: asm-ingressgateway
                port:
                  number: 443
    EOF
    

    이 매니페스트는 이전의 모든 리소스를 하나로 결합하는 인그레스 리소스를 정의합니다. 매니페스트는 다음 필드를 지정합니다.

    • kubernetes.io/ingress.allow-http: "false"는 Google Cloud 부하 분산기의 포트 80에서 HTTP 트래픽을 중지합니다. 이렇게 하면 포트 443은 HTTPS만 리슨하고 포트 80은 사용 중지되므로 암호화되지 않은 트래픽에 연결된 모든 클라이언트가 효과적으로 차단됩니다.
    • kubernetes.io/ingress.global-static-ip-name: "ingress-ip"는 이전에 만든 IP 주소를 부하 분산기와 연결합니다. 이 링크를 사용하면 부하 분산기와 별도로 IP 주소를 만들 수 있으므로 부하 분산기 수명 주기와는 별도로 재사용할 수 있습니다.
    • networking.gke.io/managed-certificates: "gke-ingress-cert"는 이 부하 분산기를 이전에 만든 Google 관리 SSL 인증서 리소스와 연결합니다.
  2. 클러스터에 ingress.yaml을 배포합니다.

    kubectl apply -f ingress.yaml
    
  3. 인그레스 리소스를 검사하여 부하 분산기 배포 진행 상황을 확인합니다.

    kubectl describe ingress gke-ingress -n asm-ingress
    

    출력은 다음과 비슷합니다.

    ...
    Annotations:
      ingress.kubernetes.io/https-forwarding-rule:       k8s2-fs-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/ssl-cert:                    mcrt-306c779e-8439-408a-9634-163664ca6ced
      networking.gke.io/managed-certificates:            gke-ingress-cert
      kubernetes.io/ingress.global-static-ip-name:  ingress-ip
      ingress.gcp.kubernetes.io/pre-shared-cert:    mcrt-306c779e-8439-408a-9634-163664ca6ced
      ingress.kubernetes.io/backends:               {"k8s-be-31610--07bdde06b914144a":"HEALTHY","k8s1-07bdde06-asm-ingress-asm-ingressgateway-443-228c1881":"HEALTHY"}
      ingress.kubernetes.io/forwarding-rule:        k8s2-fr-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/https-target-proxy:     k8s2-ts-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/target-proxy:           k8s2-tp-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/url-map:                k8s2-um-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
    ...
    

    ingress.kubernetes.io/backends 주석이 백엔드가 HEALTHY임을 나타내면 인그레스 리소스가 준비된 것입니다. 또한 주석에는 백엔드 서비스, SSL 인증서, HTTPS 대상 프록시를 포함하여 프로비저닝되는 여러 Google Cloud 리소스의 이름이 표시됩니다.

자체 서명 인그레스 게이트웨이 인증서 설치

다음 단계에서 GFE가 서비스 메시의 인그레스 게이트웨이에 대해 TLS 연결을 설정하게 해주는 인증서를 생성 및 설치합니다(Kubernetes secret 리소스). 인그레스 게이트웨이 인증서 요구사항에 대한 자세한 내용은 보안 백엔드 프로토콜 고려사항 가이드를 참조하세요.

  1. Cloud Shell에서 openssl을 사용하여 비공개 키와 인증서를 만듭니다.

    openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
     -subj "/CN=frontend.endpoints.${PROJECT}.cloud.goog/O=Edge2Mesh Inc" \
     -keyout frontend.endpoints.${PROJECT}.cloud.goog.key \
     -out frontend.endpoints.${PROJECT}.cloud.goog.crt
    
  2. asm-ingress 네임스페이스에 Secret을 만듭니다.

    kubectl -n asm-ingress create secret tls edge2mesh-credential \
     --key=frontend.endpoints.${PROJECT}.cloud.goog.key \
     --cert=frontend.endpoints.${PROJECT}.cloud.goog.crt
    

외부 부하 분산용 인그레스 게이트웨이 구성

다음 단계에서는 asm-ingress 네임스페이스에 공유 Gateway 리소스를 만듭니다. 일반적으로 플랫폼 관리자나 네트워크 관리팀에서 게이트웨이를 소유합니다. 따라서 Gateway 리소스는 플랫폼 관리자가 소유한 asm-ingress 네임스페이스에서 생성되며 자체 VirtualService 항목을 통해 다른 네임스페이스에서 사용될 수 있습니다.

  1. Cloud Shell에서 다음 명령어를 실행하여 Gateway 매니페스트를 ingress-gateway.yaml로 만듭니다.

    cat <<EOF > ingress-gateway.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
    spec:
      selector:
        asm: ingressgateway
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        hosts:
        - "*" # IMPORTANT: Must use wildcard here when using SSL, see note below
        tls:
          mode: SIMPLE
          credentialName: edge2mesh-credential
    EOF
    

    Gatewayhosts 필드에 와일드 카드 * 항목을 사용해야 합니다. GCLB에서는 백엔드에 SNI 확장 프로그램을 사용하지 않습니다. 와일드 카드 항목을 사용하면 GCLB에서 암호화된 패킷을 ASM 인그레스 게이트웨이로 보낼 수 있습니다. ASM 인그레스 게이트웨이는 패킷을 복호화하고 복호화된 패킷의 HTTP 호스트 헤더를 사용하여 VirtualService 항목을 기반으로 라우팅을 결정합니다.

  2. 클러스터에 ingress-gateway.yaml을 배포합니다.

    kubectl apply -f ingress-gateway.yaml
    

    출력은 다음과 비슷합니다.

    gateway.networking.istio.io/asm-ingressgateway created
    

Online Boutique 샘플 앱 설치

  1. Cloud Shell에서 전용 onlineboutique 네임스페이스를 만듭니다.

    kubectl create namespace onlineboutique
    
  2. 네임스페이스 라벨을 onlineboutique 네임스페이스에 추가합니다.

    kubectl label namespace onlineboutique istio-injection=enabled
    

    출력은 다음과 비슷합니다.

    namespace/onlineboutique labeled
    

    onlineboutique 네임스페이스에 istio-injection=enabled 라벨을 지정하면 애플리케이션이 배포될 때 Anthos Service Mesh가 Envoy 사이드카 프록시를 자동으로 삽입합니다.

  3. Online Boutique 샘플 앱의 Kubernetes YAML 파일을 다운로드합니다.

    curl -LO \
        https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/main/release/kubernetes-manifests.yaml
    
  4. Online Boutique 앱을 배포합니다.

    kubectl apply -f kubernetes-manifests.yaml -n onlineboutique
    

    출력은 다음과 비슷합니다.

    deployment.apps/frontend created
    service/frontend created
    service/frontend-external created
    ...
    
  5. 모든 배포가 실행 중인지 확인합니다.

    kubectl get pods -n onlineboutique
    

    출력은 다음과 비슷합니다.

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-d854d8786-fjb7q                2/2     Running   0          3m
    cartservice-85b5d5b4ff-8qn7g             2/2     Running   0          2m59s
    checkoutservice-5f9bf659b8-sxhsq         2/2     Running   0          3m1s
    ...
    
  6. 다음 명령어를 실행하여 VirtualService 매니페스트를 frontend-virtualservice.yaml로 만듭니다.

    cat <<EOF > frontend-virtualservice.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: frontend-ingress
      namespace: onlineboutique
    spec:
      hosts:
      - "frontend.endpoints.${PROJECT}.cloud.goog"
      gateways:
      - asm-ingress/asm-ingressgateway
      http:
      - route:
        - destination:
            host: frontend
            port:
              number: 80
    EOF
    

    VirtualService는 애플리케이션 네임스페이스(onlineboutique)에 생성됩니다. 일반적으로 애플리케이션 소유자는 앱 소유자가 VirtualService를 배포하도록 트래픽이 frontend 애플리케이션으로 라우팅되는 양과 방법을 결정하고 구성합니다.

  7. 클러스터에 frontend-virtualservice.yaml을 배포합니다.

    kubectl apply -f frontend-virtualservice.yaml
    

    출력은 다음과 비슷합니다.

    virtualservice.networking.istio.io/frontend-virtualservice created
    
  8. 다음 링크에 액세스합니다.

    echo "https://frontend.endpoints.${PROJECT}.cloud.goog"
    

    Online Boutique 프런트엔드가 표시됩니다.

    Online Boutique 홈페이지에 표시되는 제품

  9. 인증서의 세부정보를 표시하려면 브라우저의 주소 표시줄에서 사이트 정보 보기를 클릭하고 인증서(유효)를 클릭합니다.

    인증서 뷰어에 유효 기간과 인증서 발급자를 포함한 관리형 인증서의 세부정보가 표시됩니다.

이제 서비스 메시에서 호스팅된 애플리케이션의 프런트엔드 역할을 하는 전역 HTTPS 부하 분산기가 준비되었습니다.

정리

가이드를 완료한 후에는 이후에 요금이 청구되지 않도록 Google Cloud에서 만든 리소스를 삭제할 수 있습니다. 프로젝트를 완전히 삭제하거나 클러스터 리소스를 삭제한 다음 클러스터를 삭제할 수 있습니다.

프로젝트 삭제

  1. 콘솔에서 리소스 관리 페이지로 이동합니다.

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

개별 리소스 삭제

이 가이드에서 사용한 Cloud 프로젝트를 유지하려면 개별 리소스를 삭제하세요.

  1. 인그레스 리소스를 삭제합니다.

    kubectl delete -f ingress.yaml
    
  2. 관리형 인증서를 삭제합니다.

    kubectl delete -f managed-cert.yaml
    
  3. Endpoints DNS 항목을 삭제합니다.

    gcloud endpoints services delete "frontend.endpoints.${PROJECT}.cloud.goog"
    

    출력은 다음과 비슷합니다.

    Are you sure? This will set the service configuration to be deleted, along
    with all of the associated consumer information. Note: This does not
    immediately delete the service configuration or data and can be undone using
    the undelete command for 30 days. Only after 30 days will the service be
    purged from the system.
    
  4. 계속할지 묻는 메시지가 표시되면 Y를 입력합니다.

    출력은 다음과 비슷합니다.

    Waiting for async operation operations/services.frontend.endpoints.edge2mesh.cloud.goog-5 to complete...
    Operation finished successfully. The following command can describe the Operation details:
     gcloud endpoints operations describe operations/services.frontend.endpoints.edge2mesh.cloud.goog-5
    
  5. 고정 IP 주소를 삭제합니다.

    gcloud compute addresses delete ingress-ip --global
    

    출력은 다음과 비슷합니다.

    The following global addresses will be deleted:
    
     - [ingress-ip]
    
  6. 계속할지 묻는 메시지가 표시되면 Y를 입력합니다.

    출력은 다음과 비슷합니다.

    Deleted
    [https://www.googleapis.com/compute/v1/projects/edge2mesh/global/addresses/ingress-ip].
    
  7. GKE 클러스터를 삭제합니다.

    gcloud container clusters delete $CLUSTER_NAME --zone $CLUSTER_LOCATION
    

다음 단계