k8s_intro_3
쿠버네티스(Kubernetes) 환경에서 Redis 구축 가이드 ③
레디스 구축 준비
☸️ Redis Docker 이미지 준비 방법 (온라인 vs 폐쇄망)
1) 인터넷 연결 환경 (Online)
쿠버네티스 매니페스트(YAML) 내에 'image: redis:8.8.2'을 명시하고 'imagePullPolicy: IfNotPresent'를 주면 자동으로 Docker Hub에서 최신 이미지를 다운로드합니다.
2) 폐쇄망 환경 (Air-Gapped) - Rocky Linux 9.5 적용 방식
외부 인터넷 접속이 불가능한 폐쇄망 서버에서는 이미지 패키징 및 K3s 수동 로딩 작업을 수행해야 합니다.
- [1단계] 인터넷 가능 PC/서버에서 이미지 추출
# Docker를 이용하여 저장
$ docker pull redis:8.8.2
$ docker save -o redis-8.8.2.tar redis:8.8.2 - [2단계] 폐쇄망 Rocky Linux 9.5 서버로 파일 이관 및 K3s 이미지 로드
# 방법 A: k3s ctr(containerd CLI) 이용 직접 임포트 (추천)
$ sudo k3s ctr images import redis-8.8.2.tar
# 방법 B: K3s 자동 에이전트 이미지 디렉토리에 복사
$ cp redis-8.8.2.tar /var/lib/rancher/k3s/agent/images/ - ⚠️ 주의: StatefulSet YAML 파일 작성 시 'imagePullPolicy: IfNotPresent'로 설정하여, 쿠버네티스가 외부 인터넷으로 이미지를 다시 당겨오려다 실패하는 오류('ErrImagePull')를 방지해야 합니다.
구축 및 테스트 환경 명세
본 가이드 시리즈의 모든 테스트는 아래 사양의 환경에서 실증 검증되었습니다.
- OS: Rocky Linux 9.5 (Blue Onyx) - 64bit
- Kubernetes: K3s (v1.x, CNCF Certified Lightweight Kubernetes)
- Redis Version: Redis 8.8.2 (Latest Open Source Release)
- StorageClass: local-path (K3s 내장 Persistent Volume)
- Service Ports: Redis Port: 18504, Sentinel Port: 28504, Cluster Bus Port: 28504
- Network: Headless Service Dynamic DNS Resolution
쿠버네티스 Redis 구성 및 테스트 목차
본 가이드는 3개의 세부 구성 페이지와 1개의 종합 결론 페이지로 이어집니다. 아래 링크를 통해 각 아키텍처별 구축 방법, YAML 설정, 그리고 실제 Failover 검증 로그를 확인하실 수 있습니다.
💻 Redis-Cluster (6pods) 구성 및 테스트
- 개요: 3 Master + 3 Replica 구조의 고성능 샤딩 아키텍처.
- 핵심 요소: StatefulSet + Headless Service 기반 구성, 'cluster-announce-hostname'을 이용한 IP 변동 대응, 'create-redis-cluster.sh' 자동화 스크립트 제공.
- 🔗 [Redis-Cluster (6pods) 상세 구축 가이드 바로가기]
💻 Redis-Sentinel (6pods) 구성 및 테스트
- 개요: Redis 전용 Pod 3개와 Sentinel 전용 Pod 3개를 완벽히 분리한 고가용성(HA) 구성.
- 핵심 요소: 센티널 간 Pub/Sub 대화를 통한 자동 Failover, 'replica-priority' 제어를 통한 우선순위 기반 마스터 승격.
- 🔗 [Redis-Sentinel (6pods) 상세 구축 가이드 바로가기]
💻 Redis-Sentinel Sidecar 패턴 (3pods) 구성 및 테스트
- 개요: 1 Pod 내에 [Redis + Sentinel] 컨테이너를 함께 묶어 총 3개 Pod로 구현
- 핵심 요소: 자원 절감, 동일 Pod IP/볼륨 공유, 메인 레디스와 센티널 간 완전한 프로세스 격리 검증.
- 🔗 [Redis-Sentinel Sidecar 패턴 (3pods) 상세 구축 가이드 바로가기]
💻 Redis-Cluster 용 Java(Spring) App 구현/테스트
- 개요: App 구현 시 어떤 설정을 해야 쿠버네티스 Redis-Cluster 환경에 적합한지 구현/테스트
- 🔗 [Redis-Cluster 용 Java(Spring) App 구현/테스트 바로가기]
💻 Redis-Sentinel 용 Java(Spring) App 구현/테스트
- 개요: App 구현 시 어떤 설정을 해야 쿠버네티스 Redis-Sentinel 환경에 적합한지 구현/테스트
- 🔗 [Redis-Sentinel 용 Java(Spring) App 구현/테스트 바로가기]
💻 맺음말: 어느 아키텍처를 선택할 것인가?
- 개요: 프로젝트 규모, 자원 제약(Pod 개수), 데이터 용량, Read/Write 부하 분산 요구사항에 따른 최종 아키텍처 선택 가이드.
- 🔗 [쿠버네티스 Redis 아키텍처 선택 가이드 바로가기]
⚠️ Spring(Java) 환경에서 반드시 주의해야 할 점(JVM DNS 캐싱)📍
여기서 레디스 개발자가 꼭 알고 계셔야 하는 아주 중요한 Java/Spring 특성이 하나 있습니다. Java Virtual Machine(JVM)은 성능 향상을 위해 한 번 조회한 DNS 결과를 기본적으로 일정 시간 동안 메모리에 캐싱(Caching)해 둡니다.
💥 발생 가능한 문제 시나리오
- 1. 레디스/센티널 파드가 죽어서 재시작되어 IP가 '10.244.1.20' → '10.244.2.35'로 변경되었습니다.
- 2. K8s CoreDNS는 새 IP('10.244.2.35')를 알고 있습니다.
- 3. 하지만 Spring App의 JVM이 옛날 IP('10.244.1.20')를 계속 캐싱하고 있다면, CoreDNS에 물어보지도 않고 옛날 IP로 계속 접속을 시도하다가 커넥션 에러('UnknownHostException' 또는 'Connection Refused')가 터질 수 있습니다.
💡 해결 방법 (JVM DNS TTL 설정)
Spring App이 켜질 때 JVM의 DNS 캐시 유지 시간(TTL)을 짧게(예: 1초~3초) 설정해 주어야 합니다.
여기서는 1초로 설정했습니다. 1초면 너무 짧지 않나?
매초 다시 조회해서 설정하려면 JVM에 부하를 주는 것 아닌가?
이렇게 생각할 수도 있습니다. 하지만, 다음과 같이 총 장애복구(Failover) 시간을 고려했을 때
결코 짧지 않습니다.
① 레디스 자체 Failover 소요 시간: 'cluster-node-timeout'을 3초로 설정해도 4~5초 정도 걸립니다.
② Java(Spring Lettuce): Redis-Cluster 정보 업데이트 시간: 2초
③ JVM DNS 캐시 유지 시간을 10초 한다면 5초+2초+10초 = 17초 걸립니다.
17초 동안 명령을 처리하지 못한다는 것은 작은 문제가 아닙니다.
따라서 'JVM DNS 캐시 유지 시간'을 1초로 설정해서 총 8초 이내에 완전 복구해야 합니다.
- Java 옵션(JVM 옵션) 추가(deployment.yaml): -Dsun.net.inetaddr.ttl=1 📍
(DNS 조회 성공 결과를 1초만 캐싱하고 이후엔 CoreDNS에 다시 물어보라는 설정입니다.) - Spring App 시작 코드(Java)에 추가:
java.security.Security.setProperty("networkaddress.cache.ttl", "1"); 📍
| << Kubernetes k3s ② | K8s Redis-Cluster 준비 ① >> |
|---|
