EKS에 Multi-AZ Redis 클러스터 구축하기

박정호·2025년 5월 23일
post-thumbnail

EBS CSI Driver 설치 여부 확인

#EBS CSI Driver 설치 여부 확인
$ kubectl get pods -n kube-system | grep ebs

--- 아무것도 뜨지 않음 --- -> EBS CSI Driver 설치 되어있지 않음

$ kubectl get storageclass -o wide
NAME   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
gp2    kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  
19h

EKS 클러스터에 EBS CSI Driver가 아직 설치되지 않았다는 뜻

Kubernetes가 EBS 볼륨을 동적으로 생성할 수 없기 때문에 PVC가 계속 Pending 상태로 남아있어 문제가 발생하고 있다.

해결

eksctl로 EBS CSI 드라이버 설치

eksctl create addon \
  --name aws-ebs-csi-driver \
  --cluster <클러스터명> \
  --region ap-northeast-2 \
  --force

EBS CSI 드라이버 확인

kubectl get pods -n kube-system | grep ebs

csi driver 설치

eksctl create addon \
  --name aws-ebs-csi-driver \
  --cluster <클러스터명> \
  --region ap-northeast-2 \
  --service-account-role-arn <IAM_ROLE_ARN> \
  --force
kubectl apply -f gp3-storageclass.yaml
kubectl get pods -n kube-system | grep ebs

kubectl get pvc -n redis-cluster

kubectl get pods -n redis-cluster

하지만 여전히 pending인 상태가 지속 되었다

StorageClass gp2가 CSI 드라이버랑 연결되어 있지 않기 때문

위의 helm 방식은 잘 안되어서 yaml로 수동으로 해줘야 한다.

먼저 네임스페이스 생성

kubectl create namespace redis-cluster

Headless Service 생성

sudo vi redis-headless-svc.yaml

redis-headless-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: redis-cluster
spec:
  ports:
    - port: 6379
  clusterIP: None  # Headless
  selector:
    app: redis
kubectl apply -f redis-headless-svc.yaml

redis-statefulset.yaml

# redis-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
  namespace: redis-cluster
spec:
  serviceName: "redis"
  replicas: 6
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: redis
          image: redis:7.2
          command:
            - redis-server
            - "--cluster-enabled"
            - "yes"
            - "--cluster-config-file"
            - "nodes.conf"
            - "--cluster-node-timeout"
            - "5000"
            - "--appendonly"
            - "yes"
          ports:
            - containerPort: 6379
          volumeMounts:
            - name: data
              mountPath: /data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: gp3 <= redis의 pvc 
        resources:
          requests:
            storage: 1Gi
kubectl apply -f redis-statefulset.yaml

클러스터 구성

이제 모든 redis 파드가 bound 되었으니 클러스터를 구성해주자.

아래 명령어는 자동으로 마스터-슬레이브 쌍으로 클러스터를 구성해주는 명령어이다.

multi-az에 내가 원하는 구성으로 고정해서 구성하는 방식은 조금 더 아래에서 하도록 한다.

kubectl exec -n redis-cluster -it redis-0 -- redis-cli --cluster create \
  redis-0.redis:6379 redis-1.redis:6379 redis-2.redis:6379 \
  redis-3.redis:6379 redis-4.redis:6379 redis-5.redis:6379 \
  --cluster-replicas 1

클러스터 확인

kubectl exec -it redis-0 -n redis-cluster -- redis-cli -c
127.0.0.1:6379> cluster nodes

cluster info

cluster slots

현재 파드들 AZ 확인

kubectl get pod -n redis-cluster -o wide

각 노드가 어떤 AZ에 속하는지 확인

kubectl get nodes -L topology.kubernetes.io/zone

한 줄로 정리

kubectl get pod -n redis-cluster -o=custom-columns=NAME:.metadata.name,NODE:.spec.nodeName --no-headers | while read pod node; do
  zone=$(kubectl get node "$node" -o=jsonpath='{.metadata.labels.topology\.kubernetes\.io/zone}')
  echo "$pod -> $node -> $zone"
done

클러스터 구성이 성공한 것은 확인했다. 하지만 우리가 원하는 것은 Multi-AZ로 고가용성 클러스터!!!

Multi-AZ 클러스터 구성

위에는 마스터-슬레이브가 랜덤 AZ에 구성된다.

레디스 파드를 특정 노드에 고정해서 생성하고 마스터-슬레이브를 구성하도록 하자

기존 클러스터 삭제

kubectl delete statefulset redis -n redis-cluster

kubectl delete service redis -n redis-cluster
kubectl delete pvc --all -n redis-cluster

# pv 검색해서 redis-cluster 네임스페이스의 pv만 삭제
kubectl get pv

Redis Cluster on Multi-AZ (수동 구성) – 전체 구성 가이드

네임스페이스 생성

kubectl create namespace redis-cluster

Headless Service 정의 (redis-headless-svc.yaml)

apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: redis-cluster
spec:
  clusterIP: None  # Headless!
  selector:
    app: redis
  ports:
    - port: 6379
kubectl apply -f redis-headless-svc.yaml

StatefulSet 정의 (redis-statefulset.yaml)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
  namespace: redis-cluster
spec:
  serviceName: "redis"
  replicas: 6
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 1
              preference:
                matchExpressions:
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                      - ap-northeast-2a
            - weight: 1
              preference:
                matchExpressions:
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                      - ap-northeast-2b
            - weight: 1
              preference:
                matchExpressions:
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                      - ap-northeast-2c
      containers:
        - name: redis
          image: redis:7.2
          command:
            - redis-server
            - "--cluster-enabled"
            - "yes"
            - "--cluster-config-file"
            - "nodes.conf"
            - "--cluster-node-timeout"
            - "5000"
            - "--appendonly"
            - "yes"
          ports:
            - containerPort: 6379
          volumeMounts:
            - name: data
              mountPath: /data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: gp3
        resources:
          requests:
            storage: 1Gi
kubectl apply -f redis-statefulset.yaml

파드 및 PVC 상태 확인

kubectl get pod -o wide -n redis-cluster
kubectl get pvc -n redis-cluster

→ 각 Pod가 서로 다른 AZ의 노드에 분산되었는지 NODE 열로 확인하세요.


클러스터 생성용 클라이언트 Pod 생성

kubectl run redis-cluster-client --rm -it --restart=Never \
  -n redis-cluster \
  --image=bitnami/redis-cluster:7.0 \
  -- bash

왜 클라이언트 Pod가 필요할까?

Redis 클러스터 초기화 명령은 일반 Redis 서버(redis-server)에서는 실행할 수 없고,

redis-cli의 특별한 기능이기 때문에 다음 조건이 필요합니다:

조건이유
redis-cli 명령어 존재Redis 서버 이미지에는 CLI가 없을 수 있음
--cluster 옵션 사용 가능일반 redis-cli는 단순 키 조회용, 클러스터 명령은 별도 옵션 필요
✅ 클러스터 외부에서 전체 노드에 접근 가능노드 간 연결을 한 번에 조립해주는 역할 필요

🔨 예: 일반 redis Pod에는 없는 경우

Redis 서버에 직접 접속해서 시도해 보면:

kubectl exec -it redis-0 -n redis-cluster -- redis-cli --cluster create ...

→ 에러 발생 가능:

redis-cli: unknown option --cluster

이는 서버용 이미지에 redis-cli가 포함되지 않았거나, 알파인/경량화 버전으로 빌드됐기 때문입니다.


🧠 클러스터 생성은 하나의 "중앙 컨트롤러"가 필요한 과정

redis-cli --cluster create는 단순히 클러스터 명령을 던지는 게 아니라:

  • 각 노드에 접속해 CLUSTER MEET 수행
  • 슬롯을 나누고 (CLUSTER ADDSLOTS)
  • 슬레이브를 지정 (CLUSTER REPLICATE)
  • 각 노드 간 통신을 트리거

💡 즉, 모든 노드에 일괄적으로 작업을 수행해야 하기 때문에

→ 이를 실행할 수 있는 독립된 redis-cli가 필요한 것입니다.


✅ 결론

질문답변
왜 클러스터 생성용 클라이언트 Pod이 필요한가요?redis-cli --cluster create는 일반 redis-server에 없고, 모든 노드를 연결하고 구성하기 위해 별도의 클러스터 전용 클라이언트가 필요하기 때문입니다.
꼭 bitnami 이미지 써야 하나요?아니요, redis-cli만 있으면 다른 이미지도 가능하지만, bitnami/redis-cluster는 검증된 도구이므로 추천됩니다.

클러스터 생성 (Pod 안에서 실행)

redis-cli --cluster create \
  redis-0.redis:6379 redis-1.redis:6379 redis-2.redis:6379 \
  redis-3.redis:6379 redis-4.redis:6379 redis-5.redis:6379 \
  --cluster-replicas 1

→ 중간에 yes 입력 요구 시 반드시 입력


클러스터 상태 확인

redis-cli -c -h redis-0.redis
> cluster nodes
> cluster info

노드 별 AZ 구성

kubectl get nodes -o wide -L topology.kubernetes.io/zone

파드 ip

kubectl get pod -o wide -n redis-cluster

현재 클러스터 구성 상태

  • Master: redis-0 (ap-northeast-2b)Slave: redis-4 (ap-northeast-2c)
  • Master: redis-1 (ap-northeast-2c)Slave: redis-5 (ap-northeast-2a)
  • Master: redis-2 (ap-northeast-2a)Slave: redis-3 (ap-northeast-2b)

모든 파드가 분산 되어 있는 것을 확인할 수 있다.

0개의 댓글