전체 아키텍처
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 하나로만 외부에 노출하면 보안 관리가 단순해집니다.