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

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

Cloud de Confiance 콘솔, kubectl 명령줄 도구, Cloud Logging, Cloud Monitoring을 함께 사용하여 OutOfMemory(OOMKilled) 오류의 근본 원인을 식별하는 안내 예시를 따라가 보세요.

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

시나리오

당신은 GKE에서 실행되는 product-catalog라는 웹 앱을 담당하는 긴급 대기 엔지니어입니다.

조사는 Cloud Monitoring에서 자동 알림을 수신하면서 시작됩니다.

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

이 알림은 문제가 발생했음을 알려주며, 해당 문제가 product-catalog 워크로드와 관련되어 있음을 나타냅니다.

Cloud de Confiance 콘솔에서 문제 확인

문제를 확인하기 위해 워크로드의 개요부터 살펴봅니다.

  1. Cloud de Confiance 콘솔에서 워크로드 페이지로 이동한 후 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. 상세 이벤트 기록을 확인하기 위해 불안정한 포드에 대해 describe 명령을 실행합니다.

    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로 종료되었다고 표시됩니다. 이는 메모리가 부족해 종료되었다는 의미입니다. 이 이유는 Exit Code: 137을 통해 확인되는데, 이는 과도한 메모리 사용으로 인해 프로세스가 종료될 때 사용되는 표준 Linux 종료 코드입니다.
    • 두 번째로, Events 섹션에는 Warning: BackOff 이벤트가 표시되며, 메시지는 Back-off restarting failed container입니다. 이 메시지는 컨테이너가 실패 루프에 빠졌음을 나타내며, 이는 앞서 확인한 CrashLoopBackOff 상태의 직접적인 원인입니다.

측정항목으로 동작 시각화

kubectl describe 명령어는 발생한 상황을 알려주지만 Cloud Monitoring은 시간이 지남에 따라 환경이 어떻게 동작했는지를 보여줍니다.

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

차트에는 뚜렷한 패턴이 나타납니다. 메모리 사용량이 꾸준히 증가하다가, 컨테이너가 OOMKilled로 종료되고 다시 시작될 때 갑자가 0으로 떨어집니다. 이러한 시각적 증거는 메모리 누수 또는 메모리 제한 부족을 시사합니다.

로그에서 근본 원인 찾기

이제 컨테이너가 메모리가 부족해지고 있다는 사실은 알게 되었지만, 정확한 원인은 여전히 알 수 없습니다. 근본 원인을 찾기 위해 로그 탐색기를 사용합니다.

  1. Cloud de Confiance 콘솔에서 로그 탐색기로 이동합니다.
  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"
    }
    

이 로그 항목들은 앱이 대용량 이미지 파일을 메모리에 전체 로드하여 처리하려 하고 있으며, 이로 인해 결국 컨테이너의 메모리 제한이 초과된다는 사실을 알려줍니다.

결과

도구들을 함께 사용함으로써 문제를 종합적으로 파악할 수 있습니다.

  • 모니터링 알림을 통해 문제가 발생했음을 알게 되었습니다.
  • Cloud de Confiance 콘솔에서는 이 문제가 사용자에게 영향을 미치고 있음(다시 시작 발생)을 확인할 수 있었습니다.
  • kubectl 명령어를 통해 다시 시작의 정확한 원인(OOMKilled)를 확인했습니다.
  • 측정항목 탐색기는 시간이 지남에 따라 메모리 누수 패턴을 시각화했습니다.
  • 로그 탐색기는 메모리 문제를 유발한 구체적인 동작을 밝혀냈습니다.

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

다음 단계

  • 특정 문제를 해결하기 위한 안내가 필요하다면 GKE 문제 해결 가이드를 참조하세요.

  • 문서에서 문제 해결 방법을 찾을 수 없으면 지원 받기를 참조하여 다음 주제에 대한 조언을 포함한 추가 도움을 요청하세요.