총정리: 문제 해결 시나리오 예


Google Kubernetes Engine (GKE)의 개별 문제 해결 도구를 이해하는 것도 도움이 되지만, 실제 문제를 해결하기 위해 함께 사용되는 것을 보면 지식을 확실하게 다질 수 있습니다.

Google Cloud 콘솔, kubectl 명령줄 도구, Cloud Logging, Cloud Monitoring을 함께 사용하여 OutOfMemory (OOMKilled) 오류의 근본 원인을 식별하는 안내 예시를 따릅니다.

이 예는 이 시리즈에 설명된 문제 해결 기법의 실제 적용을 확인하려는 모든 사용자, 특히 플랫폼 관리자 및 운영자, 애플리케이션 개발자에게 유용합니다.Google Cloud 콘텐츠에서 참조하는 일반적인 역할과 예시 태스크에 대한 자세한 내용은 일반 GKE 사용자 역할 및 태스크를 참고하세요.

시나리오

GKE에서 실행되는 product-catalog이라는 웹 앱의 당직 엔지니어입니다.

Cloud Monitoring에서 자동 알림을 받으면 조사가 시작됩니다.

Alert: High memory utilization for container 'product-catalog' in 'prod' cluster.

이 알림은 문제가 있음을 알려주고 문제와 product-catalog 워크로드 간에 관련성이 있음을 나타냅니다.

Google Cloud 콘솔에서 문제 확인

워크로드의 개략적인 보기를 통해 문제를 확인합니다.

  1. Google Cloud 콘솔에서 워크로드 페이지로 이동하여 product-catalog 워크로드를 필터링합니다.
  2. 포드 상태 열을 확인합니다. 정상적인 3/3 대신 값이 비정상 상태를 꾸준히 보여줍니다(2/3). 이 값은 앱의 포드 중 하나의 상태가 Ready이 아님을 나타냅니다.
  3. 추가 조사를 위해 product-catalog 워크로드의 이름을 클릭하여 세부정보 페이지로 이동합니다.
  4. 세부정보 페이지에서 관리 포드 섹션을 확인합니다. 문제를 즉시 파악합니다. 포드의 Restarts 열에 비정상적으로 높은 수치인 14이 표시됩니다.

다시 시작 횟수가 많다는 것은 이 문제로 인해 앱이 불안정해지고 컨테이너가 상태 점검에 실패하거나 비정상 종료된다는 것을 의미합니다.

kubectl 명령어로 이유 찾기

앱이 반복적으로 다시 시작된다는 것을 알았으므로 그 이유를 알아내야 합니다. kubectl describe 명령어가 이 작업에 적합한 도구입니다.

  1. 불안정한 포드의 정확한 이름을 가져옵니다.

    kubectl get pods -n prod
    

    출력은 다음과 같습니다.

    NAME                             READY  STATUS            RESTARTS  AGE
    product-catalog-d84857dcf-g7v2x  0/1    CrashLoopBackOff  14        25m
    product-catalog-d84857dcf-lq8m4  1/1    Running           0         2h30m
    product-catalog-d84857dcf-wz9p1  1/1    Running           0         2h30m
    
  2. 불안정한 포드를 설명하여 자세한 이벤트 기록을 가져옵니다.

    kubectl describe pod product-catalog-d84857dcf-g7v2x -n prod
    
  3. 출력을 검토하고 Last StateEvents 섹션에서 단서를 찾습니다.

    Containers:
      product-catalog-api:
        ...
        State:          Waiting
          Reason:       CrashLoopBackOff
        Last State:     Terminated
          Reason:       OOMKilled
          Exit Code:    137
          Started:      Mon, 23 Jun 2025 10:50:15 -0700
          Finished:     Mon, 23 Jun 2025 10:54:58 -0700
        Ready:          False
        Restart Count:  14
    ...
    Events:
      Type     Reason     Age                           From                Message
      ----     ------     ----                          ----                -------
      Normal   Scheduled  25m                           default-scheduler   Successfully assigned prod/product-catalog-d84857dcf-g7v2x to gke-cs-cluster-default-pool-8b8a777f-224a
      Normal   Pulled     8m (x14 over 25m)             kubelet             Container image "us-central1-docker.pkg.dev/my-project/product-catalog/api:v1.2" already present on machine
      Normal   Created    8m (x14 over 25m)             kubelet             Created container product-catalog-api
      Normal   Started    8m (x14 over 25m)             kubelet             Started container product-catalog-api
      Warning  BackOff    3m (x68 over 22m)             kubelet             Back-off restarting failed container
    

    출력에서 두 가지 중요한 단서를 확인할 수 있습니다.

    • 먼저 Last State 섹션에는 컨테이너가 Reason: OOMKilled로 종료되었다고 표시되어 메모리가 부족했음을 알 수 있습니다. 이 이유는 과도한 메모리 사용으로 인해 종료된 프로세스의 표준 Linux 종료 코드인 Exit Code: 137에 의해 확인됩니다.
    • 두 번째로 Events 섹션에는 메시지 Back-off restarting failed container가 포함된 Warning: BackOff 이벤트가 표시됩니다. 이 메시지는 컨테이너가 실패 루프에 있음을 확인해 주며, 이는 앞서 본 CrashLoopBackOff 상태의 직접적인 원인입니다.

측정항목으로 동작 시각화

kubectl describe 명령어는 발생한 상황을 알려주지만 Cloud Monitoring은 시간 경과에 따른 환경의 동작을 보여줄 수 있습니다.

  1. Google Cloud 콘솔에서 측정항목 탐색기로 이동합니다.
  2. container/memory/used_bytes 측정항목을 선택합니다.
  3. 출력을 특정 클러스터, 네임스페이스, 포드 이름으로 필터링합니다.

차트에는 명확한 패턴이 표시됩니다. 메모리 사용량이 꾸준히 증가하다가 컨테이너가 OOM으로 종료되고 다시 시작되면 갑자기 0으로 떨어집니다. 이 시각적 증거는 메모리 누수 또는 메모리 제한 부족을 확인합니다.

로그에서 근본 원인 찾기

이제 컨테이너의 메모리가 부족하다는 것을 알지만 정확한 이유는 아직 알 수 없습니다. 근본 원인을 파악하려면 로그 탐색기를 사용하세요.

  1. Google Cloud 콘솔에서 로그 탐색기로 이동합니다.
  2. 마지막 비정상 종료 시간 (kubectl describe 명령의 출력에 표시됨) 바로 전의 특정 컨테이너 로그를 필터링하는 쿼리를 작성합니다.

    resource.type="k8s_container"
    resource.labels.cluster_name="example-cluster"
    resource.labels.namespace_name="prod"
    resource.labels.pod_name="product-catalog-d84857dcf-g7v2x"
    timestamp >= "2025-06-23T17:50:00Z"
    timestamp < "2025-06-23T17:55:00Z"
    
  3. 로그에서 각 비정상 종료 직전에 반복되는 메시지 패턴을 확인할 수 있습니다.

    {
      "message": "Processing large image file product-image-large.jpg",
      "severity": "INFO"
    },
    {
      "message": "WARN: Memory cache size now at 248MB, nearing limit.",
      "severity": "WARNING"
    }
    

이러한 로그 항목은 앱이 큰 이미지 파일을 메모리에 완전히 로드하여 처리하려고 시도하고 있으며, 결국 컨테이너의 메모리 한도가 소진됨을 나타냅니다.

발견 사항

이 두 도구를 함께 사용하면 문제에 대한 완전한 그림을 그릴 수 있습니다.

  • 모니터링 알림을 통해 문제가 있음을 알렸습니다.
  • Google Cloud 콘솔에 문제가 사용자에게 영향을 미치고 있음 (다시 시작)이 표시되었습니다.
  • kubectl 명령어는 다시 시작의 정확한 이유(OOMKilled)를 지적했습니다.
  • 측정항목 탐색기에서 시간 경과에 따른 메모리 누수 패턴을 시각화했습니다.
  • 로그 탐색기를 통해 메모리 문제를 일으키는 구체적인 동작이 확인되었습니다.

이제 솔루션을 구현할 준비가 되었습니다. 앱 코드를 최적화하여 큰 파일을 더 효율적으로 처리하거나, 단기 해결책으로 워크로드의 YAML 매니페스트에서 컨테이너의 메모리 제한 (특히 spec.containers.resources.limits.memory 값)을 늘릴 수 있습니다.

다음 단계