# EN: Redis HA with Sentinel — replaces single-instance redis.yaml (DEVOPS-W-04)
# VI: Redis HA voi Sentinel — thay the redis.yaml don le (DEVOPS-W-04)
#
# Architecture:
#   - redis-master:  1 pod StatefulSet (read/write)
#   - redis-replica: 2 pod StatefulSet (read-only replicas)
#   - redis-sentinel: 3 pod StatefulSet (monitors master, auto-failover)
#
# EN: Apply this file AND remove (or stop applying) redis.yaml to avoid conflicts.
# VI: Apply file nay VA xoa (hoac ngung apply) redis.yaml de tranh conflict.

# =============================================================================
# ConfigMap — Sentinel configuration template
# =============================================================================
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-sentinel-config
  namespace: staging
  labels:
    app: redis-sentinel
    environment: staging
    platform: goodgo
data:
  sentinel.conf: |
    sentinel resolve-hostnames yes
    sentinel announce-hostnames yes
    sentinel monitor goodgo-master redis-master-0.redis-master.staging.svc.cluster.local 6379 2
    sentinel auth-pass goodgo-master $(REDIS_PASSWORD)
    sentinel down-after-milliseconds goodgo-master 5000
    sentinel failover-timeout goodgo-master 60000
    sentinel parallel-syncs goodgo-master 1
  replica.conf: |
    replicaof redis-master-0.redis-master.staging.svc.cluster.local 6379
    masterauth $(REDIS_PASSWORD)
    requirepass $(REDIS_PASSWORD)
    maxmemory 256mb
    maxmemory-policy allkeys-lru
    appendonly yes

---
# =============================================================================
# StatefulSet — Redis Master (1 replica)
# =============================================================================
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-master
  namespace: staging
  labels:
    app: redis-master
    role: master
    environment: staging
    platform: goodgo
    tier: infrastructure
spec:
  serviceName: redis-master
  replicas: 1
  selector:
    matchLabels:
      app: redis-master
      role: master
  template:
    metadata:
      labels:
        app: redis-master
        role: master
        environment: staging
    spec:
      containers:
      - name: redis
        image: redis:7-alpine
        command:
        - redis-server
        - "--requirepass"
        - "$(REDIS_PASSWORD)"
        - "--maxmemory"
        - "256mb"
        - "--maxmemory-policy"
        - "allkeys-lru"
        - "--appendonly"
        - "yes"
        ports:
        - containerPort: 6379
          protocol: TCP
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: goodgo-secrets
              key: Redis__Password
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "250m"
        livenessProbe:
          exec:
            command:
            - sh
            - -c
            - redis-cli -a "$REDIS_PASSWORD" ping
          initialDelaySeconds: 10
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          exec:
            command:
            - sh
            - -c
            - redis-cli -a "$REDIS_PASSWORD" ping
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
        volumeMounts:
        - name: redis-master-data
          mountPath: /data
  volumeClaimTemplates:
  - metadata:
      name: redis-master-data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

---
# Service — Redis Master (headless for StatefulSet DNS)
apiVersion: v1
kind: Service
metadata:
  name: redis-master
  namespace: staging
  labels:
    app: redis-master
    role: master
    environment: staging
spec:
  clusterIP: None
  selector:
    app: redis-master
    role: master
  ports:
  - name: redis
    port: 6379
    targetPort: 6379

---
# Service — Redis write endpoint (used by apps)
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: staging
  labels:
    app: redis-master
    role: master
    environment: staging
spec:
  selector:
    app: redis-master
    role: master
  ports:
  - name: redis
    port: 6379
    targetPort: 6379
  type: ClusterIP

---
# =============================================================================
# StatefulSet — Redis Replicas (2 replicas for HA)
# =============================================================================
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-replica
  namespace: staging
  labels:
    app: redis-replica
    role: replica
    environment: staging
    platform: goodgo
    tier: infrastructure
spec:
  serviceName: redis-replica
  replicas: 2
  selector:
    matchLabels:
      app: redis-replica
      role: replica
  template:
    metadata:
      labels:
        app: redis-replica
        role: replica
        environment: staging
    spec:
      initContainers:
      - name: init-replica-conf
        image: busybox:1.36
        command:
        - sh
        - -c
        - |
          sed "s/\$(REDIS_PASSWORD)/$REDIS_PASSWORD/g" /config/replica.conf > /data/redis.conf
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: goodgo-secrets
              key: Redis__Password
        volumeMounts:
        - name: redis-config
          mountPath: /config
        - name: redis-replica-data
          mountPath: /data
      containers:
      - name: redis
        image: redis:7-alpine
        command:
        - redis-server
        - /data/redis.conf
        ports:
        - containerPort: 6379
          protocol: TCP
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: goodgo-secrets
              key: Redis__Password
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "250m"
        livenessProbe:
          exec:
            command:
            - sh
            - -c
            - redis-cli -a "$REDIS_PASSWORD" ping
          initialDelaySeconds: 15
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          exec:
            command:
            - sh
            - -c
            - redis-cli -a "$REDIS_PASSWORD" ping
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
        volumeMounts:
        - name: redis-replica-data
          mountPath: /data
      volumes:
      - name: redis-config
        configMap:
          name: redis-sentinel-config
  volumeClaimTemplates:
  - metadata:
      name: redis-replica-data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

---
# Service — Redis Replicas (headless)
apiVersion: v1
kind: Service
metadata:
  name: redis-replica
  namespace: staging
  labels:
    app: redis-replica
    role: replica
    environment: staging
spec:
  clusterIP: None
  selector:
    app: redis-replica
    role: replica
  ports:
  - name: redis
    port: 6379
    targetPort: 6379

---
# =============================================================================
# StatefulSet — Redis Sentinel (3 nodes — quorum = 2)
# =============================================================================
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-sentinel
  namespace: staging
  labels:
    app: redis-sentinel
    role: sentinel
    environment: staging
    platform: goodgo
    tier: infrastructure
spec:
  serviceName: redis-sentinel
  replicas: 3
  selector:
    matchLabels:
      app: redis-sentinel
      role: sentinel
  template:
    metadata:
      labels:
        app: redis-sentinel
        role: sentinel
        environment: staging
    spec:
      initContainers:
      - name: init-sentinel-conf
        image: busybox:1.36
        command:
        - sh
        - -c
        - |
          sed "s/\$(REDIS_PASSWORD)/$REDIS_PASSWORD/g" /config/sentinel.conf > /data/sentinel.conf
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: goodgo-secrets
              key: Redis__Password
        volumeMounts:
        - name: sentinel-config
          mountPath: /config
        - name: sentinel-data
          mountPath: /data
      containers:
      - name: sentinel
        image: redis:7-alpine
        command:
        - redis-sentinel
        - /data/sentinel.conf
        ports:
        - containerPort: 26379
          protocol: TCP
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: goodgo-secrets
              key: Redis__Password
        resources:
          requests:
            memory: "64Mi"
            cpu: "50m"
          limits:
            memory: "128Mi"
            cpu: "100m"
        livenessProbe:
          exec:
            command:
            - redis-cli
            - -p
            - "26379"
            - ping
          initialDelaySeconds: 15
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        readinessProbe:
          exec:
            command:
            - redis-cli
            - -p
            - "26379"
            - ping
          initialDelaySeconds: 10
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
        volumeMounts:
        - name: sentinel-data
          mountPath: /data
      volumes:
      - name: sentinel-config
        configMap:
          name: redis-sentinel-config
  volumeClaimTemplates:
  - metadata:
      name: sentinel-data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 100Mi

---
# Service — Redis Sentinel (headless + ClusterIP)
apiVersion: v1
kind: Service
metadata:
  name: redis-sentinel
  namespace: staging
  labels:
    app: redis-sentinel
    role: sentinel
    environment: staging
spec:
  selector:
    app: redis-sentinel
    role: sentinel
  ports:
  - name: sentinel
    port: 26379
    targetPort: 26379
  type: ClusterIP
