k8s 이론 공부

Part 5 — 운영과 확장

Ai와 함께 공부하자 2026. 4. 2. 16:46
728x90
반응형

Chapter 24. RBAC — 누가 무엇을 있는가

용어: RBAC(Role-Based Access Control) — 역할 기반 접근 제어. 사용자나 서비스 계정에게 역할(Role)을 부여하고, 역할에 권한을 정의하는 방식이다.

* RBAC의 핵심 4가지 리소스

1) Role: 특정 네임스페이스 안에서의 권한 정의.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: production
rules:
  - apiGroups: [""]           # 코어 API 그룹 (Pod, Service 등)
    resources: ["pods"]       # 대상 리소스
    verbs: ["get", "list", "watch"]   # 허용하는 동작

2) ClusterRole: 클러스터 전체에 적용되는 권한.

3) RoleBinding: Role 사용자/그룹/서비스계정에 연결.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: production
subjects:
  - kind: User
    name: jane
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

4) ClusterRoleBinding: ClusterRole 연결.

* ServiceAccount

용어: ServiceAccount — Pod 안의 프로세스가 API 서버에 접근할 때 사용하는 신원이다. 사람이 아닌 프로그램용 계정이라고 생각하면 된다.
apiVersion: v1
kind: ServiceAccount
metadata:
  name: monitoring-sa
  namespace: production

모든 Pod 기본적으로 default ServiceAccount 사용한다. 보안을 위해 필요한 최소 권한만 가진 ServiceAccount 별도로 만들어 사용하는 것이 좋다.

 


 

Chapter 25. ResourceQuota LimitRange

* ResourceQuota — 네임스페이스별 자원 한도

용어: ResourceQuota — 네임스페이스가 사용할 수 있는 전체 자원의 상한선을 설정한다.
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: development
spec:
  hard:
    requests.cpu: "4"           # 이 네임스페이스의 모든 Pod의 CPU requests 합이 4코어 이하
    requests.memory: 8Gi        # 메모리 requests 합이 8Gi 이하
    limits.cpu: "8"             # CPU limits 합이 8코어 이하
    limits.memory: 16Gi         # 메모리 limits 합이 16Gi 이하
    pods: "20"                  # Pod 최대 20개
    services: "10"              # Service 최대 10개

* LimitRange — Pod/Container 단위 기본값과 제한

용어: LimitRange — 네임스페이스 안에서 개별 Pod이나 컨테이너가 요청할 수 있는 자원의 기본값과 최소/최대를 설정한다.
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-mem-limit
  namespace: development
spec:
  limits:
    - type: Container
      default:                     # limits 기본값 (명시하지 않으면 이 값 적용)
        cpu: "500m"
        memory: "256Mi"
      defaultRequest:              # requests 기본값
        cpu: "100m"
        memory: "128Mi"
      max:                         # 최대값
        cpu: "2"
        memory: "2Gi"
      min:                         # 최소값
        cpu: "50m"
        memory: "64Mi"

ResourceQuota 네임스페이스전체 한도라면, LimitRange개별컨테이너의 한도다.

 


 

Chapter 26. HPA VPA — 오토스케일링

* HPA — 수평 확장/축소

용어: HPA(Horizontal Pod Autoscaler) — Pod의 CPU 사용률, 메모리 사용률, 또는 사용자 정의 메트릭을 기반으로 Pod의 수(replicas)를 자동으로 늘리거나 줄이는 리소스다.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 2                    # 최소 2개
  maxReplicas: 10                   # 최대 10개
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70    # CPU 사용률 70% 기준

HPA 동작: 평균 CPU 70% 넘으면 Pod 수를 늘리고, 70% 아래로 내려가면 Pod 수를 줄인다.

필수 조건: HPA 동작하려면 Metrics Server 클러스터에 설치되어 있어야 한다. Metrics Server Pod CPU/메모리 사용량을 수집하고, HPA 데이터를 참조한다.

* VPA — 수직 확장/축소

용어: VPA(Vertical Pod Autoscaler) — Pod의 수가 아니라, 개별 Pod의 자원 할당량(requests/limits)을 자동으로 조정하는 것이다.

VPA K8s 기본 내장이 아니라 별도 설치가 필요하다. 동작 모드가 가지 있다:

  • Off: 추천값만 제공하고 적용하지 않는다 (모니터링 용도).
  • Initial: Pod이 생성될 때만 적용한다.
  • Auto: 필요하면 기존 Pod을 재시작하면서 적용한다.

주의: HPA VPA 같은 메트릭(CPU)으로 동시에 사용하면 충돌할 있다. HPA “Pod 수를 늘려라고 하고, VPA “Pod 크기를 키워라고 하면 혼란이 생긴다. 일반적으로 HPA 메인으로 쓰고, VPA 추천 모드(Off) 적절한 requests/limits 값을 파악하는 활용한다.

 


 

Chapter 27. DaemonSet — 모든 노드에 하나씩

용어: DaemonSet — 클러스터의 모든 노드(또는 특정 노드)에 Pod을 딱 하나씩 실행하는 리소스다.
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:v1.16
          volumeMounts:
            - name: varlog
              mountPath: /var/log
      volumes:
        - name: varlog
          hostPath:
            path: /var/log

DaemonSet 전형적인 사용 사례:

  • 로그 수집: 모든 노드의 로그를 수집하는 에이전트 (Fluentd, Fluent Bit)
  • 모니터링: 모든 노드의 메트릭을 수집하는 에이전트 (Prometheus Node Exporter, WhaTap 에이전트)
  • 네트워크: CNI 플러그인, kube-proxy도 사실 DaemonSet으로 돌아간다
  • 스토리지: 분산 스토리지 클라이언트

노드가 클러스터에 추가되면 자동으로 해당 노드에도 DaemonSet Pod 생성된다. 노드가 제거되면 해당 Pod 삭제된다.

 


 

Chapter 28. StatefulSet — 상태가 있는 애플리케이션

용어: StatefulSet — 상태가 있는(Stateful) 애플리케이션을 관리하기 위한 리소스다. Deployment와 비슷하지만 중요한 차이점이 있다.

* Deployment vs StatefulSet

Deployment 관리하는 Pod이름 없는 일꾼이다. pod-abc123, pod-def456 같은 랜덤 이름이 붙고, 서로 구분할 필요가 없다. 웹서버처럼 어떤 Pod이든 같은 응답을 하는 Stateless 적합하다.

StatefulSet 다르다:

  • 고정된 순서와 이름: Pod 이름이 mysql-0, mysql-1, mysql-2 같이 순번이 붙는다.
  • 순서대로 생성/삭제: 0번이 먼저 생성되고 정상이 돼야 1번이 생성된다. 삭제는 역순.
  • 고유한 PVC: 각 Pod마다 자기만의 PV가 바인딩된다. Pod이 재생성되어도 같은 PV에 연결된다.
  • 안정적인 네트워크 ID: Pod이 재생성되어도 같은 DNS 이름을 가진다.
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-headless        # Headless Service 이름 (필수)
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          ports:
            - containerPort: 3306
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:              # 각 Pod마다 PVC를 자동 생성
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: fast-ssd
        resources:
          requests:
            storage: 10Gi

* Headless Service

StatefulSet Headless Service 필요하다.

용어: Headless Service — ClusterIP가 없는(None으로 설정된) Service다. 로드밸런싱을 하지 않고, 각 Pod에 직접 접근할 수 있는 DNS 레코드를 제공한다.
apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
spec:
  clusterIP: None                    # Headless
  selector:
    app: mysql
  ports:
    - port: 3306

이렇게 하면 Pod mysql-0.mysql-headless.default.svc.cluster.local 같은 DNS 이름이 부여된다. 특정 Pod 직접 접근해야 하는 DB 마스터/슬레이브 같은 구성에 필수다.

* 어떤 앱에 StatefulSet을 써야 하는가

  • MySQL, PostgreSQL, MongoDB 같은 데이터베이스
  • Kafka, RabbitMQ 같은 메시지 큐
  • Elasticsearch, Redis Cluster 같이 노드마다 고유한 역할이 있는 분산 시스템
  • Zookeeper, etcd 같은 분산 합의(consensus) 시스템

 


 

Chapter 29. Job CronJob — 일회성/주기적 작업

* Job — 한 번 실행하고 끝

용어: Job — 하나 이상의 Pod을 생성하여 지정된 수의 Pod이 성공적으로 종료될 때까지 관리하는 리소스다.
apiVersion: batch/v1
kind: Job
metadata:
  name: data-migration
spec:
  completions: 1                # 성공해야 하는 Pod 수
  parallelism: 1                # 동시에 실행할 Pod 수
  backoffLimit: 3               # 실패 시 최대 재시도 횟수
  activeDeadlineSeconds: 600    # 최대 실행 시간 (초)
  template:
    spec:
      containers:
        - name: migration
          image: my-migration:1.0
          command: ["python", "migrate.py"]
      restartPolicy: Never      # Job에서는 Never 또는 OnFailure만 가능

Deployment 달리 Job Pod 작업이 끝나면 종료된다. 종료된 Pod 삭제되지 않고 남아있어서 로그를 확인할 있다.

* CronJob — 주기적으로 실행

용어: CronJob — Linux의 crontab처럼 스케줄에 따라 Job을 주기적으로 실행하는 리소스다.
apiVersion: batch/v1
kind: CronJob
metadata:
  name: daily-backup
spec:
  schedule: "0 2 * * *"         # 매일 새벽 2시 (cron 문법)
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: backup
              image: backup-tool:1.0
              command: ["./backup.sh"]
          restartPolicy: OnFailure
  successfulJobsHistoryLimit: 3  # 성공한 Job 히스토리 유지 개수
  failedJobsHistoryLimit: 1      # 실패한 Job 히스토리 유지 개수

Cron 문법 빠른 참조: 요일. : 0 2 * * * = 매일 02:00, */5 * * * * = 5분마다, 0 0 * * 0 = 매주 일요일 자정.

 


 

Chapter 30. 프로브(Probe) — 컨테이너 상태 확인

K8s 컨테이너가 건강한지 가지 방법으로 확인한다.

1) livenessProbe — 살아있는가?

컨테이너가 살아있는지 확인한다. 실패하면 kubelet 컨테이너를 재시작한다.

spec:
  containers:
    - name: app
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 15     # 첫 체크까지 대기 시간
        periodSeconds: 10           # 체크 간격
        failureThreshold: 3         # 연속 3번 실패하면 재시작

2) readinessProbe — 트래픽 받을 준비가 됐는가?

컨테이너가 요청을 처리할 준비가 됐는지 확인한다. 실패하면 Service 엔드포인트에서 제외된다 (트래픽을 보내지 않는다). 컨테이너를 재시작하지는 않는다.

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

3) startupProbe — 시작됐는가?

느리게 시작하는 앱을 위한 프로브다. startupProbe 성공할 때까지 livenessProbe readinessProbe 비활성화된다.

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30          # 30번까지 실패 허용
  periodSeconds: 10             # 10초마다 → 최대 5분까지 기다림

* 프로브 방식

프로브는 가지 방식으로 실행할 있다:

  • httpGet: HTTP 요청을 보내서 2xx/3xx 응답이면 성공
  • tcpSocket: TCP 연결이 되면 성공
  • exec: 컨테이너 안에서 명령을 실행해서 종료 코드 0이면 성공

실무 : livenessProbe readinessProbe 모두 설정하자. livenessProbe 설정하면 앱이 아직 준비되지 않았는데 트래픽이 들어올 있다. readinessProbe 설정하면 앱이 교착 상태(deadlock) 빠졌을 재시작되지 않는다.

 


 

Chapter 31. Taints, Tolerations, Affinity — Pod 배치 제어

* Taints와 Tolerations

용어: Taint — 노드에 붙이는 “기피 딱지”다. Taint가 있는 노드에는 일반 Pod이 스케줄링되지 않는다.
용어: Toleration — Pod에 붙이는 “면역”이다. 특정 Taint를 용인(tolerate)하는 Pod만 해당 노드에 스케줄링된다.
# 노드에 Taint 추가
kubectl taint nodes node1 gpu=true:NoSchedule

# 이 Taint를 용인하는 Pod
spec:
  tolerations:
    - key: "gpu"
      operator: "Equal"
      value: "true"
      effect: "NoSchedule"

Effect 종류:

  • NoSchedule: 새 Pod 스케줄링 금지. 이미 있는 Pod은 그대로.
  • PreferNoSchedule: 가능하면 스케줄링하지 않지만, 다른 곳이 없으면 허용.
  • NoExecute: 새 Pod 스케줄링 금지 + 이미 있는 Pod도 퇴거(evict).

* Node Affinity — 선호하는 노드 지정

용어: Node Affinity — Pod이 특정 조건의 노드에 배치되도록 선호도를 설정하는 것이다. nodeSelector보다 표현력이 풍부하다.
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:   # 반드시 (hard)
        nodeSelectorTerms:
          - matchExpressions:
              - key: disk-type
                operator: In
                values: ["ssd"]
      preferredDuringSchedulingIgnoredDuringExecution:  # 가능하면 (soft)
        - weight: 1
          preference:
            matchExpressions:
              - key: zone
                operator: In
                values: ["az-1"]

* Pod Affinity / Anti-Affinity

  • Pod Affinity: “특정 Pod이 있는 노드에 같이 배치해줘” (예: 웹서버와 캐시를 같은 노드에)
  • Pod Anti-Affinity: “특정 Pod이 있는 노드에는 배치하지 마” (예: 같은 앱의 복제본을 다른 노드에 분산)

 


 

Chapter 32. Helm — K8s 패키지 매니저

* Helm이란?

용어: Helm — K8s 애플리케이션을 패키징, 배포, 관리하는 도구다. Linux의 apt/yum, Node.js의 npm과 비슷한 역할이다.

복잡한 (: Prometheus 모니터링 스택) Deployment, Service, ConfigMap, ServiceAccount, ClusterRole 수십 개의 YAML 파일이 필요하다. 이걸 하나하나 만들고 관리하는 고통스럽다.

Helm 이것들을 하나의 차트(Chart) 패키징한다.

# Helm으로 Prometheus 설치 (예시)
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/kube-prometheus-stack

줄이면 Prometheus, Grafana, AlertManager, Node Exporter 등이 전부 설치된다.

* Chart의 구조

my-chart/
├── Chart.yaml              # 차트 메타데이터 (이름, 버전)
├── values.yaml             # 기본 설정값
├── templates/              # K8s YAML 템플릿
│   ├── deployment.yaml
│   ├── service.yaml
│   └── configmap.yaml
└── charts/                 # 의존성 차트

values.yaml 핵심이다. 템플릿에서 {{ .Values.replicas }} 같이 참조하고, 사용자는 values.yaml 수정해서 원하는 설정으로 배포할 있다.

# values.yaml
replicas: 3
image:
  repository: nginx
  tag: "1.25"
resources:
  requests:
    cpu: 100m
    memory: 128Mi

# 커스텀 값으로 설치
helm install my-app ./my-chart -f custom-values.yaml

# 업그레이드
helm upgrade my-app ./my-chart -f custom-values.yaml

# 롤백
helm rollback my-app 1

# 삭제
helm uninstall my-app

 



Chapter 33.
모니터링 기초

* Metrics Server

K8s 내장은 아니지만 거의 필수인 컴포넌트다. 노드의 kubelet에서 CPU, 메모리 사용량을 수집한다. HPA, kubectl top 명령의 데이터 소스다.

kubectl top nodes          # 노드별 자원 사용량
kubectl top pods           # Pod별 자원 사용량

Prometheus + Grafana (업계 표준)

  • Prometheus: 메트릭 수집 및 저장. Pull 방식(Prometheus가 대상에서 데이터를 가져옴)으로 동작한다.
  • Grafana: 메트릭을 시각화하는 대시보드. Prometheus 등 다양한 데이터 소스를 연결할 수 있다.

K8s 환경에서의 모니터링 구성:

Node Exporter (노드 메트릭)     ──┐
kube-state-metrics (K8s 상태)  ──┤──→ Prometheus ──→ Grafana (대시보드)
cAdvisor (컨테이너 메트릭)       ──┘         │
                                         └──→ AlertManager (알람)
  • Node Exporter: 노드의 CPU, 메모리, 디스크, 네트워크 메트릭
  • kube-state-metrics: K8s 오브젝트의 상태 (Pod 수, Deployment 상태 등)
  • cAdvisor: 컨테이너 수준의 자원 사용량 (kubelet에 내장)

실무 포인트: WhaTap 같은 상용 모니터링 도구를 쓰더라도, Prometheus 기반의 메트릭 체계를 이해하고 있으면 커스텀 메트릭 설정이나 알람 설정에 도움이 된다.

 


 

Chapter 34. 실무에서 알아두면 좋은 것들

* kubectl 자주 쓰는 팁

# 컨텍스트/네임스페이스 관리
kubectl config get-contexts                      # 사용 가능한 컨텍스트 목록
kubectl config use-context my-cluster             # 컨텍스트 전환
kubectl config set-context --current --namespace=production  # 기본 네임스페이스 변경

# 디버깅
kubectl describe pod 이름           # 이벤트, 상태 상세
kubectl logs 이름 -c 컨테이너명     # 멀티컨테이너 Pod에서 특정 컨테이너 로그
kubectl logs 이름 --previous         # 이전(죽은) 컨테이너의 로그
kubectl get events --sort-by=.metadata.creationTimestamp   # 이벤트 시간순 정렬

# 리소스 확인
kubectl explain deployment.spec.strategy   # 특정 필드의 문서 확인
kubectl api-resources                       # 사용 가능한 리소스 종류 목록

# 빠른 YAML 생성 (dry-run으로 YAML 템플릿 뽑기)
kubectl create deployment nginx --image=nginx --dry-run=client -o yaml > deploy.yaml

* Pod이 안 뜰 때 체크리스트

  1. kubectl get pods — STATUS 확인 (Pending, CrashLoopBackOff, ImagePullBackOff 등)
  2. kubectl describe pod 이름 — Events 섹션 확인
  3. Pending: 스케줄링 실패 → 노드 자원 부족? nodeSelector/taint 문제?
  4. ImagePullBackOff: 이미지를 못 가져옴 → 이미지 이름/태그 오타? 레지스트리 접근 권한?
  5. CrashLoopBackOff: 컨테이너가 시작되자마자 죽음 → kubectl logs 이름으로 로그 확인
  6. Running인데 접속 안 됨: Service의 selector, port, targetPort 확인

 

* K8s 핵심 설계 원칙 요약

  1. 선언적 관리: 원하는 상태를 YAML로 선언하면 K8s가 맞춰준다.
  2. Reconciliation Loop: 현재 상태 → 원하는 상태 비교 → 차이 조정, 무한 반복.
  3. 모든 것이 API 객체: Pod, Service, Deployment 전부 API 서버에 등록된 객체다.
  4. 라벨과 셀렉터: 리소스 간 연결은 라벨로 한다. 이름이 아니라 라벨이다.
  5. Pod은 일시적이다: Pod에 의존하지 말고, Deployment + Service + PVC를 조합해서 안정성을 확보한다.
  6. 네임스페이스로 분리: 환경·팀·프로젝트별로 나누고, RBAC + ResourceQuota로 격리한다.

 

728x90
반응형
LIST

'k8s 이론 공부' 카테고리의 다른 글

Deployment와 rollout 이해하기  (0) 2026.04.10
부록: 핵심 용어 사전 (가나다순)  (0) 2026.04.02
Part 4 — 네트워킹과 스토리지  (0) 2026.04.02
Part 3 — 핵심 리소스  (0) 2026.04.02
Part 2 — K8s 아키텍처  (0) 2026.04.02