네임스페이스별로 리소스 사용량을 제한하여 멀티테넌트 환경에서 공정한 자원 분배를 보장합니다. **“한 팀이 모든 리소스를 독점하지 못하게 하는 것”**이 핵심입니다.
🤔 왜 ResourceQuota가 필요한가?
📋 문제 상황 예시
시나리오: 회사에서 쿠버네티스 클러스터 하나를 여러 팀이 공유
- 개발팀 A: 대용량 ML 모델 학습 (CPU 16코어, RAM 64GB 요구)
- 개발팀 B: 웹 애플리케이션 개발 (CPU 2코어, RAM 4GB면 충분)
- 개발팀 C: 마이크로서비스 테스트 (여러 개의 작은 Pod들)
문제: 팀 A가 ML 학습을 시작하면 → 클러스터 리소스 모두 소진 → 팀 B, C 작업 불가
💡 ResourceQuota 동작 원리
🔍 할당량 vs 사용량 개념
실생활 비유
할당량(Hard Limit): 은행 계좌의 “신용카드 한도”
사용량(Used): 현재까지 “사용한 금액”
남은 할당량: “아직 쓸 수 있는 금액”
# 📊 ResourceQuota 상세 설정apiVersion: v1kind: ResourceQuotametadata: name: quota-dev1 namespace: dev1spec: hard: # 1. 객체 개수 제한 pods: "10" # 최대 Pod 10개 persistentvolumeclaims: "2" # 최대 PVC 2개 services: "5" # 최대 Service 5개 secrets: "10" # 최대 Secret 10개 configmaps: "10" # 최대 ConfigMap 10개 # 2. 컴퓨팅 리소스 제한 requests.cpu: "4" # CPU 요청 총합 4코어 requests.memory: "8Gi" # 메모리 요청 총합 8GB limits.cpu: "8" # CPU 제한 총합 8코어 limits.memory: "16Gi" # 메모리 제한 총합 16GB # 3. 스토리지 리소스 제한 requests.storage: "50Gi" # 스토리지 요청 총합 50GB persistentvolumeclaims: "5" # PVC 개수 제한 # 4. 특정 스토리지 클래스 제한 requests.nvidia.com/gpu: "2" # GPU 개수 제한
💻 ResourceQuota 적용 과정 분석
📊 단계별 적용 결과 확인
# 1. 초기 상태 (아무것도 없음)kubectl describe resourcequota quota-dev1 -n dev1
Name: quota-dev1
Namespace: dev1
Resource Used Hard
-------- ---- ----
persistentvolumeclaims 0 2 # PVC: 0개 사용 / 2개 허용
pods 0 10 # Pod: 0개 사용 / 10개 허용
requests.storage 0 2Gi # 스토리지: 0GB 사용 / 2GB 허용
📊 Pod 생성 후 상태 변화
# test-pod 생성 후kubectl describe resourcequota quota-dev1 -n dev1
Name: quota-dev1
Namespace: dev1
Resource Used Hard
-------- ---- ----
persistentvolumeclaims 0 2 # PVC는 아직 생성 안함
pods 1 10 # Pod 1개 생성됨 (9개 더 가능)
requests.storage 0 2Gi # 스토리지는 아직 사용 안함
📊 PVC 생성 후 상태 변화
# PVC 1개 생성 후 (1Gi 크기)kubectl apply -f quota-1G-pvc1.yamlkubectl describe resourcequota quota-dev1 -n dev1
Name: quota-dev1
Namespace: dev1
Resource Used Hard
-------- ---- ----
persistentvolumeclaims 1 2 # PVC 1개 사용됨 (1개 더 가능)
pods 1 10 # Pod 1개 사용 중
requests.storage 1Gi 2Gi # 스토리지 1GB 사용됨 (1GB 더 가능)
# 모든 네임스페이스의 ResourceQuota 확인kubectl get resourcequota --all-namespaces# 특정 리소스 사용량 감시watch kubectl describe resourcequota quota-dev1 -n dev1# JSON 형태로 상세 정보 확인kubectl get resourcequota quota-dev1 -n dev1 -o json | jq '.status'
🎯 실전에서의 ResourceQuota 설계
🤔 질문: “팀별로 어떻게 할당량을 나눠야 할까?”
📋 할당량 계산 방법
실제 계산 과정
전체 클러스터 리소스: CPU 32코어, RAM 128GB, Storage 1TB
팀별 특성 분석:
개발팀 A (ML): 고사양 필요, 작업 수 적음
개발팀 B (웹): 중간 사양, 여러 환경 필요
개발팀 C (마이크로서비스): 저사양, Pod 수 많음
할당 전략:
# 팀 A (ML팀)requests.cpu: "12" # 전체의 37.5%requests.memory: "48Gi" # 전체의 37.5%pods: "5" # 적은 수의 고사양 Pod# 팀 B (웹팀) requests.cpu: "8" # 전체의 25%requests.memory: "32Gi" # 전체의 25%pods: "15" # 중간 수의 Pod# 팀 C (마이크로서비스팀)requests.cpu: "8" # 전체의 25%requests.memory: "32Gi" # 전체의 25%pods: "50" # 많은 수의 소형 Pod# 시스템 예약남은 12.5% = 시스템 Pod 및 예비 할당량
📊 동적 할당량 조정 스크립트
#!/bin/bash# 📊 사용률 기반 할당량 모니터링NAMESPACE="dev1"QUOTA_NAME="quota-dev1"# 현재 사용률 확인USED_PODS=$(kubectl get resourcequota $QUOTA_NAME -n $NAMESPACE -o jsonpath='{.status.used.pods}')HARD_PODS=$(kubectl get resourcequota $QUOTA_NAME -n $NAMESPACE -o jsonpath='{.status.hard.pods}')USAGE_PERCENT=$((USED_PODS * 100 / HARD_PODS))echo "Pod 사용률: $USAGE_PERCENT% ($USED_PODS/$HARD_PODS)"# 80% 초과 시 알림if [ $USAGE_PERCENT -gt 80 ]; then echo "⚠️ 경고: Pod 할당량이 80%를 초과했습니다!" echo "📊 확장을 검토해주세요."fi
이제 ResourceQuota가 어떻게 작동하는지, 왜 필요한지, 어떻게 설계해야 하는지 명확해졌나요? 💡
Requests:
cpu: 250m # 기본 요청값 자동 적용
memory: 256Mi # 기본 요청값 자동 적용
Limits:
cpu: 500m # 기본 제한값 자동 적용
memory: 512Mi # 기본 제한값 자동 적용
4. NetworkPolicy - 네트워크 보안 🛡️
핵심 목적
NetworkPolicy는 **“Pod 간의 네트워크 통신을 세밀하게 제어”**하는 방화벽 같은 역할을 합니다. **“누가, 어디서, 어떤 Pod에 접근할 수 있는가”**를 정의합니다.
🤔 왜 NetworkPolicy가 필요한가?
📋 보안 위험 시나리오
상황: 마이크로서비스 환경
- 웹 프론트엔드 Pod
- API 서버 Pod
- 데이터베이스 Pod
- 결제 처리 Pod (민감한 정보)
문제: 기본적으로 모든 Pod가 서로 자유롭게 통신 가능
→ 웹 프론트엔드에서 직접 데이터베이스 접근 가능 (보안 취약점)
→ 공격자가 하나의 Pod를 해킹하면 모든 Pod에 접근 가능
# db-pod 입장에서:# "나는 데이터베이스야. 나한테 누가 올 수 있지?"apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: database-policyspec: podSelector: matchLabels: app: database # 나는 database Pod이야 policyTypes: - Ingress # 누가 나한테 올 수 있는지만 제어 ingress: - from: - podSelector: matchLabels: app: api # api-pod만 나한테 올 수 있어! ports: - protocol: TCP port: 3306 # MySQL 포트로만!
이해 포인트!
database-pod는 “받기만” 하는 역할 → Ingress만 설정
api-pod만 허용하고, web-pod는 직접 접근 차단
이게 바로 “계층별 보안”!
📊 NetworkPolicy 구조 분석
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: example-policy namespace: productionspec: # 1. 어떤 Pod에 적용할지 선택 (필수) podSelector: matchLabels: app: database # 2. 어떤 방향의 트래픽을 제어할지 (필수) policyTypes: - Ingress # 들어오는 트래픽 제어 - Egress # 나가는 트래픽 제어 # 3. 허용할 Ingress 규칙 (선택) ingress: - from: # 어디서 오는 트래픽을 허용할지 - podSelector: matchLabels: app: api-server ports: # 어떤 포트를 허용할지 - protocol: TCP port: 5432 # 4. 허용할 Egress 규칙 (선택) egress: - to: # 어디로 가는 트래픽을 허용할지 - namespaceSelector: matchLabels: name: monitoring ports: - protocol: TCP port: 80
# 우리가 적용한 NetworkPolicy 다시보기apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: networkpolicy-deny-allspec: podSelector: matchLabels: role: sensitive # 🎯 핵심! 이 라벨을 가진 Pod만! policyTypes: - Ingress - Egress # 허용 규칙이 없음 = 모든 접근 차단
🏠 집 문단속 비유로 이해하기
우리 동네에 집이 4개 있어요:
sensitive-pod 집 (172.16.0.169) → 🔒 문단속 완료 (NetworkPolicy 적용)
internal-pod 집 (172.16.0.36) → 🚪 문 열려있음 (정책 적용 안됨)
chk-info-pod 집 (172.16.0.249) → 🚪 문 열려있음
netshoot-pod 집 (172.16.0.34) → 🚪 문 열려있음
netshoot-pod가 방문하려고 할 때:
sensitive-pod 집: 🔒 “문이 잠겨있어서 못들어가요!” (차단)
internal-pod 집: 🚪 “문이 열려있어서 들어갈 수 있어요!” (허용)
🧠 핵심 포인트 3가지만 기억하세요!
podSelector: “어떤 집에 문단속을 할까?”
role: sensitive = sensitive-pod만 선택
policyTypes: “어떤 방향을 막을까?”
Ingress = 들어오는 사람 막기
Egress = 나가는 사람 막기
허용 규칙: “누구는 들어올 수 있을까?”
없음 = 아무도 못들어옴 (완전 차단)
🎯 이제 직접 해봅시다!
Q1: 만약 role: internal 라벨을 가진 Pod도 막고 싶다면 어떻게 해야 할까요?
정답 보기
# 방법 1: 새로운 정책 추가apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: block-internal-toospec: podSelector: matchLabels: role: internal # internal-pod도 차단! policyTypes: - Ingress - Egress# 방법 2: 기존 정책 수정 (여러 라벨 선택)spec: podSelector: matchExpressions: - key: role operator: In values: ["sensitive", "internal"]
Q2: 우리 테스트에서 internal-pod가 차단 안된 이유는?
답: internal-pod는 role: internal 라벨을 가지고 있는데, 우리 정책은 role: sensitive만 대상으로 하기 때문!
STEP 2: PodSelector 기반 선택적 허용
화이트리스트 방식
“특정 Pod에서 오는 트래픽만 허용” - 마치 초대장이 있는 사람만 입장 허용하는 것과 같습니다.
# 📊 선택적 허용 정책apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-from-specific-pods namespace: defaultspec: podSelector: matchLabels: role: internal # 보호받을 Pod policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: chk-info # 이 라벨을 가진 Pod에서만 접근 허용 ports: - protocol: TCP port: 80 # HTTP 포트만 허용 egress: - to: - podSelector: matchLabels: app: chk-info # 이 라벨을 가진 Pod로만 나갈 수 있음 ports: - protocol: TCP port: 80
📊 통신 가능 여부 매트릭스
출발지 Pod
목적지 Pod
결과
이유
netshoot-pod
internal-pod
❌ 차단
netshoot-pod에 app: chk-info 라벨 없음
chk-info-pod
internal-pod
✅ 허용
chk-info-pod가 화이트리스트에 포함
internal-pod
chk-info-pod
✅ 허용
egress 규칙에 명시됨
internal-pod
external-service
❌ 차단
egress 규칙에 없음
STEP 3: IP Block 기반 제어
실제 시나리오
“내부 네트워크(172.16.0.0/16)에서만 접근 허용하고, 특정 IP 대역(172.16.6.0/24)은 제외”
# 📊 IP 기반 접근 제어apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-internal-network namespace: defaultspec: podSelector: {} # 모든 Pod에 적용 policyTypes: - Ingress - Egress ingress: - from: - ipBlock: cidr: 172.16.0.0/16 # 내부 네트워크 허용 except: - 172.16.6.0/24 # 특정 대역 제외 ports: - protocol: TCP port: 80 egress: - to: - ipBlock: cidr: 172.16.0.0/16 # 내부로만 나가기 허용 ports: - protocol: TCP port: 80 - to: {} # DNS 해석을 위해 모든 UDP 허용 ports: - protocol: UDP port: 53
🔍 IP Block 정책 해석
접근 시도
IP 주소
결과
이유
Pod → Pod
172.16.0.100
✅ 허용
내부 네트워크 범위
Pod → Pod
172.16.6.50
❌ 차단
except 범위에 포함
Pod → 외부
8.8.8.8
❌ 차단
내부 네트워크 범위 밖
Pod → DNS
172.16.0.10:53
✅ 허용
DNS용 UDP 허용
STEP 4: Namespace 간 통신 제어
네임스페이스 격리
“dev2 네임스페이스의 Pod들만 서로 통신 가능, 다른 네임스페이스와는 격리”
# 📊 네임스페이스 격리 정책apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: isolate-namespace namespace: dev2spec: podSelector: {} # dev2 네임스페이스의 모든 Pod policyTypes: - Ingress - Egress ingress: - from: - namespaceSelector: # 같은 네임스페이스만 허용 matchLabels: kubernetes.io/metadata.name: dev2 egress: - to: - namespaceSelector: # 같은 네임스페이스로만 허용 matchLabels: kubernetes.io/metadata.name: dev2 - to: {} # 외부 서비스 호출 허용 ports: - protocol: TCP port: 443 # HTTPS - protocol: UDP port: 53 # DNS
🔧 NetworkPolicy 디버깅 방법
📊 문제 해결 단계
# 1. NetworkPolicy 확인kubectl get networkpolicy -Akubectl describe networkpolicy deny-all-traffic# 2. Pod 라벨 확인kubectl get pods --show-labels# 3. 실시간 연결 테스트kubectl exec -it netshoot-pod -- bash# Pod 내부에서:curl -v --connect-timeout 10 http://target-pod-ipping target-pod-ipnslookup target-service# 4. 네트워크 정책 적용 확인kubectl logs -n kube-system -l app=cilium # Cilium CNI 사용 시
🚨 자주 발생하는 문제들
문제
증상
해결 방법
DNS 해석 실패
nslookup 안됨
egress에 UDP 53포트 허용 추가
예상과 다른 차단
허용되어야 할 통신 차단
Pod 라벨과 selector 일치 확인
정책 적용 안됨
모든 통신이 계속 허용됨
CNI가 NetworkPolicy 지원하는지 확인
부분적 차단
일부 연결만 차단됨
ingress/egress 규칙 모두 확인
🎯 실전 NetworkPolicy 설계 패턴
Pattern 1: 계층별 보안 (3-Tier Architecture)
# 📊 웹 계층 → API 계층만 허용apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: api-layer-policyspec: podSelector: matchLabels: tier: api ingress: - from: - podSelector: matchLabels: tier: web ports: - protocol: TCP port: 8080---# 📊 API 계층 → DB 계층만 허용 apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: database-layer-policyspec: podSelector: matchLabels: tier: database ingress: - from: - podSelector: matchLabels: tier: api ports: - protocol: TCP port: 5432
Pattern 2: 환경별 격리 (개발/스테이징/프로덕션)
# 📊 프로덕션 환경 완전 격리apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: production-isolation namespace: productionspec: podSelector: {} policyTypes: - Ingress - Egress ingress: - from: - namespaceSelector: matchLabels: env: production egress: - to: - namespaceSelector: matchLabels: env: production
🚨 실무에서의 NetworkPolicy 관리 - 복잡도 해결하기
현실적 문제
“Pod가 수십개, 수백개 되면 어떻게 관리하지? 뭘 놓치고 있는지도 모르겠어…”
이런 고민이 정말 현실적이고 중요합니다! 🎯
🔍 실무에서 사용하는 해결책들
1. 라벨링 전략 - 체계적 분류
회사에서 실제 사용하는 라벨 체계
# 🏷️ 표준 라벨링 규칙metadata: labels: # 계층 구분 tier: "web|api|database|cache" # 환경 구분 env: "dev|staging|prod" # 팀 구분 team: "frontend|backend|devops|ml" # 보안 등급 security-level: "public|internal|confidential|restricted" # 애플리케이션 app: "user-service|order-service|payment-service"
2. 네트워크 정책 템플릿화
# 📋 Template 1: 기본 계층별 보안apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: tier-based-policy namespace: productionspec: podSelector: matchLabels: tier: database policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: tier: api # API 계층에서만 DB 접근 가능 ports: - protocol: TCP port: 3306---# 📋 Template 2: 환경별 격리apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: env-isolation namespace: stagingspec: podSelector: {} policyTypes: - Ingress - Egress ingress: - from: - namespaceSelector: matchLabels: env: staging # 같은 환경끼리만 egress: - to: - namespaceSelector: matchLabels: env: staging
3. NetworkPolicy 시각화 도구
# 🔍 실무에서 사용하는 검증 도구들# 1. NetworkPolicy 현황 파악kubectl get networkpolicy --all-namespaces -o wide# 2. Pod 라벨 한눈에 보기 kubectl get pods --all-namespaces --show-labels | grep -E "(tier|env|team)"# 3. 네트워크 연결 테스트 자동화#!/bin/bash# network-test.shPODS=$(kubectl get pods -o name)for pod in $PODS; do echo "Testing connectivity from $pod" kubectl exec $pod -- timeout 5 nc -zv target-ip 80 || echo "BLOCKED"done
# 1. 일단 모든 네임스페이스에 기본 규칙만 적용kubectl apply -f base-security-policies.yaml
# base-security-policies.yaml# 🚨 최소한의 보안 - DNS만 허용apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-dns-onlyspec: podSelector: {} policyTypes: - Egress egress: - to: [] ports: - protocol: UDP port: 53 # DNS만 허용
Phase 2: 점진적 세분화
# 높은 위험도부터 세분화# 1. 데이터베이스 먼저# 2. 결제 시스템 # 3. 사용자 인증# 4. 일반 API
Phase 3: 모니터링 & 검증
# 🔍 정기적 검증 스크립트#!/bin/bashecho "=== NetworkPolicy 검증 레포트 ==="echo "1. 보호되지 않은 데이터베이스 Pod:"kubectl get pods -l tier=database --all-namespaces -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | while read ns name; do if ! kubectl get networkpolicy -n $ns | grep -q $name; then echo "⚠️ $ns/$name - 정책 없음!" fidoneecho "2. 외부 접근 가능한 Pod:"# 외부 IP로 접근 가능한 Pod 검사 로직
# 📋 NetworkPolicy 배포 전 체크리스트- [ ] DNS 해석이 가능한가? (UDP 53 허용)- [ ] 모니터링 시스템 접근 가능한가?- [ ] Health check 엔드포인트 접근 가능한가?- [ ] 로그 수집 시스템 접근 가능한가?- [ ] 필수 외부 API 호출 가능한가?# 🧪 테스트 스크립트kubectl exec test-pod -- nslookup google.com # DNS 체크kubectl exec test-pod -- curl health-check-url # Health 체크 kubectl exec test-pod -- wget monitoring-url # 모니터링 체크
3. 응급 상황 대응
# 🚨 네트워크 정책으로 인한 장애 시 응급 대응# 1. 특정 정책 즉시 비활성화kubectl patch networkpolicy problematic-policy -p '{"spec":{"podSelector":{"matchLabels":{"disabled":"true"}}}}'# 2. 전체 네임스페이스 정책 임시 해제kubectl get networkpolicy -n problem-namespace -o name | xargs kubectl delete# 3. 긴급 허용 정책 적용kubectl apply -f emergency-allow-all.yaml
🎯 실무 권장 사항
큰 조직에서 실제 사용하는 방법
1. 조직별 책임 분담
플랫폼팀: 기본 정책 템플릿 제공
보안팀: 보안 요구사항 정의
개발팀: 애플리케이션별 세부 정책
2. 도구 활용
Helm: 정책 템플릿 배포
ArgoCD: GitOps로 정책 관리
OPA Gatekeeper: 정책 준수 강제
Cilium: 고급 네트워크 정책
3. 단계적 적용
먼저 관찰 모드로 시작
점진적으로 엄격하게 변경
충분한 모니터링과 알림 설정
결론: NetworkPolicy는 혼자 관리하는게 아니라, 도구와 프로세스로 체계적으로 관리하는 것! 🎯
복잡하다고 포기하지 마시고, 작은 것부터 체계적으로 시작하는게 핵심입니다! 😊
🎯 실전 예시
💡 멀티테넌트 환경 보안 설정
🤔 질문: “개발팀별로 리소스를 분리하고 보안을 적용하려면?”
📋 구체적인 시나리오
실제 상황
문제: dev1팀과 dev2팀이 같은 클러스터를 사용하는데 서로의 리소스에 접근 가능
요구사항: 팀별 격리, 리소스 할당량 제한, 네트워크 격리
해결방법: RBAC + ResourceQuota + NetworkPolicy 조합
결과: 안전하고 공정한 멀티테넌트 환경 구축
💻 통합 보안 설정
# 1. RBAC 설정kubectl apply -f ns-sa-dev-both.yamlkubectl apply -f dev1/role-get-dev1.yamlkubectl apply -f dev1/rolebinding-dev1.yaml# 2. 리소스 할당량 설정kubectl apply -f ResourceQuota.yaml# 3. 리소스 제한 정책 설정kubectl apply -f LimitRange.yaml# 4. 네트워크 보안 정책 설정kubectl apply -f 1-2-NetworkPolicy-deny-all.yaml# 검증kubectl get resourcequota,limitrange,networkpolicy -n dev1