목록으로 가기

Kubernetes 클러스터 구조와 핵심 오브젝트 이해하기

Pod, Service, Deployment가 뭔지, 클러스터는 어떻게 구성되는지, kubectl 명령어까지. 쿠버네티스를 처음 접해도 이해할 수 있게 정리했습니다.

Kubernetes 클러스터 구조와 핵심 오브젝트 이해하기 ko posts kubernetes Pod, Service, Deployment가 뭔지, 클러스터는 어떻게 구성되는지, kubectl 명령어까지. 쿠버네티스를 처음 접해도 이해할 수 있게 정리했습니다.

개요

Kubernetes(K8s)는 컨테이너를 여러 서버에 자동으로 배포하고, 죽으면 다시 띄우고, 부하가 늘면 늘려주는 도구입니다.

Docker가 “컨테이너 하나를 만들고 실행하는 것"이라면, Kubernetes는 “그 컨테이너를 여러 노드에 걸쳐 운영하는 것"입니다.

이 글은 각 개념을 정의, 필요한 이유, 관련 명령어 순으로 정리합니다.

1. 클러스터 구조

정리 보기

클러스터 = 컨트롤 플레인 + 노드

Kubernetes 클러스터는 크게 두 부분으로 나뉩니다.

┌─────────────────────────────────────────────┐
│                 Control Plane                │
│  API Server / Scheduler / Controller / etcd  │
└──────────────────────┬──────────────────────┘
                       │ 명령 전달
       ┌───────────────┼───────────────┐
       ▼               ▼               ▼
┌────────────┐  ┌────────────┐  ┌────────────┐
│   Node 1   │  │   Node 2   │  │   Node 3   │
│  (워커 노드) │  │  (워커 노드) │  │  (워커 노드) │
│  Pod Pod   │  │  Pod Pod   │  │  Pod Pod   │
└────────────┘  └────────────┘  └────────────┘

Control Plane (컨트롤 플레인) — 클러스터 상태를 관리하는 컴포넌트 모음

구성요소 역할
API Server 모든 요청의 출입구. kubectl 명령이 여기로 감
Scheduler 새 Pod를 어느 Node에 배치할지 결정
Controller Manager 원하는 상태를 유지 (Pod 죽으면 다시 띄움)
etcd 클러스터 전체 상태를 저장하는 데이터베이스

Node (노드) — 실제로 컨테이너가 돌아가는 서버

구성요소 역할
kubelet 이 노드에서 Pod을 실행/감시
kube-proxy 네트워크 트래픽을 적절한 Pod으로 전달
Container Runtime 실제 컨테이너 실행 (containerd 등)

확인 명령어

# 클러스터 정보 확인
kubectl cluster-info

# 노드 목록과 상태
kubectl get nodes

# 노드 상세 정보 (CPU/메모리 할당 현황 등)
kubectl describe node <노드이름>

2. Pod (파드)

정리 보기

Pod = 가장 작은 배포 단위

Pod는 Kubernetes에서 가장 작은 실행 단위입니다. 공식 문서는 컨테이너 하나를 실행하는 단일 컨테이너 Pod(“one-container-per-Pod”)를 가장 일반적인 Kubernetes 사용 방식으로 설명합니다.

Docker에서 docker run으로 컨테이너를 띄웠다면, Kubernetes에서는 Pod를 만듭니다.

왜 컨테이너가 아니라 Pod인가?

  • 같은 Pod 안의 컨테이너끼리는 네트워크(localhost)와 볼륨을 공유
  • 앱 옆에 로그 수집기를 붙이는 식의 “사이드카 패턴"이 가능
  • 공식 문서에서는 단일 컨테이너 Pod를 가장 일반적인 사용 방식으로 설명하고, 여러 컨테이너를 한 Pod에 함께 두는 것은 컨테이너가 강하게 결합된 경우에만 쓰는 비교적 고급 사용 사례로 설명

Pod YAML 예시

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  labels:
    app: web
spec:
  containers:
    - name: web
      image: nginx:1.25
      ports:
        - containerPort: 80

명령어

# Pod 목록
kubectl get pods

# Pod 상세 정보 (이벤트, 상태, IP 등)
kubectl describe pod <pod이름>

# Pod 로그 보기
kubectl logs <pod이름>

# Pod 안에 들어가기 (디버깅)
kubectl exec -it <pod이름> -- /bin/sh

# Pod 삭제
kubectl delete pod <pod이름>

Pod의 생명주기

status.phase가 가질 수 있는 값은 Pending, Running, Succeeded, Failed, Unknown 5가지입니다.

Pending → Running → Succeeded / Failed
                    (노드와 통신 불가 시 Unknown)
  • Pending: 클러스터가 Pod를 받아들였지만 컨테이너 하나 이상이 아직 실행 준비되지 않은 상태. 스케줄링 대기 시간과 이미지 다운로드 시간이 여기 포함됨
  • Running: 노드에 바인딩되고 모든 컨테이너가 생성된 상태. 최소 한 개가 실행 중이거나 시작/재시작 중
  • Succeeded: 모든 컨테이너가 성공적으로 종료되고 재시작되지 않음
  • Failed: 모든 컨테이너가 종료됐고 그중 하나 이상이 실패로 끝남
  • Unknown: 노드와 통신이 안 돼서 상태를 가져올 수 없는 경우

CrashLoopBackOff는 phase가 아닙니다. 재시작 백오프가 걸린 컨테이너를 kubectl이 STATUS 칼럼에 표시하는 값입니다(Terminating도 같은 부류). phase는 Pod API 데이터 모델의 일부이고 STATUS는 kubectl 표시용 필드입니다.

  • CrashLoopBackOff: 컨테이너가 시작에 계속 실패해서 kubelet이 재시작 백오프(10s, 20s, 40s … 기본 상한 300초)를 적용 중인 상태

3. Deployment (디플로이먼트)

정리 보기

Deployment = “이 앱을 N개 유지해줘"라는 선언

Deployment를 만들면 K8s가 알아서 Pod을 원하는 개수만큼 띄우고, 죽으면 다시 만들고, 업데이트하면 순차적으로 교체합니다.

Deployment YAML 예시

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3              # Pod 3개 유지
  selector:
    matchLabels:
      app: web
  template:                # Pod 템플릿
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: myapp:1.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "256Mi"
              cpu: "500m"

명령어

# Deployment 생성 (YAML 적용)
kubectl apply -f deployment.yaml

# Deployment 목록
kubectl get deployments

# Pod 수 변경 (스케일링)
kubectl scale deployment web-app --replicas=5

# 이미지 업데이트 (롤링 업데이트 자동 실행)
kubectl set image deployment/web-app web=myapp:2.0

# 업데이트 상태 확인
kubectl rollout status deployment/web-app

# 문제 시 롤백
kubectl rollout undo deployment/web-app

# 배포 히스토리
kubectl rollout history deployment/web-app

Deployment → ReplicaSet → Pod 관계

Deployment (버전 관리 + 롤링 업데이트)
  └── ReplicaSet (Pod 개수 유지)
         └── Pod (실제 실행 단위)
  • Deployment가 ReplicaSet을 관리하므로, 공식 문서는 ReplicaSet을 직접 만들지 않고 Deployment를 사용하는 것을 권장 (커스텀 업데이트 제어가 필요하거나 업데이트가 아예 필요 없는 경우는 예외)

4. Service (서비스)

정리 보기

Service = Pod에 접속하는 고정 주소

Pod는 죽었다 살아나면 IP가 바뀝니다. 다른 앱이 이 Pod에 접속하려면 매번 IP를 찾아야 하는데, Service가 고정 주소를 제공합니다.

Service 종류

종류 접근 범위 용도
ClusterIP 클러스터 내부에서만 앱 간 통신 (type을 지정하지 않으면 이게 기본값)
NodePort 외부에서 노드IP:포트로 노드 포트로 직접 외부 노출
LoadBalancer 외부 로드밸런서 연결 프로바이더 연동 필요
ExternalName 외부 호스트명으로 CNAME 반환 클러스터 밖 서비스를 이름으로 참조
  • NodePort로 할당되는 포트는 API 서버의 --service-node-port-range 플래그로 정해지고, 기본값은 30000-32767입니다. nodePort를 직접 지정할 때도 이 범위 안이어야 합니다
  • LoadBalancer는 Kubernetes가 로드밸런서 자체를 제공하지 않습니다. 클라우드 프로바이더 연동이나 별도 구현이 있어야 실제로 프로비저닝됩니다

ClusterIP 예시 (기본 타입)

apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web          # label이 app=web인 Pod들에 연결
  ports:
    - port: 80        # Service 포트
      targetPort: 8080  # Pod의 컨테이너 포트
  type: ClusterIP

이렇게 만들면 클러스터 안에서 web-service:80으로 접속하면 app=web Pod들에 자동 로드밸런싱됩니다.

DNS 자동 등록

  • Service 만들면 <서비스이름>.<네임스페이스>.svc.<클러스터도메인> 형태로 A/AAAA 레코드가 등록됩니다. 클러스터 도메인 기본값이 cluster.local이라 보통 web-service.default.svc.cluster.local로 보입니다
  • 같은 네임스페이스면 그냥 서비스 이름으로 접속: curl http://web-service. Pod의 /etc/resolv.conf search 목록에 자기 네임스페이스가 들어있어서 짧은 이름이 확장됩니다
  • 다른 네임스페이스는 <서비스이름>.<네임스페이스>까지만 적어도 됩니다

명령어

# Service 목록
kubectl get services

# Service 상세 (연결된 Pod IP 목록 = Endpoints)
kubectl describe service web-service

# 외부 노출 (빠른 테스트)
kubectl expose deployment web-app --type=NodePort --port=80

5. Namespace (네임스페이스)

정리 보기

Namespace = 클러스터 내 리소스 그룹

하나의 클러스터를 논리적으로 나누는 방법입니다. 팀별, 환경별(dev/stg/prod)로 분리할 때 사용합니다.

# 네임스페이스 목록
kubectl get namespaces

# 특정 네임스페이스의 Pod 보기
kubectl get pods -n kube-system

# 네임스페이스 생성
kubectl create namespace dev

# 기본 네임스페이스 변경 (매번 -n 안 붙이려면)
kubectl config set-context --current --namespace=dev

기본 제공 네임스페이스

이름 용도
default 별도 지정 안 하면 여기에 생성됨
kube-system K8s 시스템 컴포넌트 (API Server, CoreDNS 등)
kube-public 누구나 읽을 수 있는 공개 리소스

6. ConfigMap과 Secret

정리 보기

ConfigMap = 설정 파일, Secret = 비밀 정보

앱의 설정값이나 비밀번호를 이미지에 넣지 않고 외부에서 주입합니다. Docker의 -e 환경변수나 .env 파일과 같은 역할.

ConfigMap 예시

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: "db.example.com"
  LOG_LEVEL: "info"

Secret 예시

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  DB_PASSWORD: cGFzc3dvcmQxMjM=    # base64 인코딩 (echo -n 'password123' | base64)

Pod에서 사용하기

spec:
  containers:
    - name: app
      image: myapp:1.0
      envFrom:
        - configMapRef:
            name: app-config
        - secretRef:
            name: app-secret

명령어

# ConfigMap 생성 (명령어)
kubectl create configmap app-config --from-literal=LOG_LEVEL=info

# Secret 생성
kubectl create secret generic app-secret --from-literal=DB_PASSWORD=password123

# ConfigMap/Secret 확인
kubectl get configmaps
kubectl get secrets

# Secret 내용 보기 (base64 디코딩 필요)
kubectl get secret app-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -d
  • Secret의 data 값은 base64 인코딩이며 암호화가 아닙니다. 저장 시 암호화는 etcd 암호화 설정으로 별도 구성합니다

7. 볼륨: PV와 PVC

정리 보기

PV = 프로비저닝된 스토리지, PVC = 스토리지 요청

Pod는 죽으면 데이터가 사라집니다. 데이터를 보존하려면 외부 저장소를 연결해야 합니다.

  • PersistentVolume (PV): 실제 스토리지. 관리자가 미리 만들어두는 정적 프로비저닝과, StorageClass를 통해 PVC에 맞춰 자동 생성되는 동적 프로비저닝 두 가지가 있습니다
  • PersistentVolumeClaim (PVC): 개발자가 “이만큼의 저장소가 필요합니다"라고 요청

PVC 예시

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-storage
spec:
  accessModes:
    - ReadWriteOnce       # 단일 노드에서 읽기/쓰기로 마운트
  resources:
    requests:
      storage: 10Gi       # 10GiB 요청 (Gi는 2의 거듭제곱 단위)

accessModes는 Pod 단위가 아니라 노드 단위

약어 의미
ReadWriteOnce RWO 단일 노드에서 읽기/쓰기 마운트
ReadOnlyMany ROX 여러 노드에서 읽기 전용 마운트
ReadWriteMany RWX 여러 노드에서 읽기/쓰기 마운트
ReadWriteOncePod RWOP 클러스터 전체에서 단 하나의 Pod만 읽기/쓰기
  • ReadWriteOnce는 “Pod 하나"가 아니라 “노드 하나"가 기준입니다. 같은 노드에 있는 여러 Pod가 동시에 그 볼륨을 읽고 쓸 수 있습니다. Pod 하나로 제한하려면 ReadWriteOncePod를 씁니다
  • 볼륨은 여러 accessModes를 지원해도 한 번에 하나의 모드로만 마운트됩니다
  • RWO/ROX/RWX는 PV와 PVC를 매칭하는 데 쓰이는 값이고, 마운트된 뒤 쓰기 자체를 막아주지는 않습니다. RWOP만 실제로 단일 Pod 제약이 적용됩니다

Pod에서 사용

spec:
  containers:
    - name: app
      image: myapp:1.0
      volumeMounts:
        - mountPath: /data
          name: storage
  volumes:
    - name: storage
      persistentVolumeClaim:
        claimName: data-storage

명령어

# PV, PVC 확인
kubectl get pv
kubectl get pvc

# PVC 상태 확인 (Bound = 정상 연결됨)
kubectl describe pvc data-storage

8. 워크로드 종류

정리 보기

Deployment 외에도 상황에 맞는 워크로드 종류가 있습니다.

종류 용도 예시
Deployment 상태 없는 앱 N개 유지 웹서버, API 서버
StatefulSet 순서/고유 이름이 필요한 앱 DB, Kafka, Redis 클러스터
DaemonSet 모든(또는 일부) 노드에 1개씩 배치 로그 수집기, 모니터링 에이전트
Job 한 번 실행하고 끝 DB 마이그레이션, 배치 처리
CronJob 정해진 시간에 반복 실행 매일 백업, 주기적 리포트

DaemonSet 예시 (모든 노드에 로그 수집기 배치)

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-collector
spec:
  selector:
    matchLabels:
      app: log-collector
  template:
    metadata:
      labels:
        app: log-collector
    spec:
      containers:
        - name: fluentd
          image: fluentd:latest

CronJob 예시 (매일 새벽 2시 백업)

apiVersion: batch/v1
kind: CronJob
metadata:
  name: daily-backup
spec:
  schedule: "0 2 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: backup
              image: backup-tool:1.0
          restartPolicy: OnFailure
# 각 워크로드 확인
kubectl get statefulsets
kubectl get daemonsets
kubectl get jobs
kubectl get cronjobs

9. Ingress (인그레스)

정리 보기

Ingress = 외부 → 클러스터 안으로 들어오는 입구 규칙

Service의 LoadBalancer는 서비스 하나당 로드밸런서 하나가 필요합니다. Ingress를 쓰면 하나의 입구에서 도메인/경로 기반으로 여러 Service에 라우팅할 수 있습니다.

Ingress 예시

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80
    - host: web.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-service
                port:
                  number: 80
  • Ingress는 규칙만 정의. 실제 동작은 Ingress Controller (nginx, traefik 등)가 담당
  • TLS(HTTPS) 인증서도 Ingress에서 설정
# Ingress 목록
kubectl get ingress

# 상세 확인
kubectl describe ingress my-ingress

10. kubectl 명령어 모음

정리 보기

조회 계열

# 리소스 목록 (pods, services, deployments 등)
kubectl get <리소스>

# 모든 네임스페이스에서 조회
kubectl get pods --all-namespaces
kubectl get pods -A    # 위와 같음 (축약)

# 상세 정보
kubectl describe <리소스> <이름>

# YAML로 현재 상태 보기
kubectl get deployment web-app -o yaml

생성/수정 계열

# YAML 파일로 생성 또는 업데이트
kubectl apply -f <파일.yaml>

# 폴더 안의 YAML 전부 적용
kubectl apply -f ./k8s/

# 빠른 생성 (간단한 테스트용)
kubectl run test-pod --image=nginx
kubectl create deployment test --image=nginx --replicas=2

삭제 계열

# 리소스 삭제
kubectl delete <리소스> <이름>

# YAML로 만든 것 삭제
kubectl delete -f <파일.yaml>

# 네임스페이스 통째로 삭제 (안의 모든 리소스 포함)
kubectl delete namespace dev

디버깅 계열

# 로그 보기
kubectl logs <pod이름>

# 실시간 로그 (tail -f처럼)
kubectl logs -f <pod이름>

# 이전 크래시 로그 (CrashLoopBackOff일 때)
kubectl logs <pod이름> --previous

# Pod 안에 접속
kubectl exec -it <pod이름> -- /bin/sh

# Pod 상태/이벤트 확인 (왜 안 뜨는지 원인 파악)
kubectl describe pod <pod이름>

# 리소스 사용량 (metrics-server 필요)
kubectl top pods
kubectl top nodes

배포 계열

# 롤링 업데이트
kubectl set image deployment/<이름> <컨테이너>=<새이미지>

# 롤백
kubectl rollout undo deployment/<이름>

# 스케일링
kubectl scale deployment/<이름> --replicas=<수>

# 재시작 (이미지 그대로, Pod만 재생성)
kubectl rollout restart deployment/<이름>

자동완성과 축약어

# 자동완성 설정 (매번 긴 이름 안 쳐도 됨)
source <(kubectl completion zsh)

# 축약어 사용
kubectl get po        # pods
kubectl get svc       # services
kubectl get deploy    # deployments
kubectl get ns        # namespaces
kubectl get no        # nodes

# 라벨로 필터링
kubectl get pods -l app=web

# 여러 리소스 한번에 보기
kubectl get pods,services,deployments

관련 포스트

Helm 차트 관리와 Ingress 설정, K8s 트러블슈팅 방법 Helm으로 패키지 관리하는 법, Ingress Controller 설정, Pod가 안 뜰 때 확인하는 디버 … Kubernetes Probe, HPA, RBAC — 상태 점검, 오토스케일링, 접근 제어 헬스체크(Probe), 리소스 요청/제한, 오토스케일링(HPA), 무중단 배포, 접근 제어(RBAC)까지. …