[카테고리:] 미분류

  • 쿠버네티스 운영

    주제: 오토스케일링(HPA/KEDA), 롤아웃, Mesh, PDB, 비용 최적화


    • 스케일링 삼총사: HPA(v2) + KEDA(이벤트/큐) + Cluster Autoscaler/Karpenter(노드)
    • 안정성: PDB + Readiness/StartupProbe + PodPriority/Preemption + TopologySpread
    • 롤아웃: Argo Rollouts(카나리/블루그린) + 자동 분석(p95/에러율)
    • 메시(선택): Istio/Linkerd로 mTLS, 재시도, 타임아웃, 아웃라이어 제거
    • 비용: 요청값 현실화(관측 기반), 온디맨드+스팟 혼합, ARM(Graviton) 풀, 이미지 슬림화

    1) 리소스·프로브·QoS — “죽지 않고 잘 돈다”의 기본

    요청/한도(Req/Lmt) 규칙

    • vCPU 요청= p95 사용량(관측치) ± 여유 15~25%
    • 메모리 요청= p95 (OOM 방지), 한도는 요청=한도 또는 한도 미설정(스로틀링 회피)
    resources:
      requests: { cpu: "200m", memory: "256Mi" }
      limits:   { cpu: "500m", memory: "256Mi" }  # 메모리는 equal 권장
    

    프로브

    livenessProbe:  { httpGet: { path: /healthz, port: 8000 }, periodSeconds: 10 }
    readinessProbe: { httpGet: { path: /readyz,  port: 8000 }, periodSeconds: 5, timeoutSeconds: 2 }
    startupProbe:   { httpGet: { path: /healthz, port: 8000 }, failureThreshold: 30, periodSeconds: 5 }
    

    QoS 클래스

    • Guaranteed(요청=한도, 메모리 동일) → OOM에 가장 강함
    • Burstable(일반) / BestEffort(지양)

    2) HPA v2 (CPU/메모리/커스텀 메트릭)

    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    spec:
      minReplicas: 2
      maxReplicas: 20
      behavior:
        scaleUp:
          stabilizationWindowSeconds: 30
          policies: [{ type: Percent, value: 100, periodSeconds: 60 }]
        scaleDown:
          stabilizationWindowSeconds: 300
          policies: [{ type: Percent, value: 50, periodSeconds: 60 }]
      metrics:
      - type: Resource
        resource: { name: cpu, target: { type: Utilization, averageUtilization: 60 } }
      - type: Resource
        resource: { name: memory, target: { type: AverageValue, averageValue: "400Mi" } }
      # 커스텀 메트릭 예: QPS
      - type: Pods
        pods:
          metric:
            name: http_requests_per_second
          target:
            type: AverageValue
            averageValue: "20"
    

    팁: Prometheus Adapter로 커스텀 메트릭(예: 요청/큐 길이) 노출.


    3) KEDA — 이벤트 기반 스케일(큐/스트림/웹훅)

    SQS 예:

    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    spec:
      scaleTargetRef: { name: worker }
      pollingInterval: 10
      cooldownPeriod: 120
      minReplicaCount: 0
      maxReplicaCount: 50
      triggers:
      - type: aws-sqs-queue
        metadata:
          queueURL: https://sqs.ap-northeast-2.amazonaws.com/123456789012/ex.fifo
          queueLength: "100"
          awsRegion: ap-northeast-2
    

    Kafka 랙 기준:

    - type: kafka
      metadata:
        bootstrapServers: kafka:9092
        consumerGroup: ex-worker
        topic: user.created
        lagThreshold: "1000"
    

    4) 노드 오토스케일: Cluster Autoscaler vs. Karpenter

    • Cluster Autoscaler(CA): 전통적, 안정. 노드그룹 단위 증감
    • Karpenter: 빠른 프로비저닝, 스팟 혼합/인스턴스타입 다양화 쉬움
      • 프로비저닝 템플릿에서 requirementsx86/ARM, on-demand/spot 혼합

    예시(개념):

    apiVersion: karpenter.sh/v1beta1
    kind: NodePool
    spec:
      template:
        spec:
          requirements:
          - key: kubernetes.io/arch
            operator: In
            values: ["arm64","amd64"]
          - key: karpenter.sh/capacity-type
            operator: In
            values: ["on-demand","spot"]
          taints: [{ key: "spot", value: "true", effect: "NoSchedule" }]
    

    5) 중단 내성: PDB, PodPriority, TopologySpread

    PodDisruptionBudget(PDB)

    apiVersion: policy/v1
    kind: PodDisruptionBudget
    spec:
      minAvailable: 2     # 또는 maxUnavailable: 1
      selector: { matchLabels: { app: api } }
    

    우선순위/선점

    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata: { name: critical-svc }
    value: 100000
    globalDefault: false
    
    spec:
      priorityClassName: critical-svc
    

    토폴로지 분산

    topologySpreadConstraints:
    - maxSkew: 1
      topologyKey: topology.kubernetes.io/zone
      whenUnsatisfiable: ScheduleAnyway
      labelSelector: { matchLabels: { app: api } }
    

    6) 롤아웃: Argo Rollouts(요지)

    카나리 + 자동 분석(9편 참고)을 prod 기본값으로:

    strategy:
      canary:
        canaryService: api-canary
        stableService: api
        trafficRouting:
          istio: { virtualService: { name: api-vs, routes: ["primary"] } }
        steps:
        - setWeight: 10
        - pause: { duration: 2m }
        - analysis: { templates: [{ templateName: apislo }] }
        - setWeight: 50
        - pause: { duration: 3m }
        - analysis: { templates: [{ templateName: apislo }] }
        - setWeight: 100
    

    7) 서비스 메시(옵션이지만 강력)

    Istio/Linkerd 핵심 설정(게이트웨이와 중복 조정):

    • mTLS: 서비스간 암호화/신뢰
    • 재시도/타임아웃: 멱등 GET만 재시도, 쓰기는 금지
    • Outlier Detection: 불량 인스턴스 자동 제외

    Istio VirtualService 예:

    spec:
      http:
      - route:
        - destination: { host: api.default.svc.cluster.local, subset: v1, weight: 90 }
        - destination: { host: api.default.svc.cluster.local, subset: v2, weight: 10 }
        retries: { attempts: 2, perTryTimeout: 1s, retryOn: "5xx,connect-failure,refused-stream" }
        timeout: 5s
    

    8) 스토리지/네트워킹 운영 팁

    • PVC: IOPS/처리량 계층 인지(General SSD vs. io2 등). 로그/캐시는 디스크 의존 최소화
    • 네트워크: ENI/Pod IP 고갈 주의, 노드당 최대 파드 수 확인
    • Ingress: NLB(4계층) vs ALB(7계층) 장단점 파악, gRPC면 NLB+Envoy가 단순

    9) 비용 최적화 플레이북

    1. 요청값 다운: 관측 기반으로 p95 맞추기(과도한 여유분 제거)
    2. 스팟 혼합: 워커/비핵심은 스팟+PDB+재시도/큐로 내성 확보
    3. ARM 전환: CPU 요금↓, Python/Node 호환 OK(이미지 멀티아치)
    4. 오토스케일 정책: scaleDown 빠르게(안정화창 5~10분), 워커는 0까지
    5. 이미지 다이어트: python:slim/node:alpine, readOnlyRootFS → 디스크 IO↓
    6. 로깅 비용: 샘플링/드롭(헬스체크, 디버그), 보존 기간 차등

    10) 장애 런북(요지)

    • CPU Throttle: container_cpu_cfs_throttled_seconds_total↑ → 한도 제거/상향, 코드 핫스팟
    • OOMKill: oom_killed=1 → 메모리 한도=요청, 누수/캐시 튜닝, 이미지 최적화
    • Evicted(디스크/노드압박): 노드 디스크/인노드/메모리 확인 → 노드 확장, 로그/캐시 정책 수정
    • PodPending: 자원부족/스케줄러 조건 → 요청값↓, 우선순위/토폴로지 조정, 노드 증설
    • Cold Start(Edge/Node 혼합): 런타임 분리, startupProbe 완화, 롤링 Surge 증가

    11) 48시간 액션 플랜

    • 상위 3개 워크로드에 HPA v2 도입(behavior 포함)
    • 워커에 KEDA 적용(SQS/Kafka 트리거) + minReplicaCount: 0
    • PDB + TopologySpread 적용으로 배포/장애 내성 확보
    • PriorityClass 생성해 핵심/비핵심 분리, 스팟 전용 노드 풀에 taint 부여
    • 프로브/리소스 요청 재설정(p95 기반), OOM/Throttle 대시보드 구성

    12) 2주 액션 플랜

    1. Karpenter(또는 CA)로 스팟 혼합·다양 인스턴스 자동화
    2. Argo Rollouts 전면 적용 + 분석 템플릿(p95/에러율) 표준화
    3. 메시(또는 게이트웨이)로 재시도/타임아웃/아웃라이어 정책 일원화
    4. ARM 노드 풀 PoC 및 멀티아치 이미지 파이프라인 추가
    5. 비용 리포트(월별) 자동 생성: 노드 타입/네임스페이스/워크로드별 분해

    13) “복붙” 모음

    A. Prometheus Adapter(커스텀 메트릭 선언)

    rules:
    - seriesQuery: 'http_requests_total{namespace!="",pod!=""}'
      resources: { overrides: { namespace: { resource: "namespace" }, pod: { resource: "pod" } } }
      name: { matches: "http_requests_total", as: "http_requests_per_second" }
      metricsQuery: 'sum(rate(http_requests_total{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)'
    

    B. 워커 배포 with KEDA + PDB

    apiVersion: apps/v1
    kind: Deployment
    metadata: { name: worker }
    spec:
      replicas: 0
      selector: { matchLabels: { app: worker } }
      template:
        metadata: { labels: { app: worker } }
        spec:
          tolerations: [{ key: "spot", operator: "Equal", value: "true", effect: "NoSchedule" }]
          containers:
          - name: worker
            image: ghcr.io/org/repo/worker:main
            resources: { requests: { cpu: "50m", memory: "128Mi" }, limits: { cpu: "1", memory: "256Mi" } }
    ---
    apiVersion: policy/v1
    kind: PodDisruptionBudget
    metadata: { name: worker-pdb }
    spec:
      maxUnavailable: 1
      selector: { matchLabels: { app: worker } }
    

    C. Descheduler(노드 균형·비용) 기본

    apiVersion: apps/v1
    kind: Deployment
    spec:
      template:
        spec:
          containers:
          - name: descheduler
            args: ["--policy-config-file=/policy.yaml","--descheduling-interval=10m"]
    

    마무리

    쿠버네티스 운영의 핵심은 **“스케일·내성·비용”**의 균형입니다.
    HPA/KEDA/노드 오토스케일을 맞물리게 하고, PDB/프로브/토폴로지로 안전한 롤링을 보장하며, 관측 데이터로 요청값을 주기적으로 다이어트하세요.

    다음은 11편. 보안·컴플라이언스 — 비밀관리, 암호화, PII, ISMS-P/개인정보보호법 대응으로 이어갈게요.