Spotahome을 사용하여 GKE에 Redis 배포


Redis는 주로 캐싱에 사용되는 오픈소스 기반의 인메모리 NoSQL 데이터베이스입니다. 기본 제공 복제, Lua 스크립팅, LRU 제거, 트랜잭션, 온디스크 지속성, 고가용성을 포함합니다.

이 가이드는 Google Kubernetes Engine(GKE)에 Redis 클러스터 배포에 관심이 있는 플랫폼 관리자, 클라우드 설계자, 운영 전문가를 대상으로 합니다.

이 가이드에서는 Spotahome Redis 연산자를 사용해서 Redis 클러스터를 배포하는 방법을 보여줍니다.

이 연산자는 Apache License 2.0에 따라 라이선스가 부여됩니다.

Spotahome에서 제공하는 이점은 다음과 같습니다.

  • Kubernetes 기반 Redis 클러스터 관리
  • Redis Sentinel에서 제공하는 고가용성
  • 데이터베이스 관측 가능성을 위한 원활한 Prometheus 통합
  • 커스텀 Redis 구성 설정 지원

목표

  • Redis용 GKE 인프라 계획 및 배포
  • Spotahome Redis 연산자 배포 및 구성
  • 가용성, 보안, 관측 가능성, 성능을 보장하기 위해 연산자를 사용하여 Redis 구성

배포 아키텍처

이 튜토리얼에서는 Spotahome Redis 연산자를 사용해서 3개 복제본으로 구성된 Redis Sentinel 클러스터와 함께 리더 노드와 2개의 읽기 복제본을 사용해서 GKE에 고가용성 Redis 클러스터를 배포 및 구성합니다.

Redis Sentinel은 오픈소스 Redis를 위한 고가용성 모니터링 시스템입니다. 리더 및 연결된 복제본을 포함하여 Redis 인스턴스를 지속적으로 모니터링합니다. 리더 노드가 실패하면 Sentinel이 복제본 중 하나를 새 리더로 자동 승격하여 작동하는 리더 노드를 데이터 읽기 및 쓰기에 항상 사용할 수 있도록 보장합니다. 리더 장애 또는 장애 조치 이벤트와 같은 중요한 이벤트가 Redis 클러스터에서 발생할 때 Sentinel은 이메일 또는 기타 알림 메커니즘을 통해 관리자 또는 다른 시스템에 알림을 제공할 수 있습니다.

또한 여러 가용성 영역에 분산된 Kubernetes 노드와 함께 Redis를 위한 고가용성 리전 GKE 클러스터를 배포합니다. 이 설정은 내결함성, 확장성, 지리적 중복성을 보장하는 데 도움이 됩니다. 업타임 및 가용성을 위한 SLA를 제공하면서 순차적 업데이트 및 유지보수를 가능하게 해줍니다. 자세한 내용은 리전 클러스터를 참조하세요.

다음 다이어그램은 여러 노드 및 GKE 클러스터의 영역에서 Redis 클러스터가 실행되는 방식을 보여줍니다.

다이어그램에서 Redis StatefulSet는 서로 다른 3개 영역의 노드 3개에 배포되어 있습니다. RedisFailover 커스텀 리소스 사양에 포드 어피니티토폴로지 분산 규칙을 설정하여 GKE가 노드 및 영역에 StatefulSet를 배포하는 방식을 제어합니다.

한 영역에 장애가 발생하면 GKE가 권장 구성을 사용해서 새 노드에 포드를 다시 예약합니다.

다음 다이어그램은 서로 다른 3개 영역에 있는 3개 노드에 걸쳐서 예약된 Sentinel 배포를 보여줍니다.

비용

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

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

이 문서에 설명된 태스크를 완료했으면 만든 리소스를 삭제하여 청구가 계속되는 것을 방지할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

  1. Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. Google Cloud CLI를 설치합니다.
  3. gcloud CLI를 초기화하려면 다음 명령어를 실행합니다.

    gcloud init
  4. Google Cloud 프로젝트를 만들거나 선택합니다.

    • Google Cloud 프로젝트를 만듭니다.

      gcloud projects create PROJECT_ID

      PROJECT_ID를 만들려는 Google Cloud 프로젝트의 이름으로 바꿉니다.

    • 만든 Google Cloud 프로젝트를 선택합니다.

      gcloud config set project PROJECT_ID

      PROJECT_ID를 Google Cloud 프로젝트 이름으로 바꿉니다.

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

  6. Compute Engine, IAM, GKE, Backup for GKE, and Resource Manager API를 사용 설정합니다.

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com gkebackup.googleapis.com cloudresourcemanager.googleapis.com
  7. Google Cloud CLI를 설치합니다.
  8. gcloud CLI를 초기화하려면 다음 명령어를 실행합니다.

    gcloud init
  9. Google Cloud 프로젝트를 만들거나 선택합니다.

    • Google Cloud 프로젝트를 만듭니다.

      gcloud projects create PROJECT_ID

      PROJECT_ID를 만들려는 Google Cloud 프로젝트의 이름으로 바꿉니다.

    • 만든 Google Cloud 프로젝트를 선택합니다.

      gcloud config set project PROJECT_ID

      PROJECT_ID를 Google Cloud 프로젝트 이름으로 바꿉니다.

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

  11. Compute Engine, IAM, GKE, Backup for GKE, and Resource Manager API를 사용 설정합니다.

    gcloud services enable compute.googleapis.com iam.googleapis.com container.googleapis.com gkebackup.googleapis.com cloudresourcemanager.googleapis.com
  12. Google 계정에 역할을 부여합니다. 다음 각 IAM 역할에 대해 다음 명령어를 한 번씩 실행합니다. roles/storage.objectViewer, roles/container.admin, roles/iam.serviceAccountAdmin, roles/compute.admin, roles/gkebackup.admin, roles/monitoring.viewer

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:EMAIL_ADDRESS" --role=ROLE
    • PROJECT_ID를 프로젝트 ID로 바꿉니다.
    • EMAIL_ADDRESS를 이메일 주소로 바꿉니다.
    • ROLE을 각 개별 역할로 바꿉니다.

환경 설정

이 튜토리얼에서는 Cloud Shell을 사용하여 Google Cloud에서 호스팅되는 리소스를 관리합니다. Cloud Shell에는 kubectl, gcloud CLI, Helm, Terraform을 포함하여 이 튜토리얼에 필요한 소프트웨어가 사전 설치되어 있습니다.

Cloud Shell로 환경을 설정하려면 다음 단계를 따르세요.

  1. Google Cloud 콘솔에서 Cloud Shell 활성화 아이콘Cloud Shell 활성화를 클릭하여 Google Cloud 콘솔에서 Cloud Shell 세션을 시작합니다. 그러면 Google Cloud 콘솔 하단 창에서 세션이 시작됩니다.

  2. 환경 변수를 설정합니다.

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=redis
    export REGION=us-central1
    

    PROJECT_ID를 Google Cloud의 프로젝트 ID로 바꿉니다.

  3. GitHub 저장소를 클론합니다.

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  4. 작업 디렉터리로 변경합니다.

    cd kubernetes-engine-samples/databases/redis-spotahome
    

클러스터 인프라 만들기

이 섹션에서는 Terraform 스크립트를 실행하여 가용성이 높은 비공개 리전 GKE 클러스터를 만듭니다. 다음 단계에서는 제어 영역에 대한 공개 액세스를 허용합니다.

Standard 또는 Autopilot 클러스터를 사용하여 연산자를 설치할 수 있습니다.

Standard

다음 다이어그램에서는 서로 다른 영역 3개에 배포된 비공개 리전 Standard GKE 클러스터를 보여줍니다.

이 인프라를 배포하려면 Cloud Shell에서 다음 명령어를 실행합니다.

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-standard init
terraform -chdir=terraform/gke-standard apply -var project_id=${PROJECT_ID} \
  -var region=${REGION} \
  -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

메시지가 표시되면 yes를 입력합니다. 이 명령어가 완료되고 클러스터에 준비 상태가 표시되는 데 몇 분 정도 걸릴 수 있습니다.

Terraform에서 다음 리소스를 만듭니다.

  • Kubernetes 노드의 VPC 네트워크 및 비공개 서브넷
  • NAT를 통해 인터넷에 액세스할 수 있는 라우터
  • us-central1 리전의 비공개 GKE 클러스터
  • 자동 확장이 사용 설정된 2개 노드 풀(영역당 1~2개 노드, 최소 영역당 1개 노드)
  • 로깅 및 모니터링 권한이 있는 ServiceAccount
  • 재해 복구를 위한 Backup for GKE
  • 클러스터 모니터링을 위한 Google Cloud Managed Service for Prometheus

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

...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.
...

Autopilot

다음 다이어그램에서는 비공개 리전 Autopilot GKE 클러스터를 보여줍니다.

인프라를 배포하려면 Cloud Shell에서 다음 명령어를 실행합니다.

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=terraform/gke-autopilot init
terraform -chdir=terraform/gke-autopilot apply -var project_id=${PROJECT_ID} \
  -var region=${REGION} \
  -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

메시지가 표시되면 yes를 입력합니다. 이 명령어가 완료되고 클러스터에 준비 상태가 표시되는 데 몇 분 정도 걸릴 수 있습니다.

Terraform에서 다음 리소스를 만듭니다.

  • Kubernetes 노드의 VPC 네트워크 및 비공개 서브넷
  • NAT를 통해 인터넷에 액세스할 수 있는 라우터
  • us-central1 리전의 비공개 GKE 클러스터
  • 로깅 및 모니터링 권한이 있는 ServiceAccount
  • 클러스터 모니터링을 위한 Google Cloud Managed Service for Prometheus

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

...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.
...

클러스터에 연결

Cloud Shell을 사용해서 클러스터와 통신하도록 kubectl을 구성합니다.

gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --region ${REGION}

클러스터에 Spotahome 연산자 배포

이 섹션에서는 Helm 차트를 사용해서 Kubernetes 클러스터에 Spotahome 연산자를 배포한 후 Redis 클러스터를 배포합니다.

  1. Spotahome Redis 연산자 Helm 차트 저장소를 추가합니다.

    helm repo add redis-operator https://spotahome.github.io/redis-operator
    
  2. Spotahome 연산자 및 Redis 클러스터의 네임스페이스를 추가합니다.

    kubectl create ns redis
    
  3. Helm 명령줄 도구를 사용하여 Spotahome 연산자를 배포합니다.

    helm install redis-operator redis-operator/redis-operator --version 3.2.9 -n redis
    
  4. Helm을 사용하여 Spotahome 연산자의 배포 상태를 확인합니다.

    helm ls -n redis
    

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

    NAME             NAMESPACE    REVISION    UPDATED                                STATUS      CHART                   APP VERSION
    redis-operator    redis      1           2023-09-12 13:21:48.179503 +0200 CEST    deployed    redis-operator-3.2.9    1.2.4
    

Redis 배포

Redis 클러스터 인스턴스의 기본 구성에는 다음 구성요소가 포함됩니다.

  • Redis 노드의 복제본 3개: 리더 1개와 읽기 복제본 2개
  • 쿼럼을 형성하는 Sentinel 노드의 복제본 3개
  • CPU 요청 1개 및 CPU 한도 2개의 CPU 리소스 할당(Redis의 경우 4GB 메모리 요청 및 한도 지원, Sentinel의 경우 100m/500m CPU 및 500MB 지원)
  • Kubernetes 노드 간 적절한 배포를 보장하고 해당 노드 풀 및 서로 다른 가용성 영역을 활용하는 각 워크로드에 구성된 톨러레이션(toleration), nodeAffinities, topologySpreadConstraints

이 구성은 프로덕션에 사용 가능한 Redis 클러스터를 만드는 데 필요한 최소 설정을 나타냅니다.

기본 Redis 클러스터 만들기

  1. 사용자 인증 정보로 보안 비밀을 만듭니다.

    export PASSWORD=$(openssl rand -base64 12)
    kubectl create secret generic my-user -n redis \
        --from-literal=password="$PASSWORD"
    

    이 연산자에는 사용자 인증 정보 생성 기능이 없습니다. 데이터베이스 비밀번호를 미리 생성해야 합니다.

  2. 기본 구성을 사용하여 새 Redis 클러스터를 만듭니다.

    kubectl apply -n redis -f manifests/01-basic-cluster/my-cluster.yaml
    

    이 명령어는 CPU, 메모리 요청 및 한도를 지정하는 Spotahome 연산자의 RedisFailover 커스텀 리소스를 만들고, Kubernetes 노드 간에 프로비저닝된 포드 복제본을 배포하기 위한 taint 및 어피니티를 만듭니다.

  3. Kubernetes에서 필요한 워크로드를 시작하는 동안 몇 분 정도 기다립니다.

    kubectl wait pods -l redisfailovers.databases.spotahome.com/name=my-cluster --for condition=Ready --timeout=300s -n redis
    
  4. Redis 워크로드가 생성되었는지 확인합니다.

    kubectl get pod,svc,statefulset,deploy,pdb -n redis
    

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

    NAME                                READY   STATUS  RESTARTS   AGE
    pod/redis-operator-5dc65cb7cc-krlcs   1/1   Running   0         49m
    pod/rfr-my-cluster-0                2/2     Running   0         60s
    pod/rfr-my-cluster-1                2/2     Running   0         60s
    pod/rfr-my-cluster-2                2/2     Running   0         60s
    pod/rfs-my-cluster-8475dfd96c-h5zvw   1/1   Running   0         60s
    pod/rfs-my-cluster-8475dfd96c-rmh6f   1/1   Running   0         60s
    pod/rfs-my-cluster-8475dfd96c-shzxh   1/1   Running   0         60s
    
    NAME                    TYPE        CLUSTER-IP  EXTERNAL-IP   PORT(S)   AGE
    service/redis-my-cluster ClusterIP   10.52.14.87   <none>       6389/TCP    55s
    service/redis-operator   ClusterIP   10.52.13.217   <none>      9710/TCP    49m
    service/rfr-my-cluster   ClusterIP   None           <none>      9121/TCP    61s
    service/rfs-my-cluster   ClusterIP   10.52.15.197   <none>      26379/TCP   61s
    
    NAME                            READY   AGE
    statefulset.apps/rfr-my-cluster   3/3   61s
    
    NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/redis-operator   1/1    1           1           50m
    deployment.apps/rfs-my-cluster   3/3    3           3           62s
    
    NAME                                        MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
    poddisruptionbudget.policy/rfr-my-cluster   2               N/A             1                   64s
    poddisruptionbudget.policy/rfs-my-cluster   2               N/A             1                   63s
    

연산자는 다음 리소스를 만듭니다.

  • Redis StatefulSet 및 Sentinel 배포
  • Redis용 포드 복제본 3개
  • Sentinel용 포드 복제본 3개
  • 클러스터 일관성을 위해 복제본 2개의 최소 가용성을 보장하는 PodDisruptionBudgets 2개
  • Redis 측정항목을 노출하는 rfr-my-cluster 서비스
  • Redis 클러스터 리더 노드를 대상으로 하는 redis-my-cluster 서비스
  • 클라이언트가 Sentinel을 통해 클러스터에 연결할 수 있게 해주는 rfs-my-cluster 서비스. Sentinel 지원은 클라이언트 라이브러리에 필요합니다.

Redis 사용자 인증 정보 공유

Spotahome 연산자 레거시 인증 방법을 사용해서 클라이언트와 Redis 사용자 인증 정보를 공유할 수 있습니다.

requirepass 설정을 사용해서 데이터베이스 비밀번호를 사용해야 합니다. 그런 후 모든 클라이언트에서 이 비밀번호가 사용됩니다. 추가 사용자를 관리하려면 Redis CLI 명령어를 사용합니다.

apiVersion: databases.spotahome.com/v1
kind: RedisFailover
metadata:
  name: my-cluster
spec:
  ...
  auth:
    secretPath: my-user

이 방법으로 클라이언트와 Redis 사용자 인증 정보를 공유할 때는 다음과 같은 제한사항이 있습니다.

  • Spotahome은 사용자 관리를 위한 커스텀 리소스를 제공하지 않습니다. 보안 비밀에 사용자 인증 정보를 저장하고 auth 사양에서 이를 참조할 수 있습니다.
  • 커스텀 리소스를 사용하여 TLS 암호화로 연결을 보호할 수 있는 방법이 없습니다.
  • 사용자 인증 정보의 실시간 업데이트가 지원되지 않습니다.

Redis에 연결

Redis 클라이언트를 배포하고 Kubernetes 보안 비밀에 저장된 비밀번호를 사용하여 인증할 수 있습니다.

  1. 클라이언트 포드를 실행하여 Redis 클러스터와 상호 작용합니다.

    kubectl apply -n redis -f manifests/02-auth/client-pod.yaml
    

    PASS 환경 변수는 저장소에서 my-user 보안 비밀을 가져옵니다.

  2. 포드가 준비될 때까지 기다린 후 연결합니다.

    kubectl wait pod redis-client --for=condition=Ready --timeout=300s -n redis
    kubectl exec -it redis-client -n redis -- /bin/bash
    
  3. 연결이 작동하는지 확인합니다.

    redis-cli -h redis-my-cluster -a $PASS --no-auth-warning SET my-key "testvalue"
    

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

    OK
    
  4. my-key 값을 가져옵니다.

    redis-cli -h redis-my-cluster -a $PASS --no-auth-warning GET my-key
    

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

    "testvalue"
    
  5. 포드 셸을 종료합니다.

    exit
    

Prometheus가 Redis 클러스터에 대해 측정항목을 수집하는 방법 이해

다음 다이어그램은 Prometheus 측정항목 수집의 작동 방식을 보여줍니다.

다이어그램에서 GKE 비공개 클러스터에는 다음이 포함됩니다.

  • / 경로 및 9121 포트로 측정항목을 수집하는 Redis 포드
  • Redis 포드의 측정항목을 처리하는 Prometheus 기반 수집기
  • Cloud Monitoring으로 측정항목을 전송하는 PodMonitoring 리소스

Google Cloud Managed Service for Prometheus는 Prometheus 형식의 측정항목 수집을 지원합니다. Cloud Monitoring은 Redis 측정항목에 대해 통합 대시보드를 사용합니다.

Spotahome 연산자는 redis_exporter를 사이드카로 사용해서 Prometheus 형식으로 클러스터 측정항목을 노출합니다.

  1. labelSelector로 측정항목을 스크래핑하도록 PodMonitoring 리소스를 만듭니다.

    kubectl apply -n redis -f manifests/03-prometheus-metrics/pod-monitoring.yaml
    
  2. Google Cloud 콘솔에서 GKE 클러스터 대시보드 페이지로 이동합니다.

    GKE 클러스터 대시보드로 이동

    대시보드에 0이 아닌 측정항목 수집 비율이 표시됩니다.

  3. Google Cloud 콘솔에서 대시보드 페이지로 이동합니다.

    대시보드로 이동

  4. Redis Prometheus 개요 대시보드를 엽니다. 대시보드에 연결 및 키의 양이 표시됩니다. 대시보드가 자동 프로비저닝되는 데 몇 분 정도 걸릴 수 있습니다.

  5. 클라이언트 포드에 연결하고 변수를 준비합니다.

    kubectl exec -it redis-client -n redis -- /bin/bash
    
  6. redis-cli 도구를 사용해서 새 키를 만듭니다.

    for i in {1..50}; do \
      redis-cli -h redis-my-cluster -a $PASS \
      --no-auth-warning SET mykey-$i "myvalue-$i"; \
    done
    
  7. 페이지를 새로고침하고 초당 명령어 그래프가 실제 데이터베이스 상태를 표시하도록 업데이트되었는지 확인합니다.

  8. 포드 셸을 종료합니다.

    exit
    

삭제

프로젝트 삭제

    Google Cloud 프로젝트를 삭제합니다.

    gcloud projects delete PROJECT_ID

개별 리소스 삭제

  1. 환경 변수를 설정합니다.

    export PROJECT_ID=${PROJECT_ID}
    export KUBERNETES_CLUSTER_PREFIX=redis
    export REGION=us-central1
    
  2. terraform destroy 명령어를 실행합니다.

    export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
    terraform -chdir=terraform/FOLDER destroy -var project_id=${PROJECT_ID} \
      -var region=${REGION} \
      -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}
    

    FOLDERgke-autopilot 또는 gke-standard로 바꿉니다.

    메시지가 표시되면 yes를 입력합니다.

  3. 연결되지 않은 모든 디스크를 찾습니다.

    export disk_list=$(gcloud compute disks list --filter="-users:* AND labels.name=${KUBERNETES_CLUSTER_PREFIX}-cluster" --format "value[separator=|](name,zone)")
    
  4. 디스크를 삭제합니다.

    for i in $disk_list; do
      disk_name=$(echo $i| cut -d'|' -f1)
      disk_zone=$(echo $i| cut -d'|' -f2|sed 's|.*/||')
      echo "Deleting $disk_name"
      gcloud compute disks delete $disk_name --zone $disk_zone --quiet
    done
    

다음 단계

  • Google Cloud에 대한 참조 아키텍처, 다이어그램, 권장사항 살펴보기 Cloud 아키텍처 센터 살펴보기