Cloud Service Mesh를 사용하여 GKE 비공개 클러스터에서 분산 서비스 실행

이 문서에서는 Cloud Service Mesh를 사용하여 Google Cloud의 여러 Google Kubernetes Engine(GKE) 클러스터에서 분산 서비스를 실행하는 방법을 보여줍니다. 또한 이 문서에서는 멀티 클러스터 인그레스와 Cloud Service Mesh를 사용하여 분산 서비스를 노출하는 방법을 보여줍니다. 이 문서를 사용하여 비공개 GKE 클러스터를 구성할 수 있습니다. 이 문서에서는 비공개 클러스터용으로 엄격하게 사용되는 구성을 강조해서 보여줍니다.

이 문서는 Kubernetes에 대한 기본 지식이 있는 플랫폼 관리자 및 서비스 운영자를 대상으로 합니다. 서비스 메시에 대한 일부 지식도 필수는 아니지만 도움이 됩니다. Cloud Service Mesh는 오픈소스 Istio 기술을 기반으로 합니다. 서비스 메시 및 Istio에 대한 자세한 내용은 istio.io를 참조하세요.

분산 서비스는 단일 논리적 서비스로 작동하는 Kubernetes 서비스입니다. 분산 서비스는 동일한 네임스페이스의 여러 Kubernetes 클러스터에서 실행되기 때문에 Kubernetes 서비스보다 복원력이 우수합니다. 하나 이상의 GKE 클러스터가 작동 중지되더라도 정상 클러스터가 원하는 로드를 제공할 수 있는 한 분산 서비스는 작동 상태를 유지합니다.

Kubernetes 서비스는 실행되는 클러스터의 Kubernetes API 서버를 통해서만 사용 가능합니다. Kubernetes 클러스터가 작동 중지되면(예: 예약된 유지보수 중) 해당 클러스터에서 실행 중인 모든 Kubernetes 서비스도 작동 중지됩니다. 분산 서비스를 실행하면 다른 클러스터가 트래픽을 처리할 때 유지보수 또는 업그레이드를 위해 클러스터를 중지할 수 있으므로 수명 주기 관리가 더 쉬워집니다. 분산 서비스를 만들기 위해 Cloud Service Mesh에서 제공하는 서비스 메시 기능은 여러 클러스터에서 실행되는 서비스를 연결하여 단일 논리 서비스로 작동하는 데 사용됩니다.

GKE 비공개 클러스터를 사용하면 노드와 API 서버를 Virtual Private Cloud(VPC) 네트워크에서만 사용할 수 있는 비공개 리소스로 구성할 수 있습니다. GKE 비공개 클러스터에서 분산 서비스를 실행하면 기업에 안전하고 안정적인 서비스가 제공됩니다.

아키텍처

이 튜토리얼에서는 다음 다이어그램에 표시된 아키텍처를 사용합니다.

Cloud Service Mesh를 사용하는 GKE 비공개 클러스터의 분산 서비스 아키텍처

위의 다이어그램에서 아키텍처에는 다음 클러스터가 포함됩니다.

  • 두 클러스터(gke-central-privgke-west-priv)는 서로 다른 두 리전에서 동일한 GKE 비공개 클러스터 역할을 합니다.
  • 별도의 클러스터(ingress-config)는 멀티 클러스터 인그레스를 구성하는 컨트롤 플레인 클러스터 역할을 합니다.

이 튜토리얼에서는 GKE 비공개 클러스터 2개(gke-central-privgke-west-priv)에 Bank of Anthos 샘플 애플리케이션을 배포합니다. Bank of Anthos는 온라인 뱅킹 앱을 시뮬레이션하는 마이크로서비스와 SQL 데이터베이스 여러 개로 구성된 샘플 마이크로서비스 애플리케이션입니다. 이 애플리케이션은 클라이언트에서 액세스할 수 있는 웹 프런트엔드와 은행을 시뮬레이션하는 잔액, 원장, 계좌 서비스와 같은 백엔드 서비스 여러 개로 구성됩니다.

애플리케이션에는 Kubernetes에 StatefulSets로 설치된 2개의 PostgreSQL 데이터베이스가 포함되어 있습니다. 한 데이터베이스는 트랜잭션에 사용되고 다른 데이터베이스는 사용자 계정에 사용됩니다. 두 데이터베이스를 제외한 모든 서비스가 분산 서비스로 실행됩니다. 즉, 모든 서비스의 포드가 같은 네임스페이스에 있는 두 애플리케이션 클러스터 모두에서 실행되고 Cloud Service Mesh는 각 서비스가 단일 논리적 서비스로 표시되도록 구성됩니다.

목표

  • GKE 클러스터 3개 만듭니다.
  • GKE 클러스터 두 개를 비공개 클러스터(gke-central-privgke-west-priv)로 구성합니다.
  • 하나의 GKE 클러스터(ingress-config)를 중앙 구성 클러스터로 구성합니다. 이 클러스터는 멀티 클러스터 인그레스의 구성 클러스터로 사용됩니다.
  • 두 개의 비공개 GKE 클러스터에서 클러스터 간 및 이그레스 트래픽을 허용하도록 네트워킹(NAT 게이트웨이, Cloud Router, 방화벽 규칙)을 구성합니다.
  • API 서비스가 Cloud Shell에서 2개의 비공개 GKE 클러스터에 액세스하도록 승인된 네트워크를 구성합니다.
  • 멀티 기본 모드에서 멀티 클러스터 Cloud Service Mesh를 비공개 클러스터 2개에 배포하고 구성합니다. 멀티 기본 모드는 Cloud Service Mesh 컨트롤 플레인을 두 클러스터 모두에 배포합니다.
  • 두 비공개 클러스터에 Bank of Anthos 애플리케이션을 배포합니다. 데이터베이스를 제외한 모든 서비스가 분산 서비스(두 비공개 클러스터에서 실행되는 포드)로 배포됩니다.
  • Cloud Service Mesh를 사용하여 서비스를 모니터링합니다.
  • Bank of Anthos frontend 서비스에서 멀티 클러스터 인그레스를 구성합니다. 이를 통해 외부 클라이언트(예: 웹브라우저)가 일련의 비공개 GKE 클러스터에서 실행되는 분산 서비스에 액세스할 수 있습니다.

비용

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

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

시작하기 전에

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  3. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

    Cloud Shell에서 이 튜토리얼의 모든 명령어를 실행합니다.

  4. 이 튜토리얼 전체에서 사용할 환경 변수를 정의합니다. 변수는 이 튜토리얼에서 사용되는 클러스터 이름, 리전, 영역, IP 주소 지정, Cloud Service Mesh 버전을 정의합니다.

    1. YOUR_PROJECT_ID를 프로젝트 ID로 바꿉니다.

      export PROJECT_ID=YOUR_PROJECT_ID
      gcloud config set project ${PROJECT_ID}
      
    2. 나머지 환경 변수를 설정합니다.

      export CLUSTER_1=gke-west-priv
      export CLUSTER_2=gke-central-priv
      export CLUSTER_1_ZONE=us-west2-a
      export CLUSTER_1_REGION=us-west2
      export CLUSTER_1_MASTER_IPV4_CIDR=172.16.0.0/28
      export CLUSTER_2_ZONE=us-central1-a
      export CLUSTER_2_REGION=us-central1
      export CLUSTER_2_MASTER_IPV4_CIDR=172.16.1.0/28
      export CLUSTER_INGRESS=gke-ingress
      export CLUSTER_INGRESS_ZONE=us-west1-a
      export CLUSTER_INGRESS_REGION=us-west1
      export CLUSTER_INGRESS_MASTER_IPV4_CIDR=172.16.2.0/28
      export WORKLOAD_POOL=${PROJECT_ID}.svc.id.goog
      export ASM_VERSION=1.10
      export CLOUDSHELL_IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
      

개발 환경 준비

  1. Cloud Shell에서 API를 사용 설정합니다.

    gcloud services enable \
      --project=${PROJECT_ID} \
      container.googleapis.com \
      mesh.googleapis.com \
      gkehub.googleapis.com
    
  2. 프로젝트에 Cloud Service Mesh Fleet을 사용 설정합니다.

    gcloud container fleet mesh enable --project=${PROJECT_ID}
    

비공개 GKE 클러스터의 네트워킹 준비

이 섹션에서는 분산 서비스 실행을 위해 사용하는 비공개 GKE 클러스터에 대한 네트워킹을 준비합니다.

비공개 GKE 클러스터 노드에는 공개 IP 주소가 할당되지 않습니다. 비공개 GKE 클러스터의 모든 노드에는 비공개 VPC IP 주소(RFC 1918 주소 공간)가 할당됩니다. 즉, 외부 리소스(VPC 네트워크 외부) 액세스가 필요한 포드에 Cloud NAT 게이트웨이가 필요합니다. Cloud NAT 게이트웨이는 내부 IP 주소를 갖는 포드가 인터넷과 통신하도록 허용하는 리전별 NAT 게이트웨이입니다. 이 튜토리얼에서는 각각의 두 리전에서 Cloud NAT 게이트웨이를 구성합니다. 한 리전 내의 여러 클러스터가 동일한 NAT 게이트웨이를 사용할 수 있습니다.

  1. Cloud Shell에서 2개의 NAT 게이트웨이에 대해 2개의 외부 IP 주소를 만들고 예약합니다.

    gcloud compute addresses create ${CLUSTER_1_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_1_REGION}
    
    gcloud compute addresses create ${CLUSTER_2_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_2_REGION}
    
  2. IP 주소 및 IP 주소 이름을 변수에 저장합니다.

    export NAT_REGION_1_IP_ADDR=$(gcloud compute addresses describe ${CLUSTER_1_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_1_REGION} \
      --format='value(address)')
    
    export NAT_REGION_1_IP_NAME=$(gcloud compute addresses describe ${CLUSTER_1_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_1_REGION} \
      --format='value(name)')
    
    export NAT_REGION_2_IP_ADDR=$(gcloud compute addresses describe ${CLUSTER_2_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_2_REGION} \
      --format='value(address)')
    
    export NAT_REGION_2_IP_NAME=$(gcloud compute addresses describe ${CLUSTER_2_REGION}-nat-ip \
      --project=${PROJECT_ID} \
      --region=${CLUSTER_2_REGION} \
      --format='value(name)')
    
  3. 비공개 GKE 클러스터의 두 리전에 Cloud NAT 게이트웨이를 만듭니다.

    gcloud compute routers create rtr-${CLUSTER_1_REGION} \
      --network=default \
      --region ${CLUSTER_1_REGION}
    
    gcloud compute routers nats create nat-gw-${CLUSTER_1_REGION} \
      --router=rtr-${CLUSTER_1_REGION} \
      --region ${CLUSTER_1_REGION} \
      --nat-external-ip-pool=${NAT_REGION_1_IP_NAME} \
      --nat-all-subnet-ip-ranges \
      --enable-logging
    
    gcloud compute routers create rtr-${CLUSTER_2_REGION} \
      --network=default \
      --region ${CLUSTER_2_REGION}
    
    gcloud compute routers nats create nat-gw-${CLUSTER_2_REGION} \
      --router=rtr-${CLUSTER_2_REGION} \
      --region ${CLUSTER_2_REGION} \
      --nat-external-ip-pool=${NAT_REGION_2_IP_NAME} \
      --nat-all-subnet-ip-ranges \
      --enable-logging
    
  4. 포드간 통신 및 포드-API 서버 통신을 허용하는 방화벽 규칙을 만듭니다. 포드 간 통신은 GKE 클러스터 간에 분산 서비스가 서로 통신할 수 있게 해줍니다. 포드-API 서버 통신을 사용하면 Cloud Service Mesh 컨트롤 플레인에서 서비스 검색을 위해 GKE 클러스터를 쿼리할 수 있습니다.

    gcloud compute firewall-rules create all-pods-and-master-ipv4-cidrs \
      --project ${PROJECT_ID} \
      --network default \
      --allow all \
      --direction INGRESS \
      --source-ranges 10.0.0.0/8,${CLUSTER_1_MASTER_IPV4_CIDR},${CLUSTER_2_MASTER_IPV4_CIDR},${CLUSTER_INGRESS_MASTER_IPV4_CIDR}
    

네트워킹이 이제 준비되었습니다. 이 튜토리얼에서는 모든 포드 범위가 포함된 전체 10.0.0.0/8 IP 주소 범위를 사용합니다. 프로덕션에서는 조건 및 요구사항에 따라 더 엄격한 방화벽 규칙을 만드는 것이 좋습니다.

비공개 GKE 클러스터 만들기

이 섹션에서는 샘플 앱이 배포되는 2개의 비공개 GKE 클러스터를 만듭니다. 이 튜토리얼에서 비공개 GKE 클러스터 노드에는 비공개 IP 주소가 포함되고 API 서버에는 공개 엔드포인트가 포함됩니다. 하지만 API 서버 액세스는 승인된 네트워크를 사용하여 제한됩니다.

  1. Cloud Shell에서 승인된 네트워크가 있는 2개의 비공개 클러스터를 만듭니다. 터미널에서 클러스터에 액세스할 수 있도록 포드 IP CIDR 범위(Cloud Service Mesh 컨트롤 플레인의 경우) 및 Cloud Shell에서의 액세스를 허용하도록 클러스터를 구성합니다.

    gcloud container clusters create ${CLUSTER_1} \
      --project ${PROJECT_ID} \
      --zone=${CLUSTER_1_ZONE} \
      --machine-type "e2-standard-4" \
      --num-nodes "3" --min-nodes "3" --max-nodes "5" \
      --enable-ip-alias --enable-autoscaling \
      --workload-pool=${WORKLOAD_POOL} \
      --enable-private-nodes \
      --master-ipv4-cidr=${CLUSTER_1_MASTER_IPV4_CIDR} \
      --enable-master-authorized-networks \
      --master-authorized-networks $NAT_REGION_1_IP_ADDR/32,$NAT_REGION_2_IP_ADDR/32,$CLOUDSHELL_IP/32
    
    gcloud container clusters create ${CLUSTER_2} \
      --project ${PROJECT_ID} \
      --zone=${CLUSTER_2_ZONE} \
      --machine-type "e2-standard-4" \
      --num-nodes "3" --min-nodes "3" --max-nodes "5" \
      --enable-ip-alias --enable-autoscaling \
      --workload-pool=${WORKLOAD_POOL} \
      --enable-private-nodes \
      --master-ipv4-cidr=${CLUSTER_2_MASTER_IPV4_CIDR} \
      --enable-master-authorized-networks \
      --master-authorized-networks $NAT_REGION_1_IP_ADDR/32,$NAT_REGION_2_IP_ADDR/32,$CLOUDSHELL_IP/32
    

    승인된 네트워크에는 Cloud NAT 게이트웨이의 공개 IP 주소가 포함됩니다. 비공개 클러스터의 API 서버 엔드포인트는 공개 엔드포인트이므로 비공개 클러스터에서 실행되는 포드는 Cloud NAT 게이트웨이를 사용하여 공개 API 서버 엔드포인트에 액세스해야 합니다.

    Cloud Shell IP 주소는 또한 승인된 네트워크의 일부입니다. 이를 통해 Cloud Shell 터미널에서 클러스터를 액세스하고 관리할 수 있습니다. Cloud Shell 공개 IP 주소는 동적으로 지정되므로 Cloud Shell을 시작할 때마다 다른 공개 IP 주소가 사용됩니다. 새 IP 주소를 시작하면 새 IP 주소가 두 클러스터의 승인된 네트워크에 포함되지 않기 때문에 클러스터에 대한 액세스가 손실됩니다.

    클러스터에 대한 액세스가 손실되면 새 Cloud Shell IP 주소를 포함하도록 클러스터의 승인된 네트워크를 업데이트합니다.

    1. 업데이트된 Cloud Shell 공개 IP 주소를 가져옵니다.

      export CLOUDSHELL_IP=$(dig +short myip.opendns.com @resolver1.opendns.com)
      
    2. 두 클러스터의 승인된 네트워크를 업데이트합니다.

      gcloud container clusters update ${CLUSTER_1} \
        --zone=${CLUSTER_1_ZONE} \
        --enable-master-authorized-networks \
        --master-authorized-networks $NAT_REGION_1_IP_ADDR/32,$NAT_REGION_2_IP_ADDR/32,$CLOUDSHELL_IP/32
      
      gcloud container clusters update ${CLUSTER_2} \
        --zone=${CLUSTER_2_ZONE} \
        --enable-master-authorized-networks \
        --master-authorized-networks $NAT_REGION_1_IP_ADDR/32,$NAT_REGION_2_IP_ADDR/32,$CLOUDSHELL_IP/32
      
  2. 모든 클러스터가 실행 중인지 확인합니다.

    gcloud container clusters list
    

    출력은 다음과 같이 표시됩니다.

    NAME              LOCATION       MASTER_VERSION    MASTER_IP      MACHINE_TYPE   NODE_VERSION      NUM_NODES  STATUS
    gke-central-priv  us-central1-a  1.16.15-gke.6000  35.238.99.104  e2-standard-4  1.16.15-gke.6000  3          RUNNING
    gke-west-priv     us-west2-a     1.16.15-gke.6000  34.94.188.180  e2-standard-4  1.16.15-gke.6000  3          RUNNING
    
  3. 두 클러스터 모두에 연결하여 kubeconfig 파일에 항목을 생성합니다.

    touch ~/asm-kubeconfig && export KUBECONFIG=~/asm-kubeconfig
    gcloud container clusters get-credentials ${CLUSTER_1} --zone ${CLUSTER_1_ZONE}
    gcloud container clusters get-credentials ${CLUSTER_2} --zone ${CLUSTER_2_ZONE}
    

    kubeconfig 파일을 사용하여 각 클러스터에 대해 사용자 및 컨텍스트를 만들어서 클러스터에 인증을 수행합니다. kubeconfig 파일에서 항목을 생성한 후 클러스터 간에 컨텍스트를 빠르게 전환할 수 있습니다.

  4. 편의를 위해 클러스터 컨텍스트 이름을 바꿉니다.

    kubectl config rename-context \
    gke_${PROJECT_ID}_${CLUSTER_1_ZONE}_${CLUSTER_1} ${CLUSTER_1}
    
    kubectl config rename-context \
    gke_${PROJECT_ID}_${CLUSTER_2_ZONE}_${CLUSTER_2} ${CLUSTER_2}
    
  5. 두 클러스터 컨텍스트의 이름이 올바르게 변경되고 구성되었는지 확인합니다.

    kubectl config get-contexts --output="name"
    

    출력은 다음과 같이 표시됩니다.

    gke-central-priv
    gke-west-priv
    
  6. 클러스터를 Fleet에 등록합니다.

    gcloud container fleet memberships register ${CLUSTER_1} --gke-cluster=${CLUSTER_1_ZONE}/${CLUSTER_1} --enable-workload-identity
    gcloud container fleet memberships register ${CLUSTER_2} --gke-cluster=${CLUSTER_2_ZONE}/${CLUSTER_2} --enable-workload-identity
    

이제 비공개 GKE 클러스터를 만들고 이름을 바꿨습니다.

Cloud Service Mesh 설치

이 섹션에서는 Cloud Service Mesh를 GKE 클러스터 2개에 설치하고 클러스터 간 서비스 검색에 사용할 클러스터를 구성합니다.

  1. Cloud Shell에서 fleet API를 사용하여 두 클러스터 모두에 Cloud Service Mesh를 설치합니다.

    gcloud container fleet mesh update --management automatic --memberships ${CLUSTER_1},${CLUSTER_2}
    
  2. 관리형 Cloud Service Mesh가 클러스터에 사용 설정되면 설치할 메시에 감시를 설정합니다.

    watch -g "gcloud container fleet mesh describe | grep 'code: REVISION_READY'"
    
  3. 두 클러스터 모두에 Cloud Service Mesh 인그레스 게이트웨이를 설치합니다.

    kubectl --context=${CLUSTER_1} create namespace asm-ingress
    kubectl --context=${CLUSTER_1} label namespace asm-ingress istio-injection=enabled --overwrite
    kubectl --context=${CLUSTER_2} create namespace asm-ingress
    kubectl --context=${CLUSTER_2} label namespace asm-ingress istio-injection=enabled --overwrite
    
    cat <<'EOF' > asm-ingress.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      type: LoadBalancer
      selector:
        asm: ingressgateway
      ports:
      - port: 80
        name: http
      - port: 443
        name: https
    ---
    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.
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: asm-ingressgateway-sds
      namespace: asm-ingress
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: asm-ingressgateway-sds
      namespace: asm-ingress
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: asm-ingressgateway-sds
    subjects:
    - kind: ServiceAccount
      name: default
    EOF
    
    kubectl --context=${CLUSTER_1} apply -f asm-ingress.yaml
    kubectl --context=${CLUSTER_2} apply -f asm-ingress.yaml
    
  4. Cloud Service Mesh 인그레스 게이트웨이가 배포되었는지 확인합니다.

    kubectl --context=${CLUSTER_1} get pod,service -n asm-ingress
    kubectl --context=${CLUSTER_2} get pod,service -n asm-ingress
    

    두 클러스터 모두 출력이 다음과 같이 표시됩니다.

    NAME                                        READY   STATUS    RESTARTS   AGE
    pod/asm-ingressgateway-5894744dbd-zxlgc   1/1     Running   0          84s
    
    NAME                           TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)                      AGE
    service/asm-ingressgateway   LoadBalancer   10.16.2.131   34.102.100.138   80:30432/TCP,443:30537/TCP   92s
    

    Cloud Service Mesh 컨트롤 플레인과 인그레스 게이트웨이가 두 클러스터 모두에 설치되면 클러스터 간 서비스 검색이 Fleet API에서 사용 설정됩니다. 클러스터 간 서비스 검색은 두 클러스터가 원격 클러스터의 서비스 엔드포인트를 검색할 수 있게 해줍니다. 분산 서비스는 동일한 네임스페이스에 있는 여러 클러스터에서 실행됩니다.

    두 Cloud Service Mesh 컨트롤 플레인이 분산 서비스의 모든 엔드포인트를 검색할 수 있도록 하려면 Cloud Service Mesh에 분산 서비스를 실행하는 모든 클러스터에 대한 액세스 권한이 있어야 합니다. 이 예시에서는 2개의 클러스터가 사용되므로, 두 클러스터 모두 서비스 엔드포인트에 대해 원격 클러스터를 쿼리할 수 있어야 합니다. 관리형 Cloud Service Mesh가 Fleet API에서 사용 설정되면 엔드포인트 검색이 자동으로 구성됩니다.

이제 클러스터와 Cloud Service Mesh가 구성됩니다.

Bank of Anthos 애플리케이션 배포

  1. Cloud Shell에서 Bank of Anthos GitHub 저장소를 클론합니다.

    git clone https://github.com/GoogleCloudPlatform/bank-of-anthos.git ${HOME}/bank-of-anthos
    
  2. 두 클러스터 모두에서 bank-of-anthos 네임스페이스를 만들고 라벨을 지정합니다. 라벨은 라벨이 지정된 네임스페이스 내에서 모든 포드에 있는 사이드카 Envoy 프록시의 자동 삽입을 허용합니다.

    # cluster_1
    kubectl create --context=${CLUSTER_1} namespace bank-of-anthos
    kubectl label --context=${CLUSTER_1} namespace bank-of-anthos istio-injection=enabled
    
    # cluster_2
    kubectl create --context=${CLUSTER_2} namespace bank-of-anthos
    kubectl label --context=${CLUSTER_2} namespace bank-of-anthos istio-injection=enabled
    
  3. bank-of-anthos 네임스페이스의 두 클러스터에 Bank of Anthos 애플리케이션을 배포합니다.

    # The following secret is used for user account creation and authentication
    kubectl --context=$CLUSTER_1 -n bank-of-anthos apply -f ${HOME}/bank-of-anthos/extras/jwt/jwt-secret.yaml
    kubectl --context=$CLUSTER_2 -n bank-of-anthos apply -f ${HOME}/bank-of-anthos/extras/jwt/jwt-secret.yaml
    
    # Deploy all manifests to both clusters
    kubectl --context=$CLUSTER_1 -n bank-of-anthos apply -f ${HOME}/bank-of-anthos/kubernetes-manifests
    kubectl --context=$CLUSTER_2 -n bank-of-anthos apply -f ${HOME}/bank-of-anthos/kubernetes-manifests
    

    Kubernetes 서비스는 서비스 검색을 위해 두 클러스터에 모두 있어야 합니다. 클러스터 중 하나의 서비스가 요청을 수행하려고 시도할 때는 먼저 호스트 이름이 IP 주소를 가져오도록 DNS 조회를 수행합니다. GKE에서는 클러스터에서 실행되는 kube-dns 서버가 이 조회를 처리하므로 구성된 서비스 정의가 필요합니다.

  4. 두 PostgreSQL 데이터베이스가 클러스터 중 하나에만 존재하도록 한 클러스터에서 StatefulSets를 삭제합니다.

    # Delete the two DB statefulSets from Cluster2
    kubectl --context=$CLUSTER_2 -n bank-of-anthos delete statefulset accounts-db
    kubectl --context=$CLUSTER_2 -n bank-of-anthos delete statefulset ledger-db
    
  5. 모든 포드가 두 클러스터 모두에서 실행되는지 확인합니다.

    1. cluster_1에서 포드를 가져옵니다.

      kubectl --context=${CLUSTER_1} -n bank-of-anthos get pod
      

      출력은 다음과 같이 표시됩니다.

      NAME                                  READY   STATUS    RESTARTS   AGE
      accounts-db-0                         2/2     Running   0          9m54s
      balancereader-c5d664b4c-xmkrr         2/2     Running   0          9m54s
      contacts-7fd8c5fb6-wg9xn              2/2     Running   1          9m53s
      frontend-7b7fb9b665-m7cw7             2/2     Running   1          9m53s
      ledger-db-0                           2/2     Running   0          9m53s
      ledgerwriter-7b5b6db66f-xhbp4         2/2     Running   0          9m53s
      loadgenerator-7fb54d57f8-g5lz5        2/2     Running   0          9m52s
      transactionhistory-7fdb998c5f-vqh5w   2/2     Running   1          9m52s
      userservice-76996974f5-4wlpf          2/2     Running   1          9m52s
      
    2. cluster_2에서 포드를 가져옵니다.

      kubectl --context=${CLUSTER_2} -n bank-of-anthos get pod
      

      출력은 다음과 같이 표시됩니다.

      NAME                                  READY   STATUS    RESTARTS   AGE
      balancereader-c5d664b4c-bn2pl         2/2     Running   0          9m54s
      contacts-7fd8c5fb6-kv8cp              2/2     Running   0          9m53s
      frontend-7b7fb9b665-bdpp4             2/2     Running   0          9m53s
      ledgerwriter-7b5b6db66f-297c2         2/2     Running   0          9m52s
      loadgenerator-7fb54d57f8-tj44v        2/2     Running   0          9m52s
      transactionhistory-7fdb998c5f-xvmtn   2/2     Running   0          9m52s
      userservice-76996974f5-mg7t6          2/2     Running   0          9m51s
      
  6. Cloud Service Mesh 구성을 두 클러스터 모두에 배포합니다. 이렇게 하면 asm-ingress 네임스페이스에 Gateway, frontend 서비스의 bank-of-anthos 네임스페이스에 VirtualService가 생성되며 이를 사용하여 트래픽을 frontend 서비스로 인그레스할 수 있습니다.

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

    cat <<'EOF' > asm-vs-gateway.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      selector:
        asm: ingressgateway
      servers:
        - port:
            number: 80
            name: http
            protocol: HTTP
          hosts:
            - "*"
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: frontend
      namespace: bank-of-anthos
    spec:
      hosts:
      - "*"
      gateways:
      - asm-ingress/asm-ingressgateway
      http:
      - route:
        - destination:
            host: frontend
            port:
              number: 80
    EOF
    
    kubectl --context=$CLUSTER_1 apply -f asm-vs-gateway.yaml
    
    kubectl --context=$CLUSTER_2 apply -f asm-vs-gateway.yaml
    

이제 2개의 비공개 GKE 클러스터에 Bank of Anthos 애플리케이션이 배포되었습니다. 데이터베이스를 제외하고 모든 서비스가 분산 서비스로 실행됩니다.

분산 서비스 검사

이 섹션에서는 istioctl 도구를 사용하여 프록시의 프록시 구성을 조사합니다. 이를 수행하면 해당 사이드카 프록시에 모든 서비스에 대해 2개의 포드가 표시되고 각 클러스터에서 하나의 포드가 실행되는지 확인할 수 있습니다.

  1. Cloud Shell에서 cluster_1frontend 포드에서 프록시 구성 엔드포인트 목록을 검사합니다.

    export FRONTEND1=$(kubectl get pod -n bank-of-anthos -l app=frontend \
      --context=${CLUSTER_1} -o jsonpath='{.items[0].metadata.name}')
    istioctl proxy-config endpoints \
    --context $CLUSTER_1 -n bank-of-anthos $FRONTEND1 | grep bank-of-anthos
    

    출력은 다음과 같이 표시됩니다.

    10.12.0.6:5432                   HEALTHY     OK                outbound|5432||accounts-db.bank-of-anthos.svc.cluster.local
    10.12.0.7:8080                   HEALTHY     OK                outbound|8080||balancereader.bank-of-anthos.svc.cluster.local
    10.12.0.8:8080                   HEALTHY     OK                outbound|8080||transactionhistory.bank-of-anthos.svc.cluster.local
    10.12.0.9:8080                   HEALTHY     OK                outbound|8080||userservice.bank-of-anthos.svc.cluster.local
    10.12.1.10:8080                  HEALTHY     OK                outbound|8080||ledgerwriter.bank-of-anthos.svc.cluster.local
    10.12.1.9:8080                   HEALTHY     OK                outbound|8080||contacts.bank-of-anthos.svc.cluster.local
    10.12.2.11:5432                  HEALTHY     OK                outbound|5432||ledger-db.bank-of-anthos.svc.cluster.local
    10.12.2.13:8080                  HEALTHY     OK                outbound|80||frontend.bank-of-anthos.svc.cluster.local
    10.76.1.10:8080                  HEALTHY     OK                outbound|8080||transactionhistory.bank-of-anthos.svc.cluster.local
    10.76.1.8:8080                   HEALTHY     OK                outbound|8080||balancereader.bank-of-anthos.svc.cluster.local
    10.76.1.9:8080                   HEALTHY     OK                outbound|80||frontend.bank-of-anthos.svc.cluster.local
    10.76.2.10:8080                  HEALTHY     OK                outbound|8080||userservice.bank-of-anthos.svc.cluster.local
    10.76.2.8:8080                   HEALTHY     OK                outbound|8080||contacts.bank-of-anthos.svc.cluster.local
    10.76.2.9:8080                   HEALTHY     OK                outbound|8080||ledgerwriter.bank-of-anthos.svc.cluster.local
    

    앞의 출력에서 각 분산 서비스에는 2개의 엔드포인트 IP 주소가 포함됩니다. 이것들은 각 클러스터에 대한 하나씩의 포드 IP 주소입니다.

Bank of Anthos 액세스

Bank of Anthos 애플리케이션에 액세스하려면 두 클러스터 모두에서 asm-ingressgateway 서비스 공개 IP 주소를 사용하면 됩니다.

  1. 두 클러스터 모두에서 asm-ingressgateway IP 주소를 가져옵니다.

    kubectl --context ${CLUSTER_1} \
    --namespace asm-ingress get svc asm-ingressgateway -o jsonpath='{.status.loadBalancer}' | grep "ingress"
    
    kubectl --context ${CLUSTER_2} \
    --namespace asm-ingress get svc asm-ingressgateway -o jsonpath='{.status.loadBalancer}' | grep "ingress"
    
    

    출력은 다음과 같이 표시됩니다.

    {"ingress":[{"ip":"35.236.4.18"}]}
    {"ingress":[{"ip":"34.68.94.81"}]}
    

    다음 단계에서 사용하도록 IP 주소 중 하나를 복사합니다.

  2. 웹브라우저에서 새 탭을 열고 이전 출력의 IP 주소 중 하나로 이동합니다. Bank of Anthos 프런트엔드가 표시되면 로그인하여 계정에 금액을 입금하고 다른 계정으로 자금을 이체할 수 있습니다. 애플리케이션이 완전히 작동해야 합니다.

분산 서비스 시각화

Cloud Service Mesh에서 분산 서비스를 시각화할 수 있습니다.

  1. 서비스를 보려면 Google Cloud 콘솔에서 서비스 메시 페이지로 이동합니다.

    서비스 메시로 이동

    테이블 뷰 또는 토폴로지 뷰에서 서비스를 볼 수 있습니다. 기본 뷰는 테이블 뷰로, 테이블 형식으로 실행 중인 모든 분산 서비스를 보여줍니다. 뷰를 변경하려면 표시하려는 뷰를 클릭합니다.

  2. 테이블 뷰에서 frontend distributed service를 클릭합니다. 개별 서비스를 클릭하면 연결된 서비스와 함께 서비스의 세부 뷰가 표시됩니다.

    서비스 세부정보 뷰에서 타임라인 표시를 클릭하여 SLO를 만들고 서비스의 이전 타임라인을 볼 수 있습니다.

  3. 골든 신호를 보려면 측면 패널에서 측정항목을 클릭합니다.

  4. 초당 요청 수 차트에서 분류 기준을 클릭한 후 위치를 선택합니다.

    2개 리전에 있는 두 클러스터 모두의 초당 요청 수가 결과에 표시됩니다. 분산 서비스가 정상이고 두 엔드포인트 모두 트래픽을 제공합니다.

  5. 서비스 메시의 토폴로지를 보려면 사이드 패널에서 Anthos Service Mesh를 클릭한 후 토폴로지 뷰를 클릭합니다.

  6. 추가 데이터를 보려면 frontend 서비스 위로 마우스 포인터를 가져갑니다. 그러면 프런트엔드에서 다른 서비스로의 초당 요청 수와 같은 정보가 표시됩니다.

  7. 자세한 내용을 보려면 frontend 서비스에서 확장을 클릭하세요. 서비스 및 워크로드가 표시됩니다. 워크로드를 2개의 배포로 확장하고, 배포를 ReplicaSets로 확장한 후, ReplicaSets를 포드로 확장할 수 있습니다. 모든 요소를 확장하면 기본적으로 서비스 하나와 포드 2개로 구성되는 분산된 frontend 서비스를 확인할 수 있습니다.

멀티 클러스터 인그레스 구성

이 섹션에서는 두 클러스터 모두에서 실행되는 Bank of GKE Enterprise frontend 서비스로 트래픽을 전송하는 멀티 클러스터 인그레스를 만듭니다. Cloud Load Balancing을 사용하여 두 클러스터 모두에서 asm-ingressgateway 서비스를 백엔드로 사용하는 부하 분산기를 만듭니다. ingress-config 클러스터는 멀티 클러스터 인그레스 구성을 조정하기 위해 사용됩니다.

부하 분산기를 만들려면 MultiClusterIngress 및 하나 이상의 MultiClusterServices를 사용합니다. MultiClusterIngressMultiClusterService 객체는 단일 클러스터 컨텍스트에서 사용되는 기존 Kubernetes 인그레스 및 서비스 리소스의 멀티 클러스터 아날로그입니다.

  1. 필요한 GKE Enterprise, GKE Fleet, 멀티 클러스터 인그레스 API를 사용 설정합니다.

    gcloud services enable \
      anthos.googleapis.com \
      multiclusterservicediscovery.googleapis.com \
      multiclusteringress.googleapis.com
    
  2. ingress-config 클러스터를 만듭니다. 어떤 클러스터든 사용할 수 있지만 이 용도로 별도의 클러스터를 만드는 것이 좋습니다.

    gcloud container clusters create ${CLUSTER_INGRESS} \
      --zone ${CLUSTER_INGRESS_ZONE} \
      --num-nodes=1 \
      --enable-ip-alias \
      --workload-pool=${WORKLOAD_POOL}
    
  3. 편의를 위해 클러스터 사용자 인증 정보를 가져오고 컨텍스트 이름을 변경합니다.

    gcloud container clusters get-credentials ${CLUSTER_INGRESS} \
      --zone ${CLUSTER_INGRESS_ZONE} --project ${PROJECT_ID}
    
    kubectl config rename-context \
      gke_${PROJECT_ID}_${CLUSTER_INGRESS_ZONE}_${CLUSTER_INGRESS} ${CLUSTER_INGRESS}
    
  4. 멀티 클러스터 인그레스를 사용하려면 참여하는 모든 클러스터를 GKE Enterprise Fleet에 구성 클러스터를 포함하여 등록합니다.

  5. 구성 클러스터를 등록합니다.

    gcloud container fleet memberships register ${CLUSTER_INGRESS} \
      --project=${PROJECT_ID} \
      --gke-cluster=${CLUSTER_INGRESS_ZONE}/${CLUSTER_INGRESS} \
      --enable-workload-identity
    
  6. 모든 클러스터가 GKE Enterprise Fleet에 등록되었는지 확인합니다.

    gcloud container fleet memberships list
    

    출력은 다음과 같이 표시됩니다.

    NAME            EXTERNAL_ID
    gke-west        7fe5b7ce-50d0-4e64-a9af-55d37b3dd3fa
    gke-central     6f1f6bb2-a3f6-4e9c-be52-6907d9d258cd
    gke-ingress     3574ee0f-b7e6-11ea-9787-42010a8a019c
    
  7. ingress-config 클러스터에서 멀티 클러스터 인그레스 기능을 사용 설정합니다. 이렇게 하면 클러스터에서 MulticlusterServiceMulticlusterIngress CustomResourceDefinition(CRD)이 생성됩니다.

    gcloud container fleet ingress enable \
      --config-membership=projects/${PROJECT_ID}/locations/global/memberships/${CLUSTER_INGRESS}
    
  8. ingress-config 클러스터에서 멀티 클러스터 인그레스가 사용 설정되어 있는지 확인합니다.

    gcloud container fleet ingress describe
    

    출력은 다음과 같이 표시됩니다.

    membershipStates:
      projects/986443280307/locations/global/memberships/gke-central-priv:
        state:
          code: OK
          updateTime: '2022-09-29T13:57:02.972748202Z'
      projects/986443280307/locations/global/memberships/gke-ingress:
        state:
          code: OK
          updateTime: '2022-09-29T13:57:02.972744692Z'
      projects/986443280307/locations/global/memberships/gke-west-priv:
        state:
          code: OK
          updateTime: '2022-09-29T13:57:02.972746497Z'
    
  9. 두 CRD가 ingress-config 클러스터에 배포되었는지 확인합니다.

    kubectl --context=${CLUSTER_INGRESS} get crd | grep multicluster
    

    출력은 다음과 같이 표시됩니다.

    multiclusteringresses.networking.gke.io     2020-10-29T17:32:50Z
    multiclusterservices.networking.gke.io      2020-10-29T17:32:50Z
    
  10. ingress-config 클러스터에 asm-ingress 네임스페이스를 만듭니다.

    kubectl --context ${CLUSTER_INGRESS} create namespace asm-ingress
    
  11. MultiClusterIngress 리소스 만들기

    cat <<EOF > ${HOME}/mci.yaml
    apiVersion: networking.gke.io/v1beta1
    kind: MultiClusterIngress
    metadata:
      name: asm-ingressgateway-multicluster-ingress
    spec:
      template:
        spec:
          backend:
           serviceName: asm-ingressgateway-multicluster-svc
           servicePort: 80
    EOF
    
  12. MultiClusterService 리소스 만들기

    cat <<'EOF' > $HOME/mcs.yaml
    apiVersion: networking.gke.io/v1beta1
    kind: MultiClusterService
    metadata:
      name: asm-ingressgateway-multicluster-svc
      annotations:
        beta.cloud.google.com/backend-config: '{"ports": {"80":"gke-ingress-config"}}'
    spec:
      template:
        spec:
          selector:
            asm: ingressgateway
          ports:
          - name: frontend
            protocol: TCP
            port: 80 # servicePort defined in Multi Cluster Ingress
      clusters:
      - link: "us-west2-a/gke-west-priv"
      - link: "us-central1-a/gke-central-priv"
    EOF
    
  13. 상태 확인을 위해 BackendConfig 리소스를 만듭니다.

    cat <<EOF > $HOME/backendconfig.yaml
    apiVersion: cloud.google.com/v1beta1
    kind: BackendConfig
    metadata:
      name: gke-ingress-config
    spec:
      healthCheck:
        type: HTTP
        port: 15021
        requestPath: /healthz/ready
    EOF
    
  14. BackendConfig, MultiClusterService, MultiClusterIngress 매니페스트를 적용합니다.

    kubectl --context ${CLUSTER_INGRESS} -n asm-ingress apply -f ${HOME}/backendconfig.yaml
    kubectl --context ${CLUSTER_INGRESS} -n asm-ingress apply -f ${HOME}/mci.yaml
    kubectl --context ${CLUSTER_INGRESS} -n asm-ingress apply -f ${HOME}/mcs.yaml
    
  15. 인그레스 클러스터에 배포한 MultiClusterService는 클러스터 1과 클러스터 2에 '헤드리스' Service를 만듭니다. '헤드리스' Services가 생성되었는지 확인합니다.

    kubectl --context=${CLUSTER_1} -n asm-ingress \
      get services | grep multicluster-svc
    kubectl --context=${CLUSTER_2} -n asm-ingress \
      get services | grep multicluster-svc
    

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

    mci-frontend-multi-cluster-service-svc-f7rcyqry22iq8nmw   ClusterIP      None          <none>          80/TCP         77s
    mci-frontend-multi-cluster-service-svc-f7rcyqry22iq8nmw   ClusterIP      None          <none>          80/TCP         78s
    
  16. 다음 명령어를 실행하고 Cloud Load Balancing IP 주소가 표시될 때까지 기다립니다.

    watch kubectl --context ${CLUSTER_INGRESS} -n asm-ingress get multiclusteringress \
      -o jsonpath="{.items[].status.VIP}"
    

    출력은 다음과 같이 표시됩니다.

    35.35.23.11
    

    watch 명령어를 종료하려면 Ctrl+C를 누르세요.

  17. 웹브라우저에서 Cloud Load Balancing IP 주소로 이동하여 Bank of Anthos의 프런트엔드로 이동합니다.

    kubectl --context ${CLUSTER_INGRESS} \
      -n asm-ingress get multiclusteringress \
      -o jsonpath="{.items[].status.VIP}"
    

    404 오류(또는 502 오류)가 발생하면 몇 분 정도 기다린 후 웹브라우저에서 페이지를 새로고침하세요.

삭제

계정에 요금이 청구되지 않도록 프로젝트를 삭제하거나 클러스터를 삭제합니다.

프로젝트 삭제

청구되지 않도록 하는 가장 쉬운 방법은 튜토리얼에서 만든 프로젝트를 삭제하는 것입니다.

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

클러스터 삭제

  1. Cloud Shell에서 bluegreen 클러스터를 등록 취소하고 삭제합니다.

    gcloud container fleet memberships unregister ${CLUSTER_1} \
      --project=${PROJECT} \
      --gke-uri=${CLUSTER_1_URI}
    gcloud container clusters delete ${CLUSTER_1} \
      --zone ${CLUSTER_1_ZONE} \
      --quiet
    
    gcloud container fleet memberships unregister ${CLUSTER_2} \
      --project=${PROJECT} \
      --gke-uri=${CLUSTER_2_URI}
    gcloud container clusters delete ${CLUSTER_2} \
      --zone ${CLUSTER_2_ZONE} \
      --quiet
    
  2. 인그레스 구성 클러스터에서 MuticlusterIngress 리소스를 삭제합니다.

    kubectl --context ${CLUSTER_INGRESS} -n istio-system delete -f $HOME/mci.yaml
    

    이는 프로젝트에서 Cloud Load Balancing 리소스를 삭제합니다.

  3. ingress-config 클러스터를 등록 취소하고 삭제합니다.

    gcloud container fleet memberships unregister ${CLUSTER_INGRESS} \
      --project=${PROJECT} \
      --gke-uri=${CLUSTER_INGRESS_URI}
    gcloud container clusters delete ${CLUSTER_INGRESS} \
      --zone ${CLUSTER_INGRESS_ZONE} \
      --quiet
    
  4. 모든 클러스터가 삭제되었는지 확인합니다.

    gcloud container clusters list
    

    출력은 다음과 같습니다.

    <null>
  5. kubeconfig 파일을 재설정합니다.

    unset KUBECONFIG
    

다음 단계