Kubernetes Basics
분류: Layer 5 - 플랫폼 엔지니어링 & 자동화 | 선수지식: Docker Basics, ECS vs EC2
1. 한 줄 정의
섹션 제목: “1. 한 줄 정의”Kubernetes(K8s)는 컨테이너화된 애플리케이션의 배포, 스케일링, 관리를 자동화하는 오픈소스 오케스트레이션 플랫폼이다.
2. 왜 중요한가
섹션 제목: “2. 왜 중요한가”2026년 CNCF 조사에 따르면 컨테이너를 사용하는 조직의 82%가 프로덕션에서 Kubernetes를 운영한다. ECS는 AWS 전용이지만 Kubernetes는 클라우드 중립적이어서 어디서든 동일하게 동작한다. 플랫폼 엔지니어에게 Kubernetes는 “클라우드 네이티브의 공용어(lingua franca)“로, 이것을 모르면 플랫폼 엔지니어링 도구 생태계(ArgoCD, Helm, Crossplane 등)를 이해할 수 없다.
3. 핵심 개념
섹션 제목: “3. 핵심 개념”아키텍처
Control Plane (마스터)├── API Server ← 모든 요청의 진입점├── Scheduler ← Pod를 어떤 Node에 배치할지 결정├── Controller Manager ← 원하는 상태(desired state)를 유지└── etcd ← 클러스터 상태 저장소 (key-value)
Worker Nodes├── kubelet ← 노드에서 Pod를 실행/관리├── kube-proxy ← 네트워크 라우팅└── Container Runtime (containerd 등)Control Plane 내부 동작 원리 — 왜 이렇게 설계되었나
Kubernetes의 가장 중요한 설계 원칙은 **“모든 컴포넌트가 API Server를 통해서만 통신한다”**는 것이다. Scheduler가 kubelet에게 직접 명령하지 않고, Controller Manager가 etcd에 직접 쓰지 않는다. 모든 것이 API Server를 거친다.
비유: API Server는 은행의 창구 직원이다. etcd는 금고, Scheduler와 Controller는 내부 업무 부서다. 모든 외부 요청은 창구(API Server)를 통해서만 처리된다. 이 구조 덕분에 각 컴포넌트가 독립적으로 동작하고, 하나가 재시작되어도 전체 시스템이 멈추지 않는다.
# kubectl apply -f deployment.yaml 실행 시 내부 흐름1. kubectl → API Server (HTTP 요청)2. API Server → etcd에 "Deployment 생성" 기록3. Deployment Controller (Controller Manager 안에 있음) etcd 변경 감지4. Controller → API Server에 "Pod 3개 만들어줘" 요청5. API Server → etcd에 "Pod 3개 생성 예정" 기록6. Scheduler → 새 Pod가 생겼지만 Node가 없음을 감지7. Scheduler → 리소스 여유 있는 Node 선택 → API Server에 "이 Node에 배치해줘" 요청8. API Server → etcd 업데이트9. 해당 Node의 kubelet이 etcd 변경 감지 → 실제로 컨테이너 실행📖 더 보기: Kubernetes Components 공식 문서 — API Server, etcd, Scheduler, Controller Manager 각 역할을 다이어그램으로 설명
Scheduler 내부 동작 — Pod는 어떻게 Node에 배치되나
Scheduler는 단순히 “빈 Node에 넣는다”가 아니다. 두 단계로 나눠서 최적의 Node를 선택한다:
1단계 — Filtering (거르기): 배치할 수 없는 Node를 먼저 제거한다.
- CPU/메모리 요청량이 Node 가용 자원보다 큰 경우 제외
- Pod의 NodeSelector나 Affinity 조건을 만족하지 않는 Node 제외
- Taint/Toleration 규칙을 만족하지 않는 Node 제외
2단계 — Scoring (점수 매기기): 남은 Node 중에서 최고 점수 Node를 선택한다.
- 리소스 분산도 (이미 많이 사용 중인 Node보다 여유 있는 Node 선호)
- 이미 같은 이미지가 있는 Node (이미지 Pull 시간 절약)
- 데이터 지역성, Zone 분산 등 다양한 기준
# Scheduler 선택 과정 예시Node 목록: node-1 (CPU 80%), node-2 (CPU 30%), node-3 (CPU 50%)→ Filtering: 모두 요청 가능 (nestjs-api가 250m CPU 요청)→ Scoring: node-2(높은 점수) > node-3 > node-1→ 결정: node-2에 Pod 배치📖 더 보기: Kubernetes Scheduler 공식 문서 — Filtering/Scoring 플러그인 목록과 커스텀 스케줄러 구성 방법
핵심 오브젝트
| 오브젝트 | 역할 | ECS 대응 개념 |
|---|---|---|
| Pod | 컨테이너 실행 최소 단위 (1개 이상의 컨테이너) | Task |
| Deployment | Pod의 원하는 개수를 유지, 롤링 업데이트 관리 | Service |
| Service | Pod에 안정적인 네트워크 접점 제공 (ClusterIP, LoadBalancer) | ALB + Target Group |
| Ingress | 외부 HTTP 트래픽을 Service로 라우팅 (경로 기반) | ALB Listener Rules |
| ConfigMap | 설정값을 코드와 분리해서 주입 | Task Definition 환경변수 |
| Secret | 민감 정보(비밀번호, API Key) 관리 | Secrets Manager |
| Namespace | 리소스를 논리적으로 격리 (dev/staging/prod) | ECS Cluster |
Service 네트워킹과 DNS — Pod는 서로를 어떻게 찾는가
Kubernetes에서 Pod의 IP는 언제든 바뀔 수 있다(재시작, 스케일링 등). 그래서 Pod끼리 직접 IP로 통신하면 안 된다. Service가 안정적인 네트워크 접점(ClusterIP)을 제공하고, CoreDNS가 Service 이름을 IP로 변환한다.
비유: Service는 “대표 전화번호”이고 CoreDNS는 “전화번호부”이다. 직원(Pod)이 바뀌어도 대표 전화번호는 유지되고, 전화번호부에서 부서명(Service 이름)만 찾으면 연결된다.
내부 동작 흐름:
- Pod가 생성되면 Kubernetes는 자동으로
/etc/resolv.conf파일을 주입한다 - 이 파일에는 CoreDNS의 ClusterIP(보통
10.96.0.10)가 nameserver로 설정되어 있다 - Pod에서
nestjs-api라는 Service 이름으로 요청하면 CoreDNS가nestjs-api.<namespace>.svc.cluster.local로 확장해서 ClusterIP를 반환한다 - kube-proxy가 ClusterIP로 들어온 트래픽을 실제 Pod IP로 라우팅한다(iptables 또는 IPVS 규칙 기반)
# Pod 내부에서 DNS 해석 과정$ kubectl exec -it nestjs-api-xxx -- cat /etc/resolv.confnameserver 10.96.0.10search default.svc.cluster.local svc.cluster.local cluster.localoptions ndots:5
# Service 이름으로 다른 Pod 접근 (같은 Namespace)$ kubectl exec -it nestjs-api-xxx -- curl http://redis-cache:6379# → CoreDNS가 redis-cache.default.svc.cluster.local 로 해석
# 다른 Namespace의 Service 접근$ kubectl exec -it nestjs-api-xxx -- curl http://postgres.database.svc.cluster.local:5432# → database 네임스페이스의 postgres Service로 접근# Service 정의 예시 — Nest.js API에 ClusterIP 부여apiVersion: v1kind: Servicemetadata: name: nestjs-apispec: selector: app: nestjs-api # 이 라벨을 가진 Pod에 트래픽 전달 ports: - port: 80 # Service가 받는 포트 targetPort: 3000 # Pod의 실제 포트 type: ClusterIP # 클러스터 내부에서만 접근 가능---# 외부 노출이 필요하면 LoadBalancer 타입 사용apiVersion: v1kind: Servicemetadata: name: nestjs-api-externalspec: selector: app: nestjs-api ports: - port: 80 targetPort: 3000 type: LoadBalancer # AWS에서 NLB/CLB 자동 생성📖 더 보기: Kubernetes DNS for Services and Pods 공식 문서 — Service DNS 이름 규칙, Pod DNS 설정, headless Service의 DNS 동작을 상세 설명
선언적(Declarative) 관리 — “원하는 상태”를 선언하면 Kubernetes가 맞춰준다
Kubernetes의 핵심 철학: “지금 이렇게 해라”(명령)가 아니라 “이 상태가 되어라”(선언). Pod 3개가 필요하다고 선언하면, 1개가 죽어도 Kubernetes가 새로 만들어 3개를 유지한다.
# 예: Nest.js 서비스를 3개 복제본으로 배포apiVersion: apps/v1kind: Deploymentmetadata: name: nestjs-apispec: replicas: 3 # 항상 3개 Pod 유지 selector: matchLabels: app: nestjs-api template: metadata: labels: app: nestjs-api spec: containers: - name: api image: my-ecr/nestjs-api:latest ports: - containerPort: 3000 resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m"# kubectl apply 후 상태 확인 예상 출력$ kubectl apply -f nestjs-api-deployment.yamldeployment.apps/nestjs-api created
$ kubectl get pods -l app=nestjs-apiNAME READY STATUS RESTARTS AGEnestjs-api-7d9f4b8c4-2xkpq 1/1 Running 0 23snestjs-api-7d9f4b8c4-8qwtm 1/1 Running 0 23snestjs-api-7d9f4b8c4-vn4rp 1/1 Running 0 23s선언적 관리의 크로스 도메인 전이 — Reconciliation Loop는 K8s만의 개념이 아니다
K8s의 Reconciliation Loop(현재 상태 → 원하는 상태로 지속 수렴)는 인프라 엔지니어링 전반에 걸쳐 같은 패턴으로 나타난다. 패턴을 도메인 밖에서도 인식하면 새로운 도구를 빠르게 이해할 수 있다.
| 도메인 | 원하는 상태 선언 | Reconciliation 주체 | Drift 발생 시 |
|---|---|---|---|
| Kubernetes | Deployment.spec.replicas: 3 | Controller Manager | Pod 자동 재생성 |
| Terraform | resource "aws_instance" ... | terraform apply (plan→apply 루프) | terraform plan으로 drift 감지 |
| GitOps (ArgoCD) | Git 저장소의 YAML 상태 | ArgoCD Application Controller | 클러스터를 Git 상태로 자동 동기화 |
| SQL 스키마 | CREATE TABLE / ALTER TABLE DDL | DB 마이그레이션 도구(Flyway, Liquibase) | 스키마 버전 불일치 시 마이그레이션 재실행 |
핵심 공통 구조: 선언(What) → 감지(현재 vs 원하는 상태 비교) → 수렴(조정 액션).
이 패턴을 이해하면 Crossplane(K8s로 AWS 인프라 선언적 관리), AWS Config Rules(인프라 컴플라이언스 자동 수렴), Ansible(멱등 실행)도 같은 사고 모델로 읽힌다.
📖 참고: Kubernetes Reconciliation Patterns, GitOps를 Terraform으로 확장 - Weaveworks
자가 치유(Self-Healing)
Pod가 죽으면 Deployment Controller가 자동으로 새 Pod를 생성한다. ECS Service의 “desired count 유지” 동작과 같은 원리. Controller Manager 안의 ReplicaSet Controller가 etcd를 지속적으로 감시하다가 현재 Pod 수가 desired 수와 다르면 즉시 조정한다.
# Pod 강제 삭제 후 자동 재생성 확인$ kubectl delete pod nestjs-api-7d9f4b8c4-2xkpqpod "nestjs-api-7d9f4b8c4-2xkpq" deleted
$ kubectl get pods -l app=nestjs-apiNAME READY STATUS RESTARTS AGEnestjs-api-7d9f4b8c4-8qwtm 1/1 Running 0 2mnestjs-api-7d9f4b8c4-vn4rp 1/1 Running 0 2mnestjs-api-7d9f4b8c4-k9nzx 0/1 ContainerCreating 0 2s ← 새로 생성됨HPA (Horizontal Pod Autoscaler) — 트래픽에 따라 자동 스케일링
HPA는 CPU나 메모리 사용률을 보고 Pod 수를 자동으로 늘리거나 줄인다. ECS의 Auto Scaling과 같은 개념이다.
비유: HPA는 “직원 수 자동 조절 시스템”이다. 주문이 몰리면 직원을 더 뽑고, 한산하면 줄인다. CPU 50%를 기준으로 Pod를 최소 2개에서 최대 10개까지 조절하는 예시:
# HPA 설정 예시 — Nest.js API 자동 스케일링apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: nestjs-api-hpaspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nestjs-api minReplicas: 2 # 최소 2개 유지 maxReplicas: 10 # 최대 10개까지 확장 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 # CPU 50% 초과 시 스케일 업# HPA 상태 확인 예상 출력$ kubectl get hpa nestjs-api-hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEnestjs-api-hpa Deployment/nestjs-api 23%/50% 2 10 2 5m
# 부하가 몰릴 때$ kubectl get hpa nestjs-api-hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEnestjs-api-hpa Deployment/nestjs-api 78%/50% 2 10 4 8m# → CPU 78%로 50% 초과 → 자동으로 4개로 스케일 업HPA가 동작하려면 클러스터에 metrics-server가 설치되어 있어야 한다. AWS EKS에서는 기본 설치되어 있지 않으므로 kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml로 설치해야 한다.
📖 더 보기: Amazon EKS HPA 공식 문서 — EKS에서 metrics-server 설치부터 HPA 설정까지 단계별 가이드
KEDA — 이벤트 기반 Pod 자동 스케일링 (HPA 확장)
HPA는 CPU/메모리만 기준으로 스케일링하지만, 실제 서비스에서는 “SQS 큐에 메시지가 쌓였을 때”, “Kafka 토픽 lag이 커질 때” 같은 외부 이벤트를 기준으로 스케일링해야 하는 경우가 많다. KEDA(Kubernetes Event-driven Autoscaler)가 이 역할을 한다.
비유: HPA가 “직원이 바쁠 때 사람을 추가 고용”이라면, KEDA는 “주문이 밀릴 때 사람을 추가 고용”이다. 주문량(외부 이벤트)을 보고 결정하는 것이 더 정확하다.
KEDA는 50개 이상의 내장 스케일러를 제공한다: AWS SQS, Kafka, Redis, RabbitMQ, Prometheus 메트릭 등.
# KEDA ScaledObject 예시 — SQS 큐 길이 기반 스케일링apiVersion: keda.sh/v1alpha1kind: ScaledObjectmetadata: name: nestjs-worker-scaledobjectspec: scaleTargetRef: name: nestjs-worker # 스케일링할 Deployment 이름 minReplicaCount: 0 # 큐가 비면 0개로 줄임 (비용 절감) maxReplicaCount: 20 triggers: - type: aws-sqs-queue metadata: queueURL: https://sqs.ap-northeast-2.amazonaws.com/123456789/my-queue queueLength: "5" # 큐 메시지 5개당 Pod 1개 awsRegion: "ap-northeast-2"# KEDA 스케일링 동작 확인$ kubectl get scaledobject nestjs-worker-scaledobjectNAME SCALETARGETKIND SCALETARGETNAME MIN MAX TRIGGERS READY ACTIVEnestjs-worker-scaledobject Deployment nestjs-worker 0 20 aws-sqs-queue True True
# SQS에 50개 메시지 → 자동으로 Pod 10개로 스케일 업$ kubectl get pods -l app=nestjs-workerNAME READY STATUS RESTARTS AGEnestjs-worker-6b8c4d5f7-abcde 1/1 Running 0 30snestjs-worker-6b8c4d5f7-fghij 1/1 Running 0 30s...# → 10개 Pod가 자동 생성됨Karpenter — 노드 자동 프로비저닝 (Cluster Autoscaler의 진화형)
HPA/KEDA가 Pod를 늘렸는데 클러스터에 Node가 부족하면 Pod는 Pending 상태에 멈춘다. 이때 Node를 자동으로 추가하는 것이 Karpenter다.
기존 Cluster Autoscaler와 차이:
- Cluster Autoscaler: 미리 정의한 Node Group 단위로 스케일링. 종류가 제한적
- Karpenter: Pod의 실제 요구사항(CPU, 메모리, ARM/x86 등)을 분석해서 가장 적합하고 저렴한 인스턴스 타입을 즉시 프로비저닝. Spot 인스턴스 활용 극대화
# Karpenter NodePool 예시 — Spot 우선 + On-Demand 폴백apiVersion: karpenter.sh/v1beta1kind: NodePoolmetadata: name: defaultspec: template: spec: requirements: - key: karpenter.sh/capacity-type operator: In values: ["spot", "on-demand"] # Spot 우선 시도 - key: kubernetes.io/arch operator: In values: ["amd64"] - key: karpenter.k8s.aws/instance-category operator: In values: ["c", "m", "r"] # 범용/컴퓨팅/메모리 최적화 인스턴스 limits: cpu: "1000" # 클러스터 전체 CPU 한도 disruption: consolidationPolicy: WhenUnderutilized # 덜 사용되는 노드 자동 정리# Karpenter가 Node를 자동 추가하는 과정$ kubectl get nodesNAME STATUS ROLES AGE VERSIONip-10-0-1-100.ec2 Ready <none> 5d v1.29.0ip-10-0-1-200.ec2 Ready <none> 5d v1.29.0
# Pod가 Pending → Karpenter가 Spot 인스턴스 자동 생성$ kubectl get nodesNAME STATUS ROLES AGE VERSIONip-10-0-1-100.ec2 Ready <none> 5d v1.29.0ip-10-0-1-200.ec2 Ready <none> 5d v1.29.0ip-10-0-2-50.ec2 Ready <none> 45s v1.29.0 ← Karpenter가 추가한 Spot 노드📖 더 보기: KEDA + Karpenter on EKS - AWS Blog — 이벤트 기반 Pod 스케일링과 노드 자동 프로비저닝을 결합해서 비용을 최대 70% 줄이는 실전 가이드
Readiness/Liveness Probe — 프로덕션 필수 설정
프로덕션에서 Probe를 설정하지 않으면 앱이 실제로 준비되지 않았는데도 트래픽을 받거나, 앱이 죽었는데 재시작되지 않는 문제가 생긴다.
- Readiness Probe: “이 Pod가 트래픽을 받을 준비가 됐는가” 확인. 실패하면 Service 엔드포인트에서 제외 (트래픽 차단)
- Liveness Probe: “이 Pod가 살아있는가” 확인. 실패하면 컨테이너 재시작
# Nest.js API에 Probe 설정 예시spec: containers: - name: api image: my-ecr/nestjs-api:latest readinessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 10 # 앱 시작 후 10초 기다렸다가 체크 시작 periodSeconds: 5 # 5초마다 체크 failureThreshold: 3 # 3번 연속 실패 시 트래픽 차단 livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 30 # 시작 후 30초 기다림 (liveness는 더 여유 있게) periodSeconds: 10 failureThreshold: 3 # 3번 연속 실패 시 컨테이너 재시작# Readiness Probe 실패 시 동작 확인$ kubectl describe pod nestjs-api-xxxEvents: Warning Unhealthy 5s kubelet Readiness probe failed: HTTP probe failed with statuscode: 503# → 해당 Pod는 Service 엔드포인트에서 제거됨 (트래픽 수신 안 함)# → 다른 정상 Pod들이 트래픽 처리📖 더 보기: Configure Liveness, Readiness and Startup Probes - Kubernetes 공식 문서 — Probe 종류별 설정 방법, HTTP/TCP/gRPC Probe 차이, Startup Probe가 필요한 경우
⚠️ ECS에서 넘어올 때 주의
ECS의 Task Definition = Kubernetes의 Pod spec + Deployment spec. Kubernetes는 더 세분화되어 있어서 처음에 오브젝트 수가 많아 혼란스러울 수 있다. “ECS의 X는 K8s의 Y”로 매핑하면서 학습하면 효율적이다.
2025년 Kubernetes 주요 변화
Kubernetes 1.33/1.35 신기능
-
StatefulSet MaxUnavailable (Beta): StatefulSet 업데이트 시
maxUnavailable을 설정하면 한 번에 여러 Pod를 병렬 업데이트할 수 있다. 기존에는 하나씩 순서대로 업데이트해서 DB 클러스터 업데이트에 오랜 시간이 걸렸는데, 이 기능으로 최대 60% 빠르게 업데이트 가능# StatefulSet maxUnavailable 예시 (K8s 1.35+)spec:updateStrategy:type: RollingUpdaterollingUpdate:maxUnavailable: 2 # 동시에 최대 2개 Pod 업데이트 허용 (기존: 반드시 1개씩) -
PreferSameNode 트래픽 분산: Service가 트래픽을 라우팅할 때 같은 Node에 있는 엔드포인트를 우선 선택하는 정책. 네트워크 레이턴시를 줄이고 cross-zone 데이터 전송 비용 절감 효과
AWS EKS Capabilities (2025년 11월 GA) — 3가지 핵심 Capability
AWS re:Invent 2025에서 EKS Capabilities가 정식 출시되었다. 단순히 ArgoCD 하나를 관리형으로 제공하는 것을 넘어서, Kubernetes 플랫폼 운영의 핵심 기능을 AWS가 완전 관리형으로 제공하는 체계다.
| Capability | 역할 | 요약 |
|---|---|---|
| ArgoCD Capability | GitOps 기반 앱 배포 | AWS 컨트롤 플레인에서 ArgoCD 실행, 워커 노드 리소스 사용 없음 |
| ACK (AWS Controllers for Kubernetes) | K8s 리소스로 AWS 서비스 관리 | YAML 한 줄로 RDS, SQS, S3 생성 |
| KRO (Kube Resource Orchestrator) | 복잡한 K8s 리소스를 단일 CRD로 추상화 | 개발자가 VPC+EKS+RDS 묶음을 버튼 하나로 생성 |
ACK 예시 — Kubernetes YAML로 RDS 생성:
# ACK를 사용하면 kubectl apply 한 번으로 RDS 인스턴스 생성apiVersion: rds.services.k8s.aws/v1alpha1kind: DBInstancemetadata: name: nestjs-prod-dbspec: dbInstanceIdentifier: nestjs-prod-db dbInstanceClass: db.t3.medium engine: postgres engineVersion: "15.4" masterUsername: admin allocatedStorage: 20# kubectl apply 후 RDS 인스턴스 자동 생성$ kubectl apply -f rds-instance.yamldbinstance.rds.services.k8s.aws/nestjs-prod-db created
$ kubectl get dbinstance nestjs-prod-dbNAME STATUS CLASS ENGINEnestjs-prod-db available db.t3.medium postgres# → AWS 콘솔/Terraform 없이 kubectl만으로 RDS 생성📖 더 보기: AWS EKS Capabilities 발표 - re:Invent 2025 — ArgoCD, ACK, KRO 세 가지 Capability의 아키텍처와 사용 시나리오
NetworkPolicy — Pod 간 트래픽을 코드로 제어하는 방화벽
기본 Kubernetes 클러스터는 모든 Pod가 서로 자유롭게 통신할 수 있다. 프로덕션에서는 “API 서버만 DB에 접근 가능”, “외부에서 직접 DB Pod에 접근 불가” 같은 네트워크 격리가 필수다. NetworkPolicy가 이 역할을 한다.
비유: NetworkPolicy는 “사내 방화벽 규칙서”다. “인사팀 PC는 급여 DB에만 접근 가능”, “개발자 PC는 운영 DB에 접근 불가”처럼 Pod 레벨에서 트래픽을 제어한다.
NetworkPolicy는 CNI(Container Network Interface) 플러그인이 지원해야 동작한다. EKS에서는 AWS VPC CNI + Network Policy 기능(2023년 GA), Cilium, Calico 중 하나를 사용한다.
# NetworkPolicy 예시 — nestjs-api Pod는 postgres Pod에서만 인바운드 허용apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: postgres-allow-api-only namespace: productionspec: podSelector: matchLabels: app: postgres # 이 정책이 적용되는 Pod (postgres) policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: nestjs-api # nestjs-api Pod에서 오는 트래픽만 허용 ports: - protocol: TCP port: 5432 egress: - {} # postgres에서 나가는 트래픽은 모두 허용 (응답 포함)# 기본 차단 정책 — 먼저 모든 트래픽을 막고, 허용 규칙을 추가하는 패턴 (권장)apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny-all namespace: productionspec: podSelector: {} # namespace 내 모든 Pod에 적용 policyTypes: - Ingress - Egress # ingress/egress 규칙 없음 → 모든 트래픽 차단# NetworkPolicy 적용 후 차단 확인$ kubectl exec -it attacker-pod -n production -- curl http://postgres:5432curl: (6) Could not resolve host: postgres ← 연결 거부 (차단됨)
# nestjs-api에서는 정상 접근$ kubectl exec -it nestjs-api-xxx -n production -- curl http://postgres:5432# → 정상 응답 (허용된 Pod)📖 더 보기: Kubernetes Network Policies 공식 문서 — policyTypes 종류, podSelector/namespaceSelector 조합, NetworkPolicy 레시피 모음
RBAC (Role-Based Access Control) — “누가 무엇을 할 수 있는가” 권한 관리
Kubernetes RBAC는 클러스터 내 모든 작업에 대해 “누가(Who) 어떤 리소스에(What) 어떤 행동을(How)” 할 수 있는지 제어하는 권한 시스템이다. 프로덕션 EKS에서 개발자가 kubectl로 배포하거나, ServiceAccount가 API에 접근하거나, ArgoCD가 리소스를 관리할 때 모두 RBAC 규칙이 적용된다.
비유: RBAC는 회사의 “직급별 권한 규정서”다. “인턴은 읽기만 가능”, “팀장은 수정 가능”, “IT 관리자는 모든 것 가능”처럼 역할(Role)에 권한을 부여하고, 사람(User/ServiceAccount)에게 역할을 할당한다.
RBAC 4가지 핵심 오브젝트├── Role ← 특정 Namespace 안에서의 권한 정의 (pods를 get/list 가능 등)├── ClusterRole ← 클러스터 전체에서의 권한 정의 (모든 Namespace에 적용)├── RoleBinding ← User/ServiceAccount에 Role을 연결 (Namespace 범위)└── ClusterRoleBinding ← User/ServiceAccount에 ClusterRole을 연결 (전체 범위)# Role 예시 — production Namespace에서 Pod 읽기만 허용apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata: name: pod-reader namespace: productionrules: - apiGroups: [""] # "" = core API group (Pod, Service, ConfigMap 등) resources: ["pods", "pods/log"] verbs: ["get", "list", "watch"] # 읽기만 허용 (create/delete는 불가)---# RoleBinding — 개발자 그룹에 pod-reader Role 부여apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: name: dev-team-pod-reader namespace: productionsubjects: - kind: Group name: dev-team # AWS IAM Group이나 OIDC 그룹 이름 apiGroup: rbac.authorization.k8s.ioroleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io# ServiceAccount용 ClusterRole 예시 — ArgoCD가 클러스터 전체 리소스를 관리하도록 허용apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: argocd-managerrules: - apiGroups: ["*"] resources: ["*"] verbs: ["*"] # 모든 권한 (ArgoCD는 전체 클러스터 관리가 필요)---# NestJS API ServiceAccount — S3 접근 최소 권한 (Least Privilege 원칙)# → K8s RBAC가 아닌 IAM Role로 제어 (EKS Pod Identity 활용)# RBAC 권한 확인 — "내가 이 작업을 할 수 있나?"$ kubectl auth can-i get pods --namespace productionyes
$ kubectl auth can-i delete pods --namespace productionno ← pod-reader Role만 있어서 삭제 불가
# 다른 사용자 권한 확인 (관리자가 확인)$ kubectl auth can-i create deployments --as=dev-user --namespace productionno📖 더 보기: Kubernetes RBAC 공식 문서 — Role/ClusterRole 규칙 문법, 집계 ClusterRole, EKS에서 AWS IAM과 RBAC를 연동하는 방법
4. 실무에서 어디에 쓰이나
섹션 제목: “4. 실무에서 어디에 쓰이나”- 마이크로서비스 배포 및 오케스트레이션
- 멀티 클라우드 / 하이브리드 클라우드 환경
- 개발자 셀프서비스 플랫폼 (IDP) 기반
- CI/CD 파이프라인의 배포 타겟
- 자동 스케일링 (HPA/KEDA — CPU/이벤트 기반, Karpenter — 노드 자동 추가)
- AWS EKS Auto Mode (2025): Karpenter 기반 노드 프로비저닝 자동화를 AWS 관리형으로 제공
5. ECS 유지 vs EKS 전환 판단 기준
섹션 제목: “5. ECS 유지 vs EKS 전환 판단 기준”ECS와 EKS 중 어느 쪽을 선택할지는 팀 규모, 멀티클라우드 필요성, 운영 복잡도 허용 여부 세 가지 축으로 판단한다. 아래 기준은 Datadog 2024 Container Report(ECS 55% vs EKS 45% 분포) 및 실제 마이그레이션 사례를 기반으로 정리했다.
| 판단 축 | ECS 유지 권장 | EKS 전환 권장 |
|---|---|---|
| 팀 규모 | 개발자 10명 미만, DevOps 전담 없음 | 플랫폼 팀 별도 운영, 엔지니어 10명+ |
| 멀티클라우드 필요성 | AWS 단일 환경으로 충분 | 하이브리드/멀티클라우드 필요, 온프레미스 병행 |
| 운영 복잡도 허용 | AWS 관리형 API 선호, 빠른 온보딩 중요 | RBAC·add-on·업그레이드 관리 수용 가능 |
| 생태계 요구 | 기본 CI/CD, ALB 연동으로 충분 | ArgoCD, Istio, KEDA, 커스텀 Operator 필요 |
| 비용 감수 | 컨트롤 플레인 비용 없음 | EKS 클러스터당 $0.10/시간($73/월) 추가 |
ECS를 선택한다면: AWS Fargate + App Mesh 조합으로 서비스 메시와 자동 스케일링을 EKS 없이 구현할 수 있다.
EKS를 선택한다면: AWS EKS Auto Mode(2025 GA)로 Karpenter 기반 노드 관리를 완전 위임해 운영 부담을 줄일 수 있다.
📖 참고: ECS vs EKS 2026 비교 - SquareOps, ECS에서 EKS 마이그레이션 실전 - Medium
5.5 현재 내 업무와 연결점
섹션 제목: “5.5 현재 내 업무와 연결점”- 팀이 ECS에서 EKS로 마이그레이션을 검토할 때 비교 판단 가능
- 플랫폼 엔지니어링 도구(ArgoCD, Helm, Crossplane)의 기반 이해
- Kubernetes 기반 서비스를 운영하는 다른 팀과 협업 시 공통 언어
- IDP 구축 시 Kubernetes가 인프라 추상화 레이어로 사용됨
- KEDA + SQS 조합으로 Nest.js 워커 서비스의 이벤트 기반 자동 스케일링 구현 가능
6. 자주 헷갈리는 개념 비교
섹션 제목: “6. 자주 헷갈리는 개념 비교”| 개념 A | 개념 B | 차이점 |
|---|---|---|
| ECS | EKS(Kubernetes) | ECS는 AWS 전용 간단한 오케스트레이션, EKS는 클라우드 중립 Kubernetes |
| Pod | Container | Pod는 1개 이상의 Container를 묶는 단위. 보통 1 Pod = 1 Container |
| Deployment | StatefulSet | Deployment는 상태 없는(stateless) 앱, StatefulSet은 DB처럼 상태 있는 앱 |
| Service(ClusterIP) | Service(LoadBalancer) | ClusterIP는 클러스터 내부 통신, LoadBalancer는 외부 노출 |
| Helm | kubectl apply | Helm은 패키지 매니저(여러 YAML 템플릿화), kubectl은 개별 리소스 적용 |
| HPA | KEDA | HPA는 CPU/메모리 기준 Pod 스케일링, KEDA는 SQS/Kafka 등 외부 이벤트 기반 |
| HPA | VPA | HPA는 Pod 수를 늘림, VPA는 개별 Pod의 CPU/메모리 할당량을 자동 조정 |
| Cluster Autoscaler | Karpenter | CA는 미리 정의된 Node Group 단위 스케일링, Karpenter는 요구사항 맞춤 즉시 프로비저닝 |
6.5 트러블슈팅
섹션 제목: “6.5 트러블슈팅”🔧 CrashLoopBackOff — Pod가 시작했다가 죽는 것을 반복
섹션 제목: “🔧 CrashLoopBackOff — Pod가 시작했다가 죽는 것을 반복”증상: kubectl get pods에서 STATUS가 CrashLoopBackOff이고 RESTARTS 숫자가 계속 올라감
원인: 컨테이너 안의 앱이 시작 직후 에러로 종료되는 경우. Nest.js 앱이라면 DB 연결 실패, 환경변수 누락, 포트 충돌 등이 가장 흔하다
해결:
- 로그 확인:
kubectl logs <pod-name> --previous(이전 실행 로그 확인) - 에러 메시지 파악: DB 연결 에러면 ConfigMap/Secret의 DB_HOST가 맞는지 확인
- 환경변수 확인:
kubectl exec <pod-name> -- env | grep DB - 상세 이벤트 확인:
kubectl describe pod <pod-name>→ Events 섹션 맨 아래 확인
# kubectl describe pod 출력 예시 (Events 섹션)Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Pulled 2m kubelet Successfully pulled image Normal Created 2m kubelet Created container api Warning BackOff 30s (x5 over 2m) kubelet Back-off restarting failed container🔧 OOMKilled — 메모리 부족으로 컨테이너 강제 종료
섹션 제목: “🔧 OOMKilled — 메모리 부족으로 컨테이너 강제 종료”증상: Pod STATUS가 OOMKilled 또는 kubectl describe pod에서 Exit Code: 137 확인됨
원인: Deployment YAML의 resources.limits.memory를 너무 낮게 설정했거나, Nest.js 앱에 메모리 누수가 있는 경우. Exit Code 137 = SIGKILL 신호로 강제 종료됨
해결:
- 실제 메모리 사용량 확인:
kubectl top pods -l app=nestjs-api - limits 값을 실제 사용량의 1.5~2배로 상향 조정
- 메모리 누수 의심이면 Nest.js 앱에서
--max-old-space-size옵션 확인 - 조정 후
kubectl apply -f deployment.yaml로 재배포
# kubectl describe pod으로 OOMKilled 확인Last State: Terminated Reason: OOMKilled Exit Code: 137 Started: Sun, 29 Mar 2026 10:00:00 +0900 Finished: Sun, 29 Mar 2026 10:05:32 +0900🔧 ImagePullBackOff — 컨테이너 이미지를 가져오지 못함
섹션 제목: “🔧 ImagePullBackOff — 컨테이너 이미지를 가져오지 못함”증상: kubectl get pods에서 STATUS가 ImagePullBackOff 또는 ErrImagePull
원인: ECR 같은 private 레지스트리에서 이미지를 가져올 때 인증 정보가 없거나, 이미지 태그가 존재하지 않는 경우
해결:
kubectl describe pod <pod-name>으로 정확한 에러 확인- 이미지 태그 오타 확인:
my-ecr/nestjs-api:latestt(오타) vslatest - ECR 인증 문제라면 imagePullSecret 설정 확인
- EKS 환경이면 Node의 IAM Role에 ECR 읽기 권한(
ecr:GetDownloadUrlForLayer등) 있는지 확인
# kubectl describe pod Events 섹션 예시Events: Warning Failed 2m kubelet Failed to pull image "123456789.dkr.ecr.ap-northeast-2.amazonaws.com/nestjs-api:v1.2.3": rpc error: code = Unknown desc = pull access denied Warning Failed 2m kubelet Error: ErrImagePull Warning BackOff 1m kubelet Back-off pulling image🔧 Pod가 Pending 상태에서 멈춤 — 스케줄링 실패
섹션 제목: “🔧 Pod가 Pending 상태에서 멈춤 — 스케줄링 실패”증상: kubectl get pods에서 STATUS가 Pending이고 Running이 되지 않음. 새로 추가된 Pod가 특히 많을 때 발생
원인: 클러스터에 Pod가 요청한 CPU/메모리 자원을 충족하는 Node가 없거나, Node Selector / Affinity 조건을 만족하는 Node가 없는 경우
해결:
kubectl describe pod <pod-name>의 Events 섹션에서 스케줄링 실패 이유 확인- Node 자원 현황 확인:
kubectl describe nodes | grep -A 5 "Allocated resources" - resources.requests 값을 현실적으로 낮추거나, Node를 추가
- EKS 환경이면 Cluster Autoscaler나 Karpenter가 Node를 자동으로 추가하도록 설정
# kubectl describe pod Events 예시 — 스케줄링 실패Events: Warning FailedScheduling 90s default-scheduler 0/3 nodes are available: 3 Insufficient cpu.# → 3개 Node 모두 CPU 자원 부족 → Node 추가 또는 requests 값 조정 필요🔧 Readiness Probe 실패로 서비스 중단 — 롤링 업데이트 시 주의
섹션 제목: “🔧 Readiness Probe 실패로 서비스 중단 — 롤링 업데이트 시 주의”증상: 새 버전으로 롤링 업데이트 중에 일부 Pod가 Running인데도 0/1 READY로 표시되고, 트래픽이 줄어드는 현상
원인: 새 Pod가 시작됐지만 Readiness Probe 조건(DB 연결 준비, 캐시 워밍업 등)을 아직 만족하지 못한 상태. initialDelaySeconds가 너무 짧게 설정된 경우에 특히 많이 발생
해결:
kubectl rollout status deployment/nestjs-api로 롤아웃 진행 상황 확인kubectl describe pod <new-pod>로 Readiness Probe 실패 메시지 확인initialDelaySeconds값을 앱 실제 시작 시간보다 여유 있게 늘림 (예: 10s → 30s)- 문제가 심각하면 이전 버전으로 즉시 롤백:
kubectl rollout undo deployment/nestjs-api
# 롤링 업데이트 중 상태 확인$ kubectl rollout status deployment/nestjs-apiWaiting for deployment "nestjs-api" rollout to finish: 1 out of 3 new replicas have been updated...Waiting for deployment "nestjs-api" rollout to finish: 1 old replicas are pending termination...
# 문제 발생 시 즉시 롤백$ kubectl rollout undo deployment/nestjs-apideployment.apps/nestjs-api rolled back🔧 DNS 해석 실패 — Service 이름으로 다른 Pod에 접근 불가
섹션 제목: “🔧 DNS 해석 실패 — Service 이름으로 다른 Pod에 접근 불가”증상: Pod 안에서 다른 Service에 접근할 때 could not resolve host 또는 Name or service not known 에러. Nest.js 앱에서 Redis나 PostgreSQL 연결이 DNS 해석 단계에서 실패
원인: CoreDNS Pod가 비정상이거나, Service 이름/Namespace가 잘못되었거나, NetworkPolicy가 DNS 트래픽(UDP 53)을 차단하는 경우
해결:
- CoreDNS Pod 상태 확인:
kubectl get pods -n kube-system -l k8s-app=kube-dns - DNS 해석 테스트:
kubectl exec -it <pod> -- nslookup <service-name> - Service가 실제로 존재하는지 확인:
kubectl get svc -A | grep <service-name> - 다른 Namespace의 Service라면 FQDN 사용:
<service>.<namespace>.svc.cluster.local - NetworkPolicy가 있다면 UDP 53 포트가 허용되어 있는지 확인
# DNS 디버깅 단계별 확인$ kubectl get pods -n kube-system -l k8s-app=kube-dnsNAME READY STATUS RESTARTS AGEcoredns-5d78c9869d-abc12 1/1 Running 0 3dcoredns-5d78c9869d-def34 1/1 Running 0 3d
# DNS 해석 직접 테스트$ kubectl exec -it nestjs-api-xxx -- nslookup redis-cacheServer: 10.96.0.10Address: 10.96.0.10#53
Name: redis-cache.default.svc.cluster.localAddress: 10.100.50.23
# 실패 시 출력 예시$ kubectl exec -it nestjs-api-xxx -- nslookup redis-cache** server can't find redis-cache: NXDOMAIN# → Service 이름이 잘못되었거나, 다른 Namespace에 있음📖 더 보기: Debugging DNS Resolution - Kubernetes 공식 문서 — DNS 디버깅용 Pod 생성, CoreDNS 로그 확인, ndots 설정 문제 해결 방법
🔧 resources.requests 미설정으로 특정 Node에 Pod가 몰림
섹션 제목: “🔧 resources.requests 미설정으로 특정 Node에 Pod가 몰림”증상: 클러스터에 Node가 여러 개인데 특정 Node에만 Pod가 집중되어 해당 Node가 과부하
원인: resources.requests를 설정하지 않으면 Scheduler가 Node 분산을 정확히 계산하지 못함. 또한 latest 이미지 태그를 사용하면 같은 이미지가 있는 Node를 선호해서 몰림 현상이 발생할 수 있음
해결:
- 모든 컨테이너에
resources.requests와limits명시 (Kubernetes QoS 정책 적용을 위해서도 필수) kubectl top pods로 실제 사용량 파악 후 적절한 값 설정- 특정 Node에 몰리지 않도록
podAntiAffinity설정 추가:affinity:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues: ["nestjs-api"]topologyKey: kubernetes.io/hostname
🔧 아키텍처 레벨 실패 — etcd 쿼럼 손실 & Spot 대량 회수
섹션 제목: “🔧 아키텍처 레벨 실패 — etcd 쿼럼 손실 & Spot 대량 회수”시나리오 A: etcd 쿼럼 손실 → 클러스터 전체 API 불가
etcd는 Raft 합의 알고리즘을 사용한다. 3노드 클러스터에서 2노드가 동시에 장애를 일으키면 쿼럼(과반수)을 잃고 API Server가 새 상태를 기록할 수 없게 된다. 이 시점부터 kubectl 명령이 전부 타임아웃되며, 이미 실행 중인 워커 노드의 Pod는 계속 동작하지만 신규 배포·스케일링·자가 치유가 전부 멈춘다.
# 쿼럼 손실 징후$ kubectl get nodesError from server: etcdserver: request timed out
# etcd 멤버 상태 확인 (control plane에서 직접)$ etcdctl member list --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key# → 살아있는 멤버가 3개 중 1개면 쿼럼 없음 (quorum: (N-1)/2 초과 필요)복구 절차: 정상 멤버 1개를 남기고 나머지를 강제 제거(etcdctl member remove) → 단일 노드 클러스터로 리셋 → 스냅샷 복원(etcdctl snapshot restore). EKS 환경에서는 AWS가 etcd를 완전 관리하므로 쿼럼 손실 시 AWS Support를 통해 복구 요청이 필요하다.
예방책: Control Plane을 홀수 3개 이상 노드로 구성하고, etcd를 별도 볼륨에서 운영, 정기 스냅샷을 S3에 백업. EKS 사용 시 쿼럼 관리를 AWS에 위임하므로 직접 운영 클러스터(kubeadm 등) 대비 위험이 낮다.
시나리오 B: Spot 인스턴스 대량 회수 → graceful shutdown 미설정 시 데이터 유실
AWS는 Spot 인스턴스 회수 2분 전에 termination notice(EC2 메타데이터 이벤트)를 보낸다. terminationGracePeriodSeconds 미설정(기본 30초) 또는 preStop hook 미설정 상태에서 대규모 Spot 회수가 동시에 발생하면 처리 중인 요청이 강제 종료되어 데이터 유실·504 에러 급증이 발생한다.
# Spot 친화적 Pod 설정 — graceful shutdown + PDB 조합spec: terminationGracePeriodSeconds: 120 # AWS Spot 2분 notice에 맞춤 containers: - name: api lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 10"] # 로드밸런서 헬스체크 제거 대기---# PodDisruptionBudget — 동시 회수 Pod 수 제한apiVersion: policy/v1kind: PodDisruptionBudgetmetadata: name: nestjs-api-pdbspec: minAvailable: 2 # 최소 2개 Pod 항상 유지 selector: matchLabels: app: nestjs-api필수 컴포넌트: AWS Node Termination Handler를 DaemonSet으로 배포하면 Spot notice를 감지해 자동으로 cordon → drain 순서로 처리하여 다른 노드로 Pod를 이전시킨다. Karpenter 사용 시 이 기능이 내장되어 있다.
📖 참고: etcd Disaster Recovery - 공식 문서, Spot Instance Interruption 처리 - Zesty
7. 체크리스트
섹션 제목: “7. 체크리스트”- Kubernetes가 뭔지, ECS와 어떻게 다른지 설명할 수 있다
- Pod, Deployment, Service, Ingress의 역할을 각각 설명할 수 있다
- 선언적 관리(desired state)가 뭔지 설명할 수 있다
- YAML 매니페스트의 기본 구조(apiVersion, kind, metadata, spec)를 읽을 수 있다
- 자가 치유가 어떻게 동작하는지 설명할 수 있다
- Scheduler의 Filtering/Scoring 두 단계를 설명할 수 있다
- HPA가 무엇이고 언제 필요한지 설명할 수 있다
- KEDA가 HPA와 어떻게 다른지 설명할 수 있다
- Karpenter가 Cluster Autoscaler와 어떻게 다른지 설명할 수 있다
- Readiness/Liveness Probe를 언제 어떻게 설정해야 하는지 설명할 수 있다
- NetworkPolicy가 무엇이고 왜 프로덕션에서 필요한지 설명할 수 있다
- RBAC의 Role/ClusterRole/RoleBinding 차이를 설명할 수 있다
-
kubectl auth can-i로 권한을 확인하는 방법을 설명할 수 있다
7.5. Helm 기초 — K8s 생태계의 패키지 매니저
섹션 제목: “7.5. Helm 기초 — K8s 생태계의 패키지 매니저”Kubernetes를 실제로 운영하면 수십 개의 YAML을 반복해서 관리해야 한다. Helm은 K8s 생태계에서 거의 필수인 패키지 매니저로, npm이 Node.js 패키지를 관리하듯 K8s 리소스 묶음(Chart)을 관리한다.
핵심 개념 3가지:
- Chart: Deployment, Service, ConfigMap 등 관련 리소스를 하나로 묶은 패키지.
helm install prometheus prometheus-community/prometheus한 줄로 복잡한 모니터링 스택을 설치한다. - values.yaml: Chart의 기본 설정값. 레플리카 수, 이미지 태그, 리소스 제한 등을 재정의할 수 있다. 환경별로 다른
values-prod.yaml을 만들어서helm install -f values-prod.yaml로 덮어쓴다. - Release: Chart를 특정 클러스터에 설치한 인스턴스. 같은 Chart를 여러 번 설치해서
my-app-dev,my-app-prod같은 독립적인 Release를 만들 수 있다.
helm install my-app ./charts/my-app -f values-prod.yaml # 설치helm upgrade my-app ./charts/my-app --set image.tag=v2 # 업그레이드helm rollback my-app 1 # 이전 버전으로 롤백helm list # 설치된 Release 목록ArgoCD/FluxCD와 조합하면 “Git에 values.yaml을 커밋 → GitOps가 자동으로 helm upgrade 실행”하는 패턴이 된다. 이것이 현대적인 K8s 배포 워크플로의 핵심이다.
8. 추가 학습 키워드
섹션 제목: “8. 추가 학습 키워드”Helm, Kustomize, HPA(Horizontal Pod Autoscaler), VPA, KEDA, Karpenter, RBAC, Network Policy, PersistentVolume, EKS, minikube, kind, kubectl, Lens, Cluster Autoscaler, metrics-server, Readiness/Liveness Probe, PodDisruptionBudget, topologySpreadConstraints
8.5 추천 리소스
섹션 제목: “8.5 추천 리소스”📚 추천 리소스
섹션 제목: “📚 추천 리소스”- 📖 Learn Kubernetes Basics (공식 튜토리얼) — kubectl로 첫 Deployment 배포까지 단계별 인터랙티브 튜토리얼 (입문)
- 🎬 Kubernetes Tutorial for Beginners - TechWorld with Nana (YouTube) — 3시간짜리 풀코스, 입문자가 가장 많이 추천하는 강의 (입문)
- 📖 Kubernetes Architecture Explained - DevOpsCube (2026) — Control Plane 각 컴포넌트의 역할과 내부 동작을 다이어그램으로 상세 설명 (중급)
- 📖 KEDA + Karpenter on EKS - AWS Blog — 이벤트 기반 스케일링과 노드 자동 프로비저닝 결합으로 비용 최적화 (중급)
- 📖 EKS Best Practices Guide - Security — AWS EKS 환경에서 RBAC, NetworkPolicy, Pod Security Standards를 적용하는 프로덕션 보안 가이드 (중급)
9. 내가 직접 확인해볼 것
섹션 제목: “9. 내가 직접 확인해볼 것”-
minikube start로 로컬 K8s 클러스터를 띄우고kubectl get nodes로 상태 확인$ minikube start😄 minikube v1.35.0 on Darwin arm64✅ Using the docker driver based on existing profile🏄 Done! kubectl is now configured to use "minikube" cluster$ kubectl get nodesNAME STATUS ROLES AGE VERSIONminikube Ready control-plane 2m v1.32.0 -
간단한 Deployment YAML 작성 →
kubectl apply -f→kubectl get pods로 Pod 확인$ kubectl apply -f nestjs-api-deployment.yamldeployment.apps/nestjs-api created$ kubectl get podsNAME READY STATUS RESTARTS AGEnestjs-api-7d9f4b8c4-2xkpq 1/1 Running 0 15snestjs-api-7d9f4b8c4-8qwtm 1/1 Running 0 15snestjs-api-7d9f4b8c4-vn4rp 1/1 Running 0 15s -
kubectl scale deployment nestjs-api --replicas=5로 스케일링 테스트$ kubectl scale deployment nestjs-api --replicas=5deployment.apps/nestjs-api scaled$ kubectl get podsNAME READY STATUS RESTARTS AGEnestjs-api-7d9f4b8c4-2xkpq 1/1 Running 0 2mnestjs-api-7d9f4b8c4-8qwtm 1/1 Running 0 2mnestjs-api-7d9f4b8c4-vn4rp 1/1 Running 0 2mnestjs-api-7d9f4b8c4-k9nzx 0/1 ContainerCreating 0 3snestjs-api-7d9f4b8c4-p2mwt 0/1 ContainerCreating 0 3s -
Pod를
kubectl delete pod <name>으로 강제 삭제 후 자동 재생성 확인 -
kubectl describe node minikube로 Scheduler가 사용하는 Node 자원 현황 확인$ kubectl describe node minikube | grep -A 8 "Allocated resources"Allocated resources:(Total limits may be over 100 percent, i.e., overcommitted.)Resource Requests Limits-------- -------- ------cpu 650m (32%) 700m (35%)memory 420Mi (10%) 820Mi (20%) -
Readiness Probe가 달린 Deployment를 배포하고
kubectl describe pod으로 Probe 동작 확인$ kubectl describe pod nestjs-api-xxx | grep -A 10 "Readiness"Readiness: http-get http://:3000/health delay=10s timeout=1s period=5s#success=1 #failure=3# → /health 엔드포인트로 5초마다 체크, 3번 실패 시 트래픽 차단 -
HPA 설정 후
kubectl get hpa로 현재 CPU 사용률과 레플리카 수 모니터링$ kubectl get hpa nestjs-api-hpa --watchNAME REFERENCE TARGETS MINPODS MAXPODS REPLICASnestjs-api-hpa Deployment/nestjs-api 12%/50% 2 10 2nestjs-api-hpa Deployment/nestjs-api 64%/50% 2 10 3 ← 자동 스케일 업nestjs-api-hpa Deployment/nestjs-api 81%/50% 2 10 4
10. 요약 및 복습 포인트
섹션 제목: “10. 요약 및 복습 포인트”핵심 5줄
섹션 제목: “핵심 5줄”- Kubernetes는 컨테이너 오케스트레이션의 업계 표준으로, 2026년 플랫폼 엔지니어 필수 스킬이다
- Pod(실행 단위), Deployment(복제 관리), Service(네트워크 접점)가 핵심 오브젝트이다
- YAML로 “원하는 상태”를 선언하면 Kubernetes가 자동으로 현재 상태를 맞춘다 (Controller Loop)
- HPA(CPU 기반)/KEDA(이벤트 기반)로 Pod를 자동 스케일링하고, Karpenter로 Node를 자동 프로비저닝한다
- 2025년 EKS Capabilities(ArgoCD/ACK/KRO)로 Kubernetes 플랫폼 운영 복잡도가 크게 낮아졌다
개념 연결 지도
섹션 제목: “개념 연결 지도”kubectl apply -f deployment.yaml └── API Server (모든 통신의 단일 창구) ├── etcd (원하는 상태 저장) ├── Controller Manager (현재 상태 → 원하는 상태로 맞추는 제어 루프) │ └── ReplicaSet Controller → "Pod 3개 만들어줘" └── Scheduler (어떤 Node에 배치할지 Filtering → Scoring) └── kubelet (해당 Node에서 실제 컨테이너 실행)
스케일링 레이어 ├── Pod 스케일링: HPA(CPU/메모리) → KEDA(SQS, Kafka 등 외부 이벤트) └── Node 스케일링: Karpenter(Pod 요구사항에 맞는 최적 인스턴스 즉시 프로비저닝)
ECS → K8s 매핑 Task Definition → Pod spec + Deployment spec Service → Deployment + Service(ClusterIP) ALB + Rules → Ingress Secrets Manager → Secret (+ External Secrets Operator) Auto Scaling Group → Karpenter NodePool자주 나오는 면접/리뷰 질문
섹션 제목: “자주 나오는 면접/리뷰 질문”- “ECS와 Kubernetes의 차이?” → ECS는 AWS 전용, K8s는 클라우드 중립. K8s는 더 많은 기능과 생태계를 갖추지만 복잡도도 높음
- “Deployment와 StatefulSet의 차이?” → Deployment는 상태 없는 앱(각 Pod가 교체 가능), StatefulSet은 DB처럼 Pod별로 고유한 ID와 영구 볼륨이 필요한 경우
- “resources.requests와 limits의 차이?” → requests는 Scheduler가 Node를 선택하는 기준(예약량), limits는 실제 사용 상한선. requests 없으면 Scheduler가 분산을 정확히 계산 불가
- “Readiness vs Liveness Probe?” → Readiness는 “트래픽 받을 준비 됐나” (실패 시 Service에서 제외), Liveness는 “살아있나” (실패 시 컨테이너 재시작)
프로덕션 운영 체크리스트
섹션 제목: “프로덕션 운영 체크리스트”- 모든 컨테이너에
resources.requests와limits를 명시했는가? - Readiness Probe와 Liveness Probe를 설정했는가? (
initialDelaySeconds는 실제 시작 시간보다 여유 있게) - HPA를 설정했는가? 그리고 metrics-server가 설치되어 있는가?
- 같은 종류의 Pod가 여러 Node에 분산되도록
podAntiAffinity를 설정했는가? - Karpenter(또는 Cluster Autoscaler)가 Node 자동 추가를 담당하는가?
-
latest이미지 태그 대신 특정 버전 태그(예:v1.2.3)를 사용하는가? - PodDisruptionBudget(PDB)으로 롤링 업데이트 중 최소 가용 Pod 수를 보장하는가?
최종 수정: 2026-04-01