환경: k3s v1.31+, Helm v3, ArgoCD v3.3+, Bitnami Redis Chart 24.x
들어가며
3편에서 ArgoCD와 GitOps 파이프라인을 구축하여 코드 푸시 한 번으로 자동 배포되는 환경을 만들었습니다. 하지만 Next.js 앱의 런타임 캐시(ISR 재생성, fetch 캐시)가 Pod 로컬 파일시스템에 저장되고 있어서, Pod가 재시작되면 캐시가 날아가고 여러 Pod 간에 캐시가 공유되지 않는 문제가 있었습니다.
이 편에서는 k3s 클러스터에 Redis를 배포하고, RedisInsight로 모니터링할 수 있는 환경을 구축합니다. Next.js와의 연동은 다음 편에서 다룹니다.
Redis란
Redis는 메모리 기반 key-value 저장소입니다. 디스크가 아닌 RAM에 데이터를 올려놓기 때문에, 단순 읽기/쓰기에서 마이크로초 단위의 응답 속도를 보여줍니다. String, Hash, List, Set, Sorted Set 등 다양한 자료구조를 네이티브로 지원하며, 캐시, 세션 저장, 메시지 큐, 실시간 카운터 등 빠른 접근이 필요한 임시 데이터를 다루는 데 적합합니다.
SET user:1:name "건우" ← 저장
GET user:1:name ← 조회 → "건우"
이 프로젝트에서 Redis를 도입하는 이유는 명확합니다. Next.js의 런타임 캐시(ISR 재생성, fetch 캐시)가 Pod 로컬 파일시스템에 저장되고 있는데, Pod가 재시작되면 캐시가 사라지고 여러 Pod 간에 캐시가 공유되지 않습니다. Redis를 외부 캐시 저장소로 두면 Pod 라이프사이클과 캐시를 분리할 수 있고, 모든 Pod이 동일한 캐시를 바라보게 됩니다.
키 네임스페이스와 멀티테넌시
Redis 인스턴스 하나는 하나의 빈 key-value 공간입니다. 관계형 DB처럼 테이블이나 스키마가 없기 때문에, 어떤 키가 어떤 앱의 것인지 Redis가 구분해주지 않습니다. 대신 저장하는 쪽(앱 코드)이 키 이름에 접두어를 붙여 네임스페이스를 만듭니다.
docs:abc123:/about ← Next.js docs 앱의 캐시
docs:abc123:/blog/1 ← Next.js docs 앱의 캐시
myapp:session:xyz789 ← 다른 앱의 세션
하나의 Redis에 여러 앱이 공존할 수 있고, 접두어 규칙만 잘 정하면 서로 충돌하지 않습니다. 이 프로젝트에서는 docs:<빌드ID>: 형태의 접두어로 앱과 빌드 버전까지 격리하는데, 그 이유는 5편에서 다룹니다.
Bitnami Helm 차트
Redis를 Kubernetes에 배포하려면 StatefulSet, Service, PVC, ConfigMap, Secret 참조 등 여러 리소스를 직접 작성해야 합니다. Bitnami는 이 모든 것을 패키징한 Helm 차트를 제공하며, 주간 다운로드 수백만 건의 커뮤니티 검증을 거친 프로덕션급 템플릿입니다. helm install redis bitnami/redis 한 줄이면 필요한 리소스가 전부 생성되고, Bitnami 팀이 보안 패치와 버전 업데이트를 지속적으로 관리합니다.
차트와 values의 분리
Helm 차트는 템플릿(차트 코드)과 설정값(values)으로 나뉩니다. Bitnami 차트 전체를 프로젝트에 복사하면 수십 개 파일에 수천 줄이 추가되고, 업스트림 업데이트를 직접 추적해야 하는 부담이 생깁니다. 대신 values 파일만 Git에 관리하는 구조를 택했습니다.
- 차트 코드 → Bitnami 서버에서 가져옴 (업데이트 책임도 Bitnami)
- 설정값 → 이 레포의
mirunamu/redis/values.yaml에서 관리 (Git으로 추적)
이 구조의 실질적 이점은 재현성입니다. 클러스터가 날아가더라도 values 파일이 Git에 있으니 동일한 구성을 그대로 복원할 수 있습니다.
레포 구조
| 파일 | git | 역할 |
|---|---|---|
mirunamu/redis/values.yaml | O | Redis 설정 (비밀번호 없음, Secret 이름만 참조) |
argocd/redis-app.yaml | O | ArgoCD가 Bitnami Redis 차트를 배포 |
mirunamu/redis-insight/* | O | RedisInsight Helm 차트 |
argocd/redis-insight-app.yaml | O | ArgoCD가 RedisInsight를 배포 |
secrets/redis-secret.yaml | X | 비밀번호 실제 값. kubectl apply로 수동 적용 |
Bitnami 차트 저장소 등록
Helm은 차트를 원격 저장소(repository)에서 가져옵니다. Bitnami 차트를 사용하려면 먼저 로컬 Helm에 저장소 주소를 등록해야 합니다. 이 단계는 로컬 PC에서 한 번만 실행하면 되며, 클러스터에는 영향을 주지 않습니다.
helm repo add bitnami https://charts.bitnami.com/bitnami# 등록 확인
helm repo list
# 목록 갱신 (최신 차트 버전 반영)
helm repo updateRedis 설정 파일 생성
# mirunamu/redis/values.yaml
architecture: replication
# Redis keyspace notification 활성화 (캐시 만료 이벤트 감지용)
commonConfiguration: |-
notify-keyspace-events Exe
auth:
existingSecret: redis-secret
existingSecretPasswordKey: redis-password
master:
persistence:
size: 1Gi
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
replica:
replicaCount: 1
persistence:
size: 1Gi
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi주요 설정 해설
architecture: replication — Bitnami Redis 차트는 standalone과 replication 두 가지 아키텍처를 지원합니다. standalone은 마스터 Pod 하나만 띄우는 구성이고, replication은 마스터 1개와 레플리카 N개를 띄워 데이터를 실시간 복제합니다. 홈 클러스터 규모에서 레플리카가 반드시 필요한 것은 아니지만, 추후 용도가 늘어날 가능성을 고려하여 replication으로 구성했습니다.
| 역할 | Pod | 기능 |
|---|---|---|
| 마스터 | redis-master-0 | 모든 읽기/쓰기 처리 |
| 레플리카 | redis-replicas-0 | 마스터 데이터를 실시간 복제, 읽기 분산 가능 |
auth.existingSecret — Redis 비밀번호를 values 파일에 평문으로 적는 대신, Kubernetes Secret 리소스를 참조하도록 합니다. values 파일은 Git에 올라가므로 비밀번호가 노출되면 안 되고, Secret은 .gitignore 처리된 별도 파일로 관리합니다.
commonConfiguration: notify-keyspace-events Exe — Redis의 Keyspace Notification 기능을 활성화합니다. E는 이벤트 타입별 알림, x는 키 만료(expired), e는 키 퇴거(evicted) 이벤트를 의미합니다. 캐시 핸들러 라이브러리가 이 알림을 구독하여 만료된 캐시를 감지하는 데 사용합니다.
리소스 제한 — requests는 Pod가 스케줄링될 때 최소 보장 자원이고, limits는 사용 가능한 상한입니다. 홈 서버는 자원이 한정되어 있으므로, Redis가 다른 워크로드의 자원을 잠식하지 않도록 CPU 250m / 메모리 256Mi로 상한을 설정했습니다. 캐시 데이터가 수백 MB를 넘어가지 않는 한 이 정도면 충분합니다.
persistence.size: 1Gi — Redis는 메모리 기반이지만 RDB 스냅샷이나 AOF 로그로 디스크에 데이터를 백업합니다. PVC 1GB는 현재 캐시 규모(수십 MB)에 비해 넉넉한 값입니다.
사용 가능한 전체 설정 확인
helm show values bitnami/redis수백 개 항목이 출력됩니다. 이 중 필요한 것만 values.yaml에 오버라이드하면 나머지는 차트 기본값이 적용됩니다.
Redis Secret 생성
# secrets/redis-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: redis-secret
type: Opaque
stringData:
redis-password: "비밀번호"이 파일은 .gitignore에 포함되어 Git에 올라가지 않습니다. 비밀번호가 포함된 파일이므로 반드시 로컬에서만 관리해야 합니다.
# 수동으로 클러스터에 적용 (최초 1회)
kubectl apply -f secrets/redis-secret.yaml -n mirunamu
# 확인
kubectl get secret redis-secret -n mirunamu주의
Secret이 클러스터에 먼저 있어야 Redis Pod가 뜰 때 비밀번호를 찾을 수 있습니다. ArgoCD로 Redis를 배포하기 전에 반드시 먼저 적용해야 합니다.
ArgoCD Application 생성
# argocd/redis-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: redis
namespace: argocd
spec:
project: default
sources:
# Bitnami 서버에서 Redis Helm 차트를 가져옴
- repoURL: https://charts.bitnami.com/bitnami
chart: redis
targetRevision: 24.*
helm:
valueFiles:
- $values/mirunamu/redis/values.yaml
# 이 Git 레포에서 values 파일을 가져옴
- repoURL: https://github.com/mirunamu00/helm-chart.git
targetRevision: master
ref: values
destination:
server: https://kubernetes.default.svc
namespace: mirunamu
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=truemulti-source Application
일반적인 ArgoCD Application은 source가 하나입니다. 그런데 Bitnami 차트처럼 차트 코드와 설정값이 서로 다른 저장소에 있는 경우, 하나의 source로는 양쪽을 동시에 참조할 수 없습니다. ArgoCD의 multi-source 기능이 이 문제를 해결합니다.
sources[0]— Bitnami 서버에서 Redis Helm 차트를 가져옵니다.targetRevision: 24.*는 24.x 범위의 최신 차트 버전을 사용하겠다는 의미입니다.helm.valueFiles에서$values/접두어를 사용하면 아래 Git 소스를 참조합니다.sources[1]— 이 프로젝트의 Git 레포를ref: values로 등록하여, 위에서$values라는 이름으로 접근할 수 있게 합니다.
결과적으로 ArgoCD가 Bitnami 서버에서 차트 템플릿을 다운받고, Git 레포에서 values 파일을 읽어 둘을 합친 뒤, 완성된 Kubernetes YAML을 클러스터에 적용합니다.
배포 흐름
redis-app.yaml과 redis/values.yaml을 커밋/푸시하면, 3편에서 구성한 app-of-apps가 argocd/ 폴더의 변경을 감지하여 새 Application을 생성합니다. Application이 생성되면 Bitnami 서버에서 차트를, Git에서 values 파일을 각각 가져와 렌더링하고, mirunamu 네임스페이스에 Redis 리소스를 자동으로 생성합니다.
클러스터에 생성되는 리소스
| 리소스 | 이름 | 역할 |
|---|---|---|
| StatefulSet | redis-master | 마스터 Pod 관리 |
| StatefulSet | redis-replicas | 레플리카 Pod 관리 |
| Pod | redis-master-0 | Redis 마스터 프로세스 |
| Pod | redis-replicas-0 | Redis 레플리카 프로세스 |
| Service | redis-master | 마스터 접속 주소 |
| Service | redis-headless | StatefulSet용 내부 DNS |
| PVC | redis-data-redis-master-0 | 마스터 데이터 디스크 (Pod 죽어도 유지) |
| PVC | redis-data-redis-replicas-0 | 레플리카 데이터 디스크 |
커밋/푸시 → 배포 확인
git add .
git commit -m "Redis 배포 설정 추가"
git push# Pod 확인
kubectl get pods -n mirunamu -l app.kubernetes.io/name=redis기대 출력:
NAME READY STATUS RESTARTS AGE
redis-master-0 1/1 Running 0 48s
redis-replicas-0 1/1 Running 0 48s
# ArgoCD Application 확인
kubectl get app redis -n argocdNAME SYNC STATUS HEALTH STATUS
redis Synced Healthy
접속 테스트
Pod가 Running 상태가 되었다면, 실제로 Redis가 응답하는지 확인할 차례입니다. 임시 Pod를 띄워서 redis-cli로 ping을 보냅니다.
kubectl run redis-test --rm -it --image=redis:7 -n mirunamu -- \
redis-cli -h redis-master.mirunamu.svc.cluster.local -a 비밀번호 pingPONG이 돌아오면 Redis가 정상적으로 동작하고 있으며, 인증도 통과한 것입니다.
접속 정보
앱에서 Redis에 접속할 때는 Kubernetes 내부 DNS를 사용합니다. Kubernetes는 Service가 생성되면 <서비스명>.<네임스페이스>.svc.cluster.local 형식의 DNS 레코드를 자동으로 만들어줍니다. Bitnami 차트가 redis-master라는 Service를 생성하므로, 클러스터 내부에서는 이 주소가 고정된 접속점이 됩니다.
redis://default:비밀번호@redis-master.mirunamu.svc.cluster.local:6379
이 URL을 앱의 환경변수(REDIS_URL)로 주입하면, 앱 코드에서 별도의 호스트/포트 설정 없이 Redis에 연결할 수 있습니다.
RedisInsight 배포
redis-cli만으로도 Redis를 관리할 수 있지만, 키가 수십 개를 넘어가면 전체 구조를 파악하기 어렵고, 캐시 키의 TTL이나 메모리 사용량을 실시간으로 모니터링하기가 번거롭습니다. RedisInsight는 Redis Labs(현 Redis Inc.)가 제공하는 공식 GUI 도구로, 브라우저에서 키 조회/수정, 메모리 분석, 슬로우 로그 모니터링 등을 할 수 있습니다.
Bitnami가 제공하는 차트가 없으므로, 간단한 Helm 차트를 직접 작성합니다.
차트 구조
values.yaml
image:
repository: redis/redisinsight
tag: latest
pullPolicy: Always
service:
port: 80
targetPort: 5540 # RedisInsight 기본 포트
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256MiArgoCD Application
# argocd/redis-insight-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: redis-insight
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/mirunamu00/helm-chart.git
targetRevision: master
path: mirunamu/redis-insight
destination:
server: https://kubernetes.default.svc
namespace: mirunamu
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=trueRedis Application이 multi-source였던 것과 달리, RedisInsight는 source가 하나입니다. 직접 작성한 차트이므로 Git 레포 하나에서 템플릿과 values를 모두 가져오면 됩니다.
Ingress 라우팅 추가
mirunamu/ingress/values.yaml의 apps에 항목을 추가합니다.
apps:
- host: docs.mirunamu.info
serviceName: docs
servicePort: 80
- host: redis.mirunamu.info
serviceName: redis-insight
servicePort: 80접속 방법
방법 1: 포트포워딩 (DNS/공유기 설정 불필요)
kubectl port-forward svc/redis-insight -n mirunamu 5540:80브라우저에서 http://localhost:5540 접속.
방법 2: 도메인 접속 (DNS + 공유기 포트포워딩 필요)
DNS에 redis.mirunamu.info A 레코드를 추가하고, 브라우저에서 https://redis.mirunamu.info로 접속합니다.
RedisInsight에서 Redis 연결
첫 접속 시 EULA 동의 후 + Connect existing database를 클릭하고, 앞서 사용한 것과 동일한 connection URL을 입력합니다.
redis://default:비밀번호@redis-master.mirunamu.svc.cluster.local:6379
연결되면 Redis에 저장된 모든 키를 트리 구조로 탐색할 수 있고, 개별 키의 값/TTL/메모리 사용량을 실시간으로 확인할 수 있습니다. 다음 편에서 Next.js 캐시 핸들러를 연동한 뒤, 캐시 키가 올바르게 생성되고 정리되는지 검증하는 데 이 도구를 사용합니다.
삭제
Redis를 완전히 제거하려면 ArgoCD Application 삭제와 PVC 정리를 순서대로 진행해야 합니다.
Redis만 삭제
ArgoCD Application을 삭제하면 StatefulSet, Pod, Service 등 관련 리소스가 cascade로 자동 삭제됩니다.
kubectl delete app redis -n argocd다만 PVC(Persistent Volume Claim)는 데이터 보호를 위해 의도적으로 남겨집니다. Kubernetes의 기본 reclaimPolicy가 Retain이기 때문인데, 실수로 앱을 삭제해도 데이터를 복구할 수 있도록 한 안전장치입니다. 완전 삭제가 필요하면 수동으로 제거합니다.
kubectl delete pvc redis-data-redis-master-0 -n mirunamu
kubectl delete pvc redis-data-redis-replicas-0 -n mirunamuRedisInsight만 삭제
kubectl delete app redis-insight -n argocdRedisInsight는 상태를 Redis에 저장하므로 PVC가 없고, Application 삭제만으로 깨끗하게 제거됩니다.
Git에서도 제거
위 명령어는 클러스터에서만 삭제하는 것입니다. Git에 argocd/redis-app.yaml이 남아 있으면 다음 동기화 시 ArgoCD가 다시 생성합니다. 영구적으로 제거하려면 해당 파일을 삭제 후 커밋/푸시하면, app-of-apps의 prune: true 설정에 의해 ArgoCD Application까지 자동 삭제됩니다.
트러블슈팅
정리
4편 요약
- Redis 기초: 메모리 기반 key-value 저장소. 키 이름에 접두어를 붙여서 앱별로 구분합니다
- Bitnami Helm 차트: values 파일만 Git에서 관리하고, 차트 코드는 Bitnami 서버에서 가져옵니다
- replication 구성: 마스터 1개 + 레플리카 1개. Secret으로 비밀번호 관리
- ArgoCD multi-source: Bitnami 차트 + Git values 파일을 결합하여 배포
- RedisInsight: 직접 작성한 Helm 차트로 Redis GUI 모니터링 환경 구축
이것으로 k3s 클러스터에 Redis 인프라가 올라갔습니다. 다음 편에서는 Next.js의 캐시 아키텍처를 이해하고, Redis 캐시 핸들러를 연동합니다.