On-premise Kubernetes로 iEvent 서비스 전체 구조 — 4개 서비스를 1개 클러스터에서 운영하기

전체 아키텍처

Internet
  → Nginx Ingress (cert-manager Let's Encrypt TLS)
  → [FastAPI Backend] [React Admin] [Scheduler] [MinIO]
  → MySQL (StatefulSet)
  → Redis (Deployment)
  → MinIO (StatefulSet, PVC)

Namespace 분리

# 프로덕션과 스테이징을 같은 클러스터에서 분리
kubectl create namespace ivent-prod
kubectl create namespace ivent-staging

# 프로덕션 배포
kubectl apply -f k8s/ -n ivent-prod

서비스별 Deployment 구성

# Backend API — replica 2 (수평 확장)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ivent-backend
  namespace: ivent-prod
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ivent-backend
  template:
    metadata:
      labels:
        app: ivent-backend
    spec:
      containers:
      - name: backend
        image: registry.ivent.local/ivent-backend:latest
        ports:
        - containerPort: 8000
        envFrom:
        - configMapRef:
            name: ivent-config
        - secretRef:
            name: ivent-secrets
        resources:
          requests:
            cpu: "100m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        readinessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 10
          periodSeconds: 5

Service 노출

# ClusterIP로 내부 통신, Ingress로만 외부 노출
apiVersion: v1
kind: Service
metadata:
  name: ivent-backend
spec:
  type: ClusterIP
  selector:
    app: ivent-backend
  ports:
  - port: 8000
    targetPort: 8000

Ingress 라우팅

# api.ivent.com → backend:8000
# admin.ivent.com → react-admin:80
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ivent-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.ivent.com
    - admin.ivent.com
    secretName: ivent-tls
  rules:
  - host: api.ivent.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ivent-backend
            port:
              number: 8000
  - host: admin.ivent.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ivent-admin
            port:
              number: 80

MySQL StatefulSet

# 데이터 영속성을 위해 PVC 사용
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ivent-mysql
spec:
  replicas: 1
  serviceName: ivent-mysql
  template:
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: ivent-secrets
              key: mysql-root-password
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: mysql-data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 20Gi

교훈

On-premise K8s의 핵심은 StatefulSet으로 DB/MinIO 데이터를 PVC에 안전하게 보관하고, Scheduler는 replica=1 Deployment로 실행하는 것입니다. 내부 서비스는 ClusterIP만 사용하고 Ingress 하나로만 외부에 노출하면 보안 관리가 단순해집니다.