문제 해결


Google Kubernetes Engine(GKE) 사용 중에 문제가 발생할 경우 유용하게 활용할 수 있는 문제 해결 단계를 알아봅니다.

추가 지원이 필요하면 Cloud Customer Care에 연락합니다.

Kubernetes 리소스 디버깅

클러스터와 관련된 문제가 발생하는 경우, Kubernetes 문서의 클러스터 문제해결을 참조하세요.

애플리케이션, pod 또는 컨트롤러 객체에 문제가 있는 경우 애플리케이션 문제 해결을 참조하세요.

동일한 Virtual Private Cloud(VPC) 네트워크에 있는 Compute Engine VM 사이의 연결 또는 VPC 네트워크 피어링에 연결된 2개의 VPC 네트워크 사이의 연결과 관련된 문제가 있으면 내부 IP 주소를 사용하는 가상 머신(VM) 인스턴스 사이의 연결 문제 해결을 참조하세요.

Cloud NAT, VPC 기반 클러스터, 또는 IP 마스커레이드 에이전트를 사용하여 클러스터에서 외부 IP 주소로 트래픽을 전송할 때 패킷 손실이 발생하는 경우 GKE 클러스터에서 Cloud NAT 패킷 손실 문제 해결을 참조하세요.

kubectl 명령어로 문제 해결

kubectl 명령어를 찾을 수 없음

  1. 다음 명령어를 실행하여 kubectl 바이너리를 설치합니다.

    gcloud components update kubectl
    
  2. 설치 프로그램에서 $PATH 환경 변수를 수정하라는 메시지가 표시되면 '예'라고 답합니다. 이 변수를 수정하면 전체 파일 경로를 입력하지 않고 kubectl 명령어를 사용할 수 있습니다.

    또는 다음 줄을 ~/.bashrc(macOS에서는 ~/.bash_profile 또는 셸이 환경 변수를 저장하는 위치)에 추가합니다.

    export PATH=$PATH:/usr/local/share/google/google-cloud-sdk/bin/
    
  3. 다음 명령어를 실행하여 업데이트된 .bashrc(또는 .bash_profile) 파일을 로드합니다.

    source ~/.bashrc
    

kubectl 명령어가 'connection refused' 오류 반환

다음 명령어로 클러스터 컨텍스트를 설정합니다.

gcloud container clusters get-credentials CLUSTER_NAME

CLUSTER_NAME에 입력할 내용을 모르겠으면 다음 명령어를 사용하여 클러스터를 나열합니다.

gcloud container clusters list

kubectl 명령어 타임아웃

클러스터를 만든 후 클러스터에 kubectl 명령어를 실행하려고 하면 Unable to connect to the server: dial tcp IP_ADDRESS: connect: connection timed out 또는 Unable to connect to the server: dial tcp IP_ADDRESS: i/o timeout과 같은 오류가 반환됩니다.

이 문제는 kubectl이 클러스터 제어 영역과 통신할 수 없을 때 발생합니다.

이 문제를 해결하려면 클러스터가 설정된 컨텍스트를 확인합니다.

  1. $HOME/.kube/config로 이동하거나 kubectl config view 명령어를 실행하여 구성 파일에 클러스터 컨텍스트 및 제어 영역의 외부 IP 주소가 포함되는지 확인합니다.

  2. 클러스터 사용자 인증 정보를 설정합니다.

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=COMPUTE_LOCATION \
        --project=PROJECT_ID
    

    다음을 바꿉니다.

    • CLUSTER_NAME: 클러스터의 이름입니다.
    • COMPUTE_LOCATION: Compute Engine 위치입니다.
    • PROJECT_ID: GKE 클러스터가 생성된 프로젝트의 ID입니다.
  3. 클러스터가 비공개 GKE 클러스터인 경우 연결하려는 머신의 발신 IP가 기존 승인된 네트워크 목록에 포함되어 있는지 확인합니다. 콘솔에서 또는 다음 명령어를 실행하여 기존 승인된 네트워크를 찾을 수 있습니다.

    gcloud container clusters describe CLUSTER_NAME \
        --location=COMPUTE_LOCATION \
        --project=PROJECT_ID \
        --format "flattened(masterAuthorizedNetworksConfig.cidrBlocks[])"
    

머신의 발신 IP가 위 명령어 출력의 승인된 네트워크 목록에 포함되지 않았으면 비공개 클러스터의 제어 영역에 연결할 수 없음 또는 Cloud Shell을 사용하여 비공개 클러스터 액세스(Cloud Shell에서 연결하는 경우)의 단계를 수행합니다.

kubectl 명령어가 'failed to negotiate an api version' 오류 반환

kubectl에 사용자 인증 정보가 있는지 확인합니다.

gcloud auth application-default login

kubectl logs, attach, exec, port-forward 명령어가 응답하지 않음

이러한 명령어는 클러스터의 제어 영역이 클러스터 내 노드와 통신할 수 있어야 작동합니다. 하지만 제어 영역이 클러스터 노드와 동일한 Compute Engine 네트워크 없으므로 SSH 또는 Konnectivity 프록시 터널을 사용해서 보안 연결을 보장합니다.

GKE는 Compute Engine 프로젝트 메타데이터에 SSH 공개 키 파일을 저장합니다. Google 제공 이미지를 사용하는 모든 Compute Engine VM은 VM의 승인된 사용자 목록에 추가할 SSH 키를 위해 프로젝트의 공통 메타데이터와 인스턴스의 메타데이터를 정기적으로 확인합니다. 또한 GKE는 제어 영역의 IP 주소에서 클러스터의 각 노드로 SSH 액세스를 허용하는 방화벽 규칙을 Compute Engine 네트워크에 추가합니다.

위의 kubectl 명령어가 실행되지 않으면 API 서버가 노드와 통신하지 못할 수 있습니다. 가능한 원인을 확인합니다.

  • 클러스터에 노드가 없습니다.

    클러스터의 노드 수를 0으로 줄이면 명령어가 작동하지 않습니다.

    이를 수정하려면 적어도 노드가 하나가 되도록 클러스터의 크기를 조절합니다.

SSH

  • 네트워크의 방화벽 규칙은 제어 영역에서 SSH 액세스를 허용하지 않습니다.

    모든 Compute Engine 네트워크는 모든 IP 주소에서 SSH 액세스를 허용하는(물론 유효한 비공개 키 필요) default-allow-ssh라는 방화벽 규칙으로 생성됩니다. 또한 GKE는 특별히 클러스터의 제어 영역에서 클러스터의 노드로 SSH 액세스를 허용하는 gke-CLUSTER_NAME-RANDOM_CHARACTERS-ssh 형식의 SSH 규칙을 각 공개 클러스터에 삽입합니다. 이러한 규칙 중 어느 규칙이라도 존재하지 않으면 제어 영역에서 SSH 터널을 열 수 없습니다.

    이 문제를 해결하려면 클러스터의 모든 노드에 있는 태그를 사용하여 제어 영역의 IP 주소에서 VM으로 액세스를 허용하는 방화벽 규칙을 다시 추가합니다.

  • 프로젝트의 'ssh-keys' 공통 메타데이터 항목이 가득 찼습니다.

    'ssh-keys'라는 프로젝트의 메타데이터 항목이 최대 크기 제한에 가까워지면 GKE는 SSH 터널을 열기 위해 자체 SSH 키를 추가할 수 없습니다. 다음 명령어를 실행하면 프로젝트의 메타데이터를 표시할 수 있습니다.

    gcloud compute project-info describe [--project=PROJECT_ID]
    

    그런 다음 ssh-key 목록의 길이를 확인할 수 있습니다.

    이 문제를 해결하려면 더 이상 필요 없는 일부 SSH 키를 삭제합니다.

  • 클러스터의 VM에서 'ssh-keys' 키로 메타데이터 필드를 설정했습니다.

    VM의 노드 에이전트는 프로젝트 전체 SSH 키보다 인스턴스별 ssh-keys를 선호합니다. 따라서 특별히 클러스터 노드에 SSH 키를 설정한 경우, 프로젝트 메타데이터에 있는 제어 영역의 SSH 키가 노드에 사용되지 않습니다. 확인하려면 gcloud compute instances describe VM_NAME를 실행하고 메타데이터에서 ssh-keys 필드를 찾습니다.

    이를 수정하려면 인스턴스 메타데이터에서 인스턴스별 SSH 키를 삭제합니다.

Konnectivity 프록시

  • 다음 시스템 배포를 확인하여 클러스터에 Konnectivity 프록시가 사용되는지 확인합니다.

    kubectl get deployments konnectivity-agent --namespace kube-system
    
  • 네트워크의 방화벽 규칙은 제어 영역에 대해 Konnectivity 에이전트 액세스를 허용하지 않습니다.

    클러스터를 만들면 Konnectivity 에이전트 포드가 제어 영역에 대해 연결을 설정하고 포트 8132에서 유지보수합니다. kubectl 명령어 중 하나를 실행하면 API 서버가 이 연결을 사용해서 클러스터와 통신합니다.

    네트워크의 방화벽 규칙에 이그레스 거부 규칙이 포함된 경우 에이전트 연결을 방해할 수 있습니다. 포트 8132에서 클러스터 제어 영역에 대해 이그레스 트래픽을 허용해야 합니다. (비교를 위해 API 서버에는 443이 사용됩니다.)

  • 클러스터의 네트워크 정책kube-system 네임스페이스에서 workload 네임스페이스로의 인그레스를 차단합니다. 영향을 받는 네임스페이스에서 네트워크 정책을 찾으려면 다음 명령어를 실행합니다.

    kubectl get networkpolicy --namespace AFFECTED_NAMESPACE
    

    이 문제를 해결하려면 네트워크 정책 spec.ingress 필드에 다음을 추가합니다.

    - from:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: kube-system
        podSelector:
          matchLabels:
            k8s-app: konnectivity-agent
    

이러한 기능은 클러스터의 정상 작동에는 필요하지 않습니다. 클러스터의 네트워크를 모든 외부 액세스로부터 잠그려고 하면 이러한 기능이 작동하지 않습니다.

오류 4xx 문제 해결

GKE 클러스터에 연결할 때 인증 및 승인 오류

이 문제는 로컬 환경의 GKE 클러스터에서 kubectl 명령어를 실행할 때 발생할 수 있습니다. 명령어가 실패하고 일반적으로 HTTP 상태 코드 401(승인되지 않음)과 함께 오류 메시지가 표시됩니다.

이 문제의 원인은 다음 중 하나일 수 있습니다.

  • gke-gcloud-auth-plugin 인증 플러그인이 올바르게 설치 또는 구성되지 않았습니다.
  • 클러스터 API 서버에 연결하고 kubectl 명령어를 실행하기 위한 권한이 부족합니다.

원인을 진단하려면 다음을 수행합니다.

curl을 사용하여 클러스터에 연결

curl을 사용하면 kubectl CLI 및 gke-gcloud-auth-plugin 플러그인을 우회합니다.

  1. 환경 변수를 설정합니다.

    APISERVER=https://$(gcloud container clusters describe CLUSTER_NAME --location=COMPUTE_LOCATION --format "value(endpoint)")
    TOKEN=$(gcloud auth print-access-token)
    
  2. 액세스 토큰이 유효한지 확인합니다.

    curl https://oauth2.googleapis.com/tokeninfo?access_token=$TOKEN
    
  3. API 서버에서 핵심 API 엔드포인트에 연결할 수 있는지 확인합니다.

    gcloud container clusters describe CLUSTER_NAME --location=COMPUTE_LOCATION --format "value(masterAuth.clusterCaCertificate)" | base64 -d > /tmp/ca.crt
    curl -s -X GET "${APISERVER}/api/v1/namespaces" --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt
    

curl 명령어가 다음과 비슷한 출력과 함께 실패하면 클러스터에 액세스할 수 있는 올바른 권한이 있는지 확인합니다.

{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}

curl 명령어가 성공하면 플러그인이 원인인지 확인합니다.

kubeconfig에서 플러그인 구성

다음 단계에서는 클러스터에 인증할 때 gke-gcloud-auth-plugin 바이너리를 무시하도록 로컬 환경을 구성합니다. 버전 1.25 이상을 실행하는 Kubernetes 클라이언트에서는 gke-gcloud-auth-plugin 바이너리가 필수입니다. 따라서 플러그인을 필요로 하지 않고 클러스터에 액세스하려면 다음 단계를 수행합니다.

  1. curl을 사용하여 kubectl CLI 버전 1.24를 설치합니다.

    curl -LO https://dl.k8s.io/release/v1.24.0/bin/linux/amd64/kubectl
    

    kubectl CLI 버전 1.24 이하를 사용할 수 있습니다.

  2. 텍스트 편집기에서 Bash 셸에 대한 .bashrc와 같은 셸 시작 스크립트 파일을 엽니다.

    vi ~/.bashrc
    
  3. 다음 줄을 파일에 추가하고 저장합니다.

    export USE_GKE_GCLOUD_AUTH_PLUGIN=False
    
  4. 시작 스크립트를 실행합니다.

    source ~/.bashrc
    
  5. .kube/config 파일을 설정하는 클러스터의 사용자 인증 정보를 가져옵니다.

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=COMPUTE_LOCATION
    

    다음을 바꿉니다.

  6. kubectl 명령어를 실행합니다.

    kubectl cluster-info
    

401 오류 또는 비슷한 승인 오류가 발생하면 작업 수행에 올바른 권한이 있는지 확인합니다.

오류 400: 노드 풀에 다시 만들기 필요

진행 중인 사용자 인증 정보 순환을 완료할 때와 같이 제어 영역 및 노드를 다시 만드는 작업을 수행하려고 시도하면 다음 문제가 발생합니다.

GKE가 클러스터에 노드 풀을 하나 이상 다시 만들지 않았기 때문에 작업이 실패합니다. 백엔드에서 노드 풀이 다시 만들도록 표시되었지만 실제 다시 만들기 작업이 시작되려면 일부 시간이 걸릴 수 있습니다.

오류 메시지는 다음과 비슷합니다.

ERROR: (gcloud.container.clusters.update) ResponseError: code=400, message=Node pool "test-pool-1" requires recreation.

이 문제를 해결하려면 다음 중 한 가지를 따르세요.

  • 다시 만들기가 수행될 때까지 기다립니다. 기존 유지보수 기간 및 제외 항목과 같은 요소에 따라 몇 시간, 며칠, 몇 주가 걸릴 수 있습니다.
  • 제어 영역과 동일한 버전으로 버전 업그레이드를 시작하여 영향을 받는 노드 풀 다시 만들기를 수동으로 시작합니다. 다시 만들기를 시작하려면 다음 명령어를 실행합니다.

    gcloud container clusters upgrade CLUSTER_NAME \
        --node-pool=POOL_NAME
    

    업그레이드가 완료된 후 작업을 다시 시도합니다.

오류 403: 권한 부족

gcloud container clusters get-credentials를 사용하여 GKE 클러스터에 연결을 시도하지만 계정에 Kubernetes API 서버에 액세스할 수 있는 권한이 없을 때 다음 오류가 발생합니다.

ERROR: (gcloud.container.clusters.get-credentials) ResponseError: code=403, message=Required "container.clusters.get" permission(s) for "projects/<your-project>/locations/<region>/clusters/<your-cluster>".

이 문제를 해결하려면 다음 단계를 따르세요.

  1. 액세스 문제가 있는 계정을 식별합니다.

    gcloud auth list
    
  2. Kubernetes API 서버에 인증의 안내에 따라 계정에 필요한 액세스 권한을 부여합니다.

오류 404: gcloud container 명령어를 호출할 때 리소스를 '찾을 수 없음'

Google Cloud CLI에 다시 인증합니다.

gcloud auth login

오류 400/403: 계정에 수정 권한 없음

Compute Engine 기본 서비스 계정, Google API 서비스 에이전트, GKE와 연결된 서비스 계정이 수동으로 삭제되었거나 수정되었습니다.

Compute Engine 또는 Kubernetes Engine API를 사용 설정하면 Google Cloud가 다음 서비스 계정 및 에이전트를 만듭니다.

  • 프로젝트에 대해 수정 권한이 있는 Compute Engine 기본 서비스 계정
  • 프로젝트에 대해 수정 권한이 있는 Google API 서비스 에이전트
  • 프로젝트에 대해 Kubernetes Engine 서비스 에이전트 역할이 있는 Google Kubernetes Engine 서비스 계정

특정 시점에 이러한 권한을 수정하거나, 프로젝트에서 역할 바인딩을 삭제하거나, 서비스 계정을 완전히 삭제하거나, API를 사용 중지하면 클러스터 만들기 및 모든 관리 기능이 실패합니다.

Google Kubernetes Engine 서비스 계정의 이름은 다음과 같습니다. 여기서 PROJECT_NUMBER프로젝트 번호입니다.

service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com

다음 명령어를 사용해서 Google Kubernetes Engine 서비스 계정에 프로젝트에 할당된 Kubernetes Engine 서비스 에이전트 역할이 있는지 확인할 수 있습니다.

gcloud projects get-iam-policy PROJECT_ID

PROJECT_ID를 프로젝트 ID로 바꿉니다.

Google Kubernetes Engine 서비스 계정에서 Kubernetes Engine 서비스 에이전트 역할을 삭제한 경우 문제를 해결하려면 이를 다시 추가합니다. 그렇지 않으면 Kubernetes Engine API를 다시 사용 설정할 수 있습니다. 그러면 서비스 계정과 권한이 올바르게 복원됩니다.

콘솔

  1. Google Cloud 콘솔의 API 및 서비스 페이지로 이동합니다.

    API 및 서비스로 이동

  2. 프로젝트를 선택합니다.

  3. API 및 서비스 사용 설정을 클릭합니다.

  4. Kubernetes를 검색한 후 검색 결과에서 API를 선택합니다.

  5. 사용 설정을 클릭합니다. 이전에 API를 사용 설정했으면 먼저 API를 중지했다가 다시 사용 설정해야 합니다. API와 관련 서비스가 사용 설정되는 데 몇 분 정도 걸릴 수 있습니다.

gcloud

gcloud CLI에서 다음 명령어를 실행하여 서비스 계정을 다시 추가합니다.

PROJECT_NUMBER=$(gcloud projects describe "PROJECT_ID" --format 'get(projectNumber)')
gcloud projects add-iam-policy-binding PROJECT_ID \
 --member "serviceAccount:service-${PROJECT_NUMBER?}@container-engine-robot.iam.gserviceaccount.com" \
 --role roles/container.serviceAgent

GKE 클러스터 연결 문제 해결

CONDITION_NOT_MET 오류: constraints/compute.vmExternalIpAccess 제약 조건 위반

조직 정책 제약 조건 constraints/compute.vmExternalIpAccessDeny All로 구성되었거나 공개 GKE 클러스터를 만들려고 시도 중인 조직, 폴더, 프로젝트 수준에서 특정 VM 인스턴스로 외부 IP를 제한하도록 구성되었습니다.

공개 GKE 클러스터를 만들면 이 클러스터의 워커 노드를 구성하는 기본 Compute Engine VM에 외부 IP 주소가 할당됩니다. 조직 정책 제약조건 constraints/compute.vmExternalIpAccessDeny All로 구성하거나 특정 VM 인스턴스로 외부 IP를 제한하도록 구성하면 정책에 따라 GKE 워커 노드가 외부 IP 주소를 가져오지 못하도록 방지되어 클러스터 만들기 오류가 발생합니다.

클러스터 만들기 작업 로그를 찾으려면 로그 탐색기를 사용해서 다음과 비슷한 검색어로 GKE 클러스터 작업 감사 로그를 검토할 수 있습니다.

resource.type="gke_cluster"
logName="projects/test-last-gke-sa/logs/cloudaudit.googleapis.com%2Factivity"
protoPayload.methodName="google.container.v1beta1.ClusterManager.CreateCluster"
resource.labels.cluster_name="CLUSTER_NAME"
resource.labels.project_id="PROJECT_ID"

이 문제를 해결하기 위해서는 GKE 공개 클러스터를 만들려고 시도 중인 프로젝트에서 constraints/compute.vmExternalIpAccess 제약조건에 적용되는 정책이 Allow All인지 확인합니다. 이 제약조건 사용에 대한 자세한 내용은 특정 VM 인스턴스로 외부 IP 주소 제한을 참조하세요. 제약조건을 Allow All로 설정한 후 실패한 클러스터를 삭제하고 새 클러스터를 만듭니다. 이 작업은 실패한 클러스터 복구가 가능하지 않기 때문에 필요합니다.

배포된 워크로드 문제 해결

워크로드 포드에 문제가 있으면 GKE가 오류를 반환합니다. kubectl 명령줄 도구 또는 Google Cloud 콘솔을 사용하여 포드 상태를 확인할 수 있습니다.

kubectl

클러스터에서 실행 중인 모든 Pod를 확인하려면 다음 명령어를 실행합니다.

kubectl get pods

다음과 같이 출력됩니다.

NAME       READY  STATUS             RESTARTS  AGE
POD_NAME   0/1    CrashLoopBackOff   23        8d

특정 Pod에 대한 자세한 내용을 보려면 다음 명령어를 실행합니다.

kubectl describe pod POD_NAME

POD_NAME을 원하는 Pod의 이름으로 바꿉니다.

콘솔

다음 단계를 수행합니다.

  1. Google Cloud 콘솔에서 워크로드 페이지로 이동합니다.

    워크로드로 이동

  2. 원하는 워크로드를 선택합니다. 개요 탭에 워크로드 상태가 표시됩니다.

  3. 관리형 Pod 섹션에서 오류 상태 메시지를 클릭합니다.

다음 섹션에서는 워크로드가 반환하는 몇 가지 일반적인 오류와 그 해결 방법을 설명합니다.

CrashLoopBackOff

CrashLoopBackOff는 컨테이너가 다시 시작 후 반복적으로 비정상 종료됨을 나타냅니다. 컨테이너는 다양한 원인으로 인해 비정상 종료될 수 있습니다. Pod의 로그를 확인하면 근본 원인을 해결할 수 있습니다.

기본적으로 비정상 종료된 컨테이너는 5분으로 제한된 지수 지연으로 다시 시작됩니다. spec: restartPolicy에서 restartPolicy 필드 배포의 포드 사양을 설정하여 이 동작을 변경할 수 있습니다. 이 필드의 기본값은 Always입니다.

Google Cloud 콘솔을 사용하여 CrashLoopBackOff 오류를 문제 해결할 수 있습니다.

  1. 비정상 종료 루프 포드 대화형 플레이북으로 이동합니다.

    플레이북으로 이동

  2. 클러스터에 대해 문제 해결하려는 클러스터 이름을 입력합니다.

  3. 네임스페이스에 대해 문제 해결하려는 네임스페이스를 입력합니다.

  4. (선택사항) 이후의 CrashLoopBackOff 오류를 알리도록 알림을 만듭니다.

    1. 향후 문제 완화 팁 섹션에서 알림 만들기를 선택합니다.

로그 검사

kubectl 명령줄 도구 또는 Google Cloud 콘솔을 사용하여 포드의 컨테이너가 비정상 종료되는 원인을 확인할 수 있습니다.

kubectl

클러스터에서 실행 중인 모든 Pod를 확인하려면 다음 명령어를 실행합니다.

kubectl get pods

CrashLoopBackOff 오류가 있는 Pod를 찾습니다.

pod의 로그를 가져오려면 다음 명령어를 실행합니다.

kubectl logs POD_NAME

POD_NAME을 문제가 있는 pod의 이름으로 바꿉니다.

-p 플래그를 전달하여 pod 컨테이너의 이전 인스턴스 로그(있는 경우)를 가져올 수도 있습니다.

콘솔

다음 단계를 수행합니다.

  1. Google Cloud 콘솔에서 워크로드 페이지로 이동합니다.

    워크로드로 이동

  2. 원하는 워크로드를 선택합니다. 개요 탭에 워크로드 상태가 표시됩니다.

  3. 관리형 포드 섹션에서 문제가 있는 포드를 클릭합니다.

  4. 포드의 메뉴에서 로그 탭을 클릭합니다.

비정상 종료된 컨테이너의 '종료 코드' 확인

다음 태스크를 수행하여 종료 코드를 확인할 수 있습니다.

  1. 다음 명령어를 실행합니다.

    kubectl describe pod POD_NAME
    

    POD_NAME을 Pod의 이름으로 바꿉니다.

  2. containers: CONTAINER_NAME: last state: exit code 필드 값을 검토합니다.

    • 종료 코드가 1이면 애플리케이션 비정상 종료로 인해 컨테이너가 비정상 종료된 것입니다.
    • 종료 코드가 0이면 앱이 실행된 시간을 확인합니다.

    애플리케이션의 기본 프로세스가 종료되면 컨테이너가 종료됩니다. 앱 실행이 아주 빨리 끝나면 컨테이너가 계속 다시 시작될 수 있습니다.

실행 중인 컨테이너에 연결

Pod에 대한 셸을 엽니다.

kubectl exec -it POD_NAME -- /bin/bash

pod에 컨테이너가 두 개 이상 있으면 -c CONTAINER_NAME을 추가합니다.

이제 컨테이너에서 bash 명령어를 실행할 수 있습니다. 네트워크를 테스트하거나 애플리케이션에서 사용하는 파일 또는 데이터베이스에 액세스할 수 있는지 확인할 수 있습니다.

ImagePullBackOff 및 ErrImagePull

ImagePullBackOffErrImagePull은 컨테이너가 사용하는 이미지를 이미지 레지스트리에서 로드할 수 없음을 나타냅니다.

Google Cloud 콘솔 또는 kubectl 명령줄 도구를 사용하여 이 문제를 확인할 수 있습니다.

kubectl

포드의 컨테이너 이미지에 대한 자세한 정보를 보려면 다음 명령어를 실행합니다.

kubectl describe pod POD_NAME

콘솔

다음 단계를 수행합니다.

  1. Google Cloud 콘솔에서 워크로드 페이지로 이동합니다.

    워크로드로 이동

  2. 원하는 워크로드를 선택합니다. 개요 탭에 워크로드 상태가 표시됩니다.

  3. 관리형 포드 섹션에서 문제가 있는 포드를 클릭합니다.

  4. 포드의 메뉴에서 이벤트 탭을 클릭합니다.

이미지를 찾을 수 없는 경우

이미지를 찾을 수 없는 경우, 다음을 수행합니다.

  1. 이미지의 이름이 올바른지 확인합니다.
  2. 이미지의 태그가 올바른지 확인합니다. (:latest를 사용하거나 태그를 사용하지 않으면 최신 이미지를 가져올 수 있습니다.)
  3. 이미지에 전체 레지스트리 경로가 있으면 사용 중인 Docker 레지스트리에 있는지 확인합니다. 이미지 이름만 제공하는 경우, Docker Hub 레지스트리를 확인합니다.
  4. Docker 이미지를 수동으로 가져옵니다.

    • SSH를 통해 노드에 연결합니다.

      예를 들어 VM에 SSH로 연결하려면 다음을 실행합니다.

      gcloud compute ssh VM_NAME --zone=ZONE_NAME
      

      다음을 바꿉니다.

    • docker-credential-gcr configure-docker를 실행합니다. 이 명령어는 /home/[USER]/.docker/config.json에서 구성 파일을 생성합니다. 이 파일에 credHelpers 필드의 이미지 레지스트리가 포함되는지 확인합니다. 예를 들어 다음 파일에는 asia.gcr.io, eu.gcr.io, gcr.io, marketplace.gcr.io, us.gcr.io에 호스팅된 이미지의 인증 정보가 포함됩니다.

      {
        "auths": {},
        "credHelpers": {
          "asia.gcr.io": "gcr",
          "eu.gcr.io": "gcr",
          "gcr.io": "gcr",
          "marketplace.gcr.io": "gcr",
          "us.gcr.io": "gcr"
        }
      }
      
    • docker pull IMAGE_NAME을 실행합니다.

    이 방법이 효과적이면 pod에서 ImagePullSecrets을 지정해야 할 수도 있습니다. 포드는 자체 네임스페이스에 있는 이미지 가져오기 보안 비밀만을 참조할 수 있으므로 이 프로세스는 네임스페이스당 한 번 수행해야 합니다.

권한 거부됨 오류

"permission denied" 또는 "no pull access" 오류가 발생하면 로그인되어 있고 이미지에 대한 액세스 권한이 있는지 확인합니다. 이미지를 호스팅하는 레지스트리에 따라 다음 방법 중 하나를 시도합니다.

Artifact Registry

이미지가 Artifact Registry에 있으면 노드 풀의 서비스 계정에 이미지가 포함된 저장소에 대한 읽기 액세스 권한이 필요합니다.

서비스 계정에 artifactregistry.reader 역할을 부여합니다.

gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
    --location=REPOSITORY_LOCATION \
    --member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
    --role="roles/artifactregistry.reader"

다음을 바꿉니다.

  • REPOSITORY_NAME: Artifact Registry 저장소의 이름입니다.
  • REPOSITORY_LOCATION: Artifact Registry 저장소의 리전입니다.
  • SERVICE_ACCOUNT_EMAIL: 노드 풀과 연결된 IAM 서비스 계정의 이메일 주소입니다.

Container Registry

이미지가 Container Registry에 있으면 노드 풀의 서비스 계정에 이미지가 포함된 Cloud Storage 버킷에 대한 읽기 액세스 권한이 필요합니다.

버킷에서 읽을 수 있도록 서비스 계정에 roles/storage.objectViewer 역할을 부여합니다.

gsutil iam ch \
serviceAccount:SERVICE_ACCOUNT_EMAIL:roles/storage.objectViewer \
  gs://BUCKET_NAME

다음을 바꿉니다.

  • SERVICE_ACCOUNT_EMAIL: 노드 풀과 연결된 서비스 계정의 이메일입니다. gcloud iam service-accounts list를 사용하여 프로젝트의 모든 서비스 계정을 나열할 수 있습니다.
  • BUCKET_NAME: 이미지가 포함된 Cloud Storage 버킷의 이름입니다. gsutil ls를 사용하여 프로젝트의 모든 버킷을 나열할 수 있습니다.

레지스트리 관리자가 Container Registry 대신 gcr.io 도메인에 대해 이미지를 저장하도록 Artifact Registry에서 gcr.io 저장소를 설정한 경우 Container Registry 대신 Artifact Registry에 대해 읽기 액세스 권한을 부여해야 합니다.

비공개 레지스트리

이미지가 비공개 레지스트리에 있으면 이미지에 액세스하기 위해 키가 필요할 수 있습니다. 자세한 내용은 비공개 레지스트리 사용을 참조하세요.

401 승인되지 않음: 비공개 Container Registry 저장소에서 이미지를 가져올 수 없음

비공개 Container Registry 저장소에서 이미지를 가져올 때 다음과 비슷한 오류가 발생할 수 있습니다.

gcr.io/PROJECT_ID/IMAGE:TAG: rpc error: code = Unknown desc = failed to pull and
unpack image gcr.io/PROJECT_ID/IMAGE:TAG: failed to resolve reference
gcr.io/PROJECT_ID/IMAGE]:TAG: unexpected status code [manifests 1.0]: 401 Unauthorized

Warning  Failed     3m39s (x4 over 5m12s)  kubelet            Error: ErrImagePull
Warning  Failed     3m9s (x6 over 5m12s)   kubelet            Error: ImagePullBackOff
Normal   BackOff    2s (x18 over 5m12s)    kubelet            Back-off pulling image
  1. 포드를 실행 중인 노드를 식별합니다.

    kubectl describe pod POD_NAME | grep "Node:"
    
  2. 노드에 스토리지 범위가 포함되었는지 확인합니다.

    gcloud compute instances describe NODE_NAME \
        --zone=COMPUTE_ZONE --format="flattened(serviceAccounts[].scopes)"
    

    노드의 액세스 범위에는 최소한 다음 중 하나 이상이 포함되어야 합니다.

    serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/devstorage.read_only
    serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/cloud-platform
    
  3. 충분한 범위를 사용해서 노드가 포함된 노드 풀을 다시 만듭니다. 기존 노드는 수정할 수 없고, 올바른 범위를 사용해서 노드를 다시 만들어야 합니다.

    • 권장사항: gke-default 범위를 사용해서 새 노드 풀을 만듭니다.

      gcloud container node-pools create NODE_POOL_NAME \
          --cluster=CLUSTER_NAME \
          --zone=COMPUTE_ZONE \
          --scopes="gke-default"
      
    • 스토리지 범위만 사용해서 새 노드 풀을 만듭니다.

      gcloud container node-pools create NODE_POOL_NAME \
          --cluster=CLUSTER_NAME \
          --zone=COMPUTE_ZONE \
          --scopes="https://www.googleapis.com/auth/devstorage.read_only"
      

예약할 수 없는 포드

PodUnschedulable은 리소스 부족 또는 일부 구성 오류로 인해 포드를 예약할 수 없음을 나타냅니다.

Kubernetes API 서버 및 Kubernetes 스케줄러 측정항목을 Cloud Monitoring으로 전송하도록 GKE 클러스터를 구성한 경우 스케줄러 측정항목API 서버 측정항목에서 이러한 오류에 대한 자세한 정보를 찾을 수 있습니다.

Google Cloud 콘솔을 사용하여 PodUnschedulable 오류를 문제 해결할 수 있습니다.

  1. 예약할 수 없는 포드 대화형 플레이북으로 이동합니다.

    플레이북으로 이동

  2. 클러스터에 대해 문제 해결하려는 클러스터 이름을 입력합니다.

  3. 네임스페이스에 대해 문제 해결하려는 네임스페이스를 입력합니다.

  4. (선택사항) 이후의 PodUnschedulable 오류를 알리도록 알림을 만듭니다.

    1. 향후 문제 완화 팁 섹션에서 알림 만들기를 선택합니다.

리소스 부족

CPU, 메모리 또는 다른 리소스 부족을 나타내는 오류가 발생할 수 있습니다. 예: '모든 조건자와 일치하는 노드를 사용할 수 없음: cpu 부족 (2)'은 2개의 노드에 포드의 요청 충족에 사용할 수 있는 CPU가 충분하지 않음을 나타냅니다.

포드 리소스 요청이 적격한 노드 풀에서 단일 노드의 요청을 초과할 경우 GKE가 포드를 예약하지 않고 새 노드를 추가하기 위한 수직 확장을 트리거하지 않습니다. GKE가 포드를 예약할 수 있도록 하려면 포드에 대해 더 적은 수의 리소스를 요청하거나 리소스가 충분한 새 노드 풀을 만들어야 합니다.

또한 예약되지 않은 포드가 실행될 수 있는 노드를 사용해서 GKE가 노드 풀을 자동으로 만들 수 있도록 노드 자동 프로비저닝을 사용 설정할 수 있습니다.

기본 CPU 요청은 100m 또는 CPU의 10%(또는 코어 한 개)입니다. 더 많은 리소스 또는 더 적은 리소스를 요청하려면 spec: containers: resources: requests의 포드 사양에 값을 지정합니다.

MatchNodeSelector

MatchNodeSelector는 Pod의 라벨 선택기와 일치하는 노드가 없음을 나타냅니다.

spec: nodeSelector에서 Pod 사양의 nodeSelector 필드에 지정된 라벨을 통해 이를 확인할 수 있습니다.

클러스터의 노드에 라벨이 어떻게 지정되어 있는지 확인하려면 다음 명령어를 실행합니다.

kubectl get nodes --show-labels

노드에 라벨을 연결하려면 다음 명령어를 실행합니다.

kubectl label nodes NODE_NAME LABEL_KEY=LABEL_VALUE

다음을 바꿉니다.

  • NODE_NAME: 원하는 노드
  • LABEL_KEY: 라벨의 키
  • LABEL_VALUE: 라벨의 값

자세한 내용은 포드를 노드에 할당을 참조하세요.

podToleratesNodeTaint

PodToleratesNodeTaints는 현재 노드 taint를 허용하는 노드가 없으므로 pod를 어떠한 노드에도 예약할 수 없음을 나타냅니다.

이 경우인지 확인하려면 다음 명령어를 실행합니다.

kubectl describe nodes NODE_NAME

출력에서 키-값 쌍과 예약 효과가 나열되는 Taints 필드를 확인합니다.

나열된 효과가 NoSchedule이면 일치하는 톨러레이션이 없는 한 노드에서 pod를 예약할 수 없습니다.

이 문제를 해결하는 한 가지 방법은 taint를 제거하는 것입니다. 예를 들어 NoSchedule taint를 삭제하려면 다음 명령어를 실행합니다.

kubectl taint nodes NODE_NAME key:NoSchedule-

PodFitsHostPort

PodFitsHostPorts는 노드가 사용하려 하는 포트가 이미 사용 중임을 나타냅니다.

이 문제를 해결하려면 spec: containers: ports: hostPort에서 Pod 사양의 hostPort 값을 확인합니다. 이 값을 다른 포트로 변경해야 할 수도 있습니다.

최소 가용성 없음

노드에 적절한 리소스가 있지만 여전히 Does not have minimum availability 메시지가 표시되면 Pod 상태를 확인합니다. 상태가 SchedulingDisabled 또는 Cordoned이면 노드가 새 포드를 예약할 수 없습니다. Google Cloud 콘솔 또는 kubectl 명령줄 도구를 사용해서 노드 상태를 확인할 수 있습니다.

kubectl

노드 상태를 가져오려면 다음 명령어를 실행합니다.

kubectl get nodes

노드에서 예약을 사용 설정하려면 다음을 실행합니다.

kubectl uncordon NODE_NAME

콘솔

다음 단계를 수행합니다.

  1. Google Cloud 콘솔에서 Google Kubernetes Engine 페이지로 이동합니다.

    Google Kubernetes Engine으로 이동

  2. 원하는 클러스터를 선택합니다. 노드 탭에 노드와 노드 상태가 표시됩니다.

노드에서 예약을 사용 설정하려면 다음 단계를 수행합니다.

  1. 목록에서 원하는 노드를 클릭합니다.

  2. 노드 세부정보에서 차단 해제 버튼을 클릭합니다.

노드당 최대 노드 수 한도 도달

클러스터의 모든 노드에서 노드당 최대 노드 수 한도에 도달하면 포드가 예약 불가능한 상태로 멈춥니다. 포드 이벤트 탭에서 Too many pods 문구가 포함된 메시지가 표시됩니다.

  1. Google Cloud 콘솔의 GKE 클러스터 세부정보에 있는 노드 탭에서 Maximum pods per node 구성을 확인합니다.

  2. 노드 목록을 가져옵니다.

    kubectl get nodes
    
  3. 각 노드에 대해 노드에서 실행 중인 포드 수를 확인합니다.

    kubectl get pods -o wide | grep NODE_NAME | wc -l
    
  4. 한도에 도달하면 새 노드 풀을 추가하거나 기존 노드 풀에 노드를 더 추가합니다.

클러스터 자동 확장 처리가 사용 설정된 상태로 최대 노드 풀 크기에 도달

클러스터 자동 확장 처리 구성에 따라 노드 풀이 최대 크기에 도달했으면 GKE에서 이 노드 풀로 예약되었을 포드에 대해 수직 확장이 트리거되지 않습니다. 이 노드 풀로 포드를 예약하려면 클러스터 자동 확장 처리 구성을 변경합니다.

클러스터 자동 확장 처리가 사용 중지된 상태로 최대 노드 풀 크기에 도달

노드 풀이 최대 노드 수에 도달했고 클러스터 자동 확장 처리가 사용 중지되어 있으면 GKE가 노드 풀로 포드를 예약할 수 없습니다. GKE가 클러스터 크기를 자동으로 조정할 수 있도록 노드 풀의 크기를 늘리거나 또는 클러스터 자동 확장 처리를 사용 설정합니다.

결합 해제된 PersistentVolumeClaim

Unbound PersistentVolumeClaims는 Pod가 결합되지 않은 PersistentVolumeClaim을 참조함을 나타냅니다. 이 오류는 PersistentVolume이 프로비저닝을 실패한 경우에 발생할 수 있습니다. PersistentVolumeClaim의 이벤트를 가져오고 실패를 검사하여 프로비저닝 실패를 확인할 수 있습니다.

이벤트를 가져오려면 다음 명령어를 실행합니다.

kubectl describe pvc STATEFULSET_NAME-PVC_NAME-0

다음을 바꿉니다.

  • STATEFULSET_NAME: StatefulSet 객체의 이름입니다.
  • PVC_NAME: PersistentVolumeClaim 객체의 이름입니다.

이는 PersistentVolume을 수동으로 사전 프로비저닝하고 PersistentVolumeClaim에 결합하는 중에 구성 오류가 있어도 발생할 수 있습니다. 볼륨을 다시 사전 프로비저닝할 수 있습니다.

할당량 부족

GKE가 클러스터를 수직 확장할 수 있도록 프로젝트에 Compute Engine 할당량이 충분한지 확인합니다. GKE가 포드를 예약할 수 있도록 클러스터에 노드를 추가하려고 시도할 때 수직 확장으로 인해 프로젝트의 가용 할당량이 초과될 경우 scale.up.error.quota.exceeded 오류 메시지가 표시됩니다.

자세한 내용은 ScaleUp 오류를 참조하세요.

지원 중단된 API

클러스터의 부 버전에서 삭제된 지원 중단된 API를 사용 중이 아닌지 확인합니다. 자세한 내용은 GKE 지원 중단을 참조하세요.

연결 문제

네트워크 개요 설명에서 언급한 것처럼, 효율적인 문제 해결을 위해서는 네트워크 네임스페이스에서 노드의 루트 네임스페이스로 pod가 연결된 방법을 이해하는 것이 중요합니다. 아래의 설명에서는 특별히 언급하지 않는 한 클러스터가 Calico 대신 GKE의 기본 CNI를 사용한다고 가정합니다. 즉, 네트워크 정책이 적용되지 않습니다.

선택 노드의 포드에 가용성 없음

선택 노드의 Pod에 네트워크 연결이 없으면 Linux 브리지가 작동 중인지 확인합니다.

ip address show cbr0

Linux 브리지가 작동 중지되었으면 다음 방법으로 작동시킵니다.

sudo ip link set cbr0 up

노드가 cbr0에 연결된 Pod MAC 주소를 학습하는지 확인합니다.

arp -an

선택 노드의 Pod에 최소 연결이 포함됨

선택 노드의 Pod에 최소 연결이 포함된 경우 먼저 도구 상자 컨테이너에서 tcpdump를 실행하여 손실된 패킷이 있는지 여부를 확인해야 합니다.

sudo toolbox bash

아직 설치하지 않았으면 도구 상자에서 tcpdump를 설치합니다.

apt install -y tcpdump

cbr0에 대해 tcpdump를 실행합니다.

tcpdump -ni cbr0 host HOSTNAME and port PORT_NUMBER and [TCP|UDP|ICMP]

브리지에서 큰 패킷이 다운스트림으로 삭제된 것으로 나타나면(예: TCP 핸드셰이크가 완료되었지만 SSL hello가 수신되지 않음) 각 Linux 포드 인터페이스의 MTU가 클러스터 VPC 네트워크의 MTU로 올바르게 설정되었는지 확인합니다.

ip address show cbr0

오버레이가 사용된 경우(예: Weave 또는 Flannel), 오버레이의 캡슐화 오버헤드를 수용하도록 이 MTU를 더 줄여야 합니다.

GKE MTU

포드 인터페이스로 선택된 MTU는 클러스터 노드 및 기본 VPC MTU 설정에 사용되는 컨테이너 네트워크 인터페이스(CNI)에 따라 달라집니다. 자세한 내용은 포드를 참조하세요.

포드 인터페이스 MTU 값은 1460이거나 노드의 기본 인터페이스에서 상속됩니다.

CNI MTU GKE Standard
kubenet 1460 기본
kubenet
(GKE 버전 1.26.1 이상)
상속됨 기본
Calico 1460

--enable-network-policy를 사용하여 사용 설정됩니다.

자세한 내용은 네트워크 정책을 사용한 포드 및 서비스 간 통신 제어를 참조하세요.

netd 상속됨 다음 중 하나를 사용하여 사용 설정됩니다.
GKE Dataplane V2 상속됨

--enable-dataplane-v2를 사용하여 사용 설정됩니다.

자세한 내용은 GKE Dataplane V2 사용을 참조하세요.

간헐적인 연결 오류

포드에 대한 연결은 iptable에 의해 전달됩니다. 흐름은 conntrack 테이블의 항목으로 추적되며, 노드당 작업 부하가 많은 경우, conntrack 테이블 소진이 오류로 나타날 수 있습니다. 이러한 문제는 노드의 직렬 콘솔에 로깅될 수 있습니다. 예를 들면 다음과 같습니다.

nf_conntrack: table full, dropping packet

간헐적인 문제가 conntrack 소진으로 인해 발생한다는 사실을 확인할 수 있으면 클러스터 크기를 늘리거나(따라서 노드당 워크로드 및 흐름의 수를 줄이거나) nf_conntrack_max를 늘릴 수 있습니다.

new_ct_max=$(awk '$1 == "MemTotal:" { printf "%d\n", $2/32; exit; }' /proc/meminfo)
sysctl -w net.netfilter.nf_conntrack_max="${new_ct_max:?}" \
  && echo "net.netfilter.nf_conntrack_max=${new_ct_max:?}" >> /etc/sysctl.conf

또한 NodeLocal DNSCache를 사용하여 연결 추적 항목을 줄일 수 있습니다.

컨테이너에 대해 'bind: Address already in use'가 보고됨

컨테이너 로그에 따라 애플리케이션이 바인딩하려는 포트가 이미 예약되었기 때문에 포드의 컨테이너를 시작할 수 없습니다. 컨테이너에 비정상 종료 루프가 발생 합니다. 예를 들어 Cloud Logging에서 다음이 발생합니다.

resource.type="container"
textPayload:"bind: Address already in use"
resource.labels.container_name="redis"

2018-10-16 07:06:47.000 CEST 16 Oct 05:06:47.533 # Creating Server TCP listening socket *:60250: bind: Address already in use
2018-10-16 07:07:35.000 CEST 16 Oct 05:07:35.753 # Creating Server TCP listening socket *:60250: bind: Address already in use

Docker가 충돌할 때 일부 경우에는 실행 중인 컨테이너가 뒤쳐져서 오래된 상태가 될 수 있습니다. 프로세스는 포드에 할당된 네트워크 네임스페이스에서 계속 실행 중이며, 해당 포트에서 수신 대기 중입니다. Docker 및 kubelet은 오래된 컨테이너를 모르므로 새 프로세스로 새 컨테이너를 시작하려 합니다. 따라서 이미 Pod와 연결된 네트워크 네임스페이스에 추가될 때 포트에서 결합할 수 없습니다.

이 문제를 진단하려면 다음 안내를 따르세요.

  1. .metadata.uuid 필드에 Pod의 UUID가 필요합니다.

    kubectl get pod -o custom-columns="name:.metadata.name,UUID:.metadata.uid" ubuntu-6948dd5657-4gsgg
    
    name                      UUID
    ubuntu-6948dd5657-4gsgg   db9ed086-edba-11e8-bdd6-42010a800164
    
  2. 노드에서 다음 명령어의 출력을 가져옵니다.

    docker ps -a
    ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
    
  3. 이 Pod에서 실행 중인 프로세스를 확인합니다. cgroup 네임스페이스의 UUID에는 Pod의 UUID가 포함되어 있으므로 ps 출력에서 Pod UUID에 grep을 실행할 수 있습니다. 앞의 라인에도 grep을 수행하므로 docker-containerd-shim 프로세스가 컨테이너 ID를 인수에 지정하게 됩니다. 출력이 더 간단해지도록 cgroup 열의 나머지 부분을 잘라냅니다.

    # ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep -B 1 db9ed086-edba-11e8-bdd6-42010a800164 | sed s/'blkio:.*'/''/
    1283089     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 276e173b0846e24b704d4 12:
    1283107 1283089 Ss   sys_pause            4026532393         pause           /pause                                     12:
    1283150     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim ab4c7762f5abf40951770 12:
    1283169 1283150 Ss   do_wait              4026532393         sh              /bin/sh -c echo hello && sleep 6000000     12:
    1283185 1283169 S    hrtimer_nanosleep    4026532393           sleep           sleep 6000000                            12:
    1283244     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 44e76e50e5ef4156fd5d3 12:
    1283263 1283244 Ss   sigsuspend           4026532393         nginx           nginx: master process nginx -g daemon off; 12:
    1283282 1283263 S    ep_poll              4026532393           nginx           nginx: worker process
    
  4. 이 목록에서 docker ps에도 표시되는 컨테이너 ID를 확인할 수 있습니다.

    주요 내용은 다음과 같습니다.

    • docker-containerd-shim 276e173b0846e24b704d4 - 일시 중지
    • docker-containerd-shim ab4c7762f5abf40951770 - sleep을 포함한 sh(sleep-ctr)
    • docker-containerd-shim 44e76e50e5ef4156fd5d3 - nginx(echoserver-ctr)
  5. docker ps 출력에서 해당 부분을 확인합니다.

    # docker ps --no-trunc | egrep '276e173b0846e24b704d4|ab4c7762f5abf40951770|44e76e50e5ef4156fd5d3'
    44e76e50e5ef4156fd5d383744fa6a5f14460582d0b16855177cbed89a3cbd1f   gcr.io/google_containers/echoserver@sha256:3e7b182372b398d97b747bbe6cb7595e5ffaaae9a62506c725656966d36643cc                   "nginx -g 'daemon off;'"                                                                                                                                                                                                                                                                                                                                                                     14 hours ago        Up 14 hours                             k8s_echoserver-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
    ab4c7762f5abf40951770d3e247fa2559a2d1f8c8834e5412bdcec7df37f8475   ubuntu@sha256:acd85db6e4b18aafa7fcde5480872909bd8e6d5fbd4e5e790ecc09acc06a8b78                                                "/bin/sh -c 'echo hello && sleep 6000000'"                                                                                                                                                                                                                                                                                                                                                   14 hours ago        Up 14 hours                             k8s_sleep-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
    276e173b0846e24b704d41cf4fbb950bfa5d0f59c304827349f4cf5091be3327   registry.k8s.io/pause-amd64:3.1
    

    일반적인 경우에는 ps의 모든 컨테이너 ID가 docker ps에 표시됩니다. 표시되지 않은 항목이 있으면 이는 오래된 컨테이너이고, 이미 사용 중인 것으로 보고되는 TCP 포트에서 리슨 중인 docker-containerd-shim process의 하위 프로세스가 표시됩니다.

    이를 확인하려면 컨테이너의 네트워크 네임스페이스에서 netstat을 실행합니다. Pod에서 모든 컨테이너 프로세스의 pid(docker-containerd-shim 아님)를 가져옵니다.

    위 예시의 경우는 다음과 같습니다.

    • 1283107 - pause
    • 1283169 - sh
    • 1283185 - sleep
    • 1283263 - nginx master
    • 1283282 - nginx worker
    # nsenter -t 1283107 --net netstat -anp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
    unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
    unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
    
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # nsenter -t 1283169 --net netstat -anp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
    unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
    unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
    

    또한 ip netns를 사용하여 netstat을 실행할 수도 있지만 Docker가 연결을 수행하고 있지 않으므로 프로세스의 네트워크 네임스페이스를 수동으로 연결해야 합니다.

    # ln -s /proc/1283169/ns/net /var/run/netns/1283169
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns list
    1283169 (id: 2)
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns exec 1283169 netstat -anp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
    unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
    unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # rm /var/run/netns/1283169
    

완화 방법:

단기적인 완화 방법은 위에서 설명한 방법으로 비활성 프로세스를 식별하고 kill [PID] 명령어를 사용하여 프로세스를 종료하는 것입니다.

장기적인 완화 방법은 Docker가 충돌하는 원인을 식별하고 해결하는 것입니다. 가능한 이유는 다음과 같습니다.

  • 좀비 프로세스 누적으로 인한 PID 네임스페이스 부족
  • docker 버그
  • 리소스 압력/OOM

오류: "범위 0에 대한 할당 실패: 설정된 범위에 IP 주소 없음"

GKE 버전 1.18.17 이상에서는 컨테이너가 시작되기 전 포드가 삭제되었을 때 메모리 부족(OOM) 이벤트로 인해 잘못된 포드 제거가 수행되는 문제가 수정되었습니다. 이러한 잘못된 제거로 인해 포드가 고립되고 할당된 노드 범위로부터 예약된 IP 주소를 계속 사용할 수 있습니다. 시간이 지나면 고립된 포드가 쌓여 GKE에서 새 포드에 할당할 수 있는 IP 주소가 부족하게 됩니다. 그 결과 할당된 노드 범위에 새 포드에 할당할 수 있는 가용 IP가 없어서 failed to allocate for range 0: no IP addresses in range set 오류 메시지가 표시됩니다.

이 문제를 해결하려면 GKE 버전 1.18.17 이상으로 클러스터 및 노드 풀을 업그레이드합니다.

GKE 버전 1.18.17 이전의 클러스터에서 이 문제를 방지하고 해결하려면 이후에 OOM 이벤트가 발생하지 않도록 리소스 한도를 늘리고, 고립된 포드를 삭제하여 IP 주소를 회수합니다.

또한 GKE IP 주소 사용률 통계도 확인할 수 있습니다.

영향을 받는 노드에서 고립된 포드 삭제

노드를 드레이닝하거나, 노드 풀을 업그레이드하거나, 영향을 받는 디렉터리를 이동하여 고립된 포드를 삭제할 수 있습니다.

노드 드레이닝(권장)

  1. 새 포드가 예약되지 않도록 노드를 차단합니다.

     kubectl cordon NODE
    

    NODE를 드레이닝하려는 노드 이름으로 바꿉니다.

  2. 노드를 드레이닝합니다. GKE가 배포로 관리되는 포드를 다른 노드에 자동으로 다시 예약합니다. --force 플래그를 사용해서 관리 리소스가 없는 고립된 포드를 드레이닝합니다.

     kubectl drain NODE --force
    
  3. GKE가 새 포드를 예약할 수 있도록 노드를 차단 해제합니다.

     kubectl uncordon NODE
    

영향을 받는 디렉터리 이동

/var/lib/kubelet/pods에서 고립된 포드 디렉터리를 식별하고 GKE가 포드를 해지하도록 기본 디렉터리 외부로 이동합니다.

리소스 종료 문제 해결

네임스페이스가 Terminating 상태로 멈춰 있음

네임스페이스는 네임스페이스 내에 하나 이상의 리소스가 존재할 때 Kubernetes 파이널라이저를 사용하여 삭제를 방지합니다. kubectl delete 명령어를 사용하여 네임스페이스를 삭제할 때는 Kubernetes가 종속 리소스를 삭제하고 모든 파이널라이저를 지울 때까지 네임스페이스가 Terminating 상태로 전환됩니다. 네임스페이스 수명 주기 컨트롤러는 먼저 GKE가 삭제해야 하는 네임스페이스의 모든 리소스를 나열합니다. GKE가 종속 리소스를 삭제할 수 없거나 네임스페이스 수명 주기 컨트롤러가 네임스페이스가 비어 있는지 확인할 수 없으면 사용자가 문제를 해결할 때까지 네임스페이스가 Terminating 상태로 유지됩니다.

Terminating 상태로 멈춘 네임스페이스를 해결하려면 삭제를 차단하는 비정상 구성요소를 식별하고 이를 삭제해야 합니다. 다음 솔루션 중 하나를 시도해 보세요.

사용할 수 없는 API 서비스 찾기 및 삭제

  1. 사용할 수 없는 API 서비스를 나열합니다.

    kubectl get apiservice | grep False
    
  2. 응답하지 않는 서비스를 문제 해결합니다.

    kubectl describe apiservice API_SERVICE
    

    API_SERVICE를 응답하지 않는 서비스 이름으로 바꿉니다.

  3. 네임스페이스가 여전히 종료 중인지 확인합니다.

    kubectl get ns | grep Terminating
    

나머지 리소스 찾기 및 삭제

  1. 종료 네임스페이스에 남은 모든 리소스를 나열합니다.

    kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get -n NAMESPACE
    

    NAMESPACE를 삭제하려는 네임스페이스의 이름으로 바꿉니다.

  2. 출력에 표시된 모든 리소스를 삭제합니다.

  3. 네임스페이스가 여전히 종료 중인지 확인합니다.

    kubectl get ns | grep Terminating
    

네임스페이스 강제 삭제

네임스페이스 삭제를 차단하는 파이널라이저를 삭제하여 네임스페이스를 강제 종료할 수 있습니다.

  1. 네임스페이스 매니페스트를 YAML 파일로 저장합니다.

    kubectl get ns NAMESPACE -o yaml > ns-terminating.yml
    
  2. 텍스트 편집기에서 매니페스트를 열고 spec.finalizers 필드에서 모든 값을 삭제합니다.

    vi ns-terminating.yml
    
  3. 파이널라이저 필드가 비어 있는지 확인합니다.

    cat ns-terminating.yml
    

    다음과 유사하게 출력됩니다.

    apiVersion: v1
    kind: Namespace
    metadata:
      annotations:
      name: NAMESPACE
    spec:
      finalizers:
    status:
      phase: Terminating
    
  4. HTTP 프록시를 시작하여 Kubernetes API에 액세스합니다.

    kubectl proxy
    
  5. curl을 사용하여 네임스페이스 매니페스트를 바꿉니다.

    curl -H "Content-Type: application/yaml" -X PUT --data-binary @ns-terminating.yml http://127.0.0.1:8001/api/v1/namespaces/NAMESPACE/finalize
    
  6. 네임스페이스가 여전히 종료 중인지 확인합니다.

    kubectl get ns | grep Terminating
    

GKE 클러스터에서 Cloud NAT 패킷 손실 문제 해결

VPC 기반 GKE 비공개 클러스터의 노드 VM은 외부 IP 주소가 없으며 그 자체로 인터넷에 연결할 수 없습니다. 비공개 클러스터가 공개 연결을 수행하도록 Cloud NAT를 사용해서 외부 IP 주소 및 포트를 할당할 수 있습니다.

노드 VM에 Cloud NAT의 외부 포트 및 IP 주소 할당이 부족해지면 패킷이 삭제됩니다. 이를 방지하기 위해서는 아웃바운드 패킷 비율을 줄이거나 사용 가능한 Cloud NAT 소스 IP 주소 및 포트의 할당을 늘릴 수 있습니다. 다음 섹션에서는 GKE 비공개 클러스터의 컨텍스트에서 Cloud NAT로부터 패킷 손실을 진단하고 문제 해결하는 방법을 설명합니다.

패킷 손실 진단

이 섹션에서는 Cloud Logging을 사용하여 손실된 패킷을 로깅하고 Cloud Monitoring을 사용해서 손실된 패킷의 원인을 진단하는 방법을 설명합니다.

손실된 패킷 로깅

Cloud Logging에서 다음 쿼리를 사용하여 손실된 패킷을 로깅할 수 있습니다.

resource.type="nat_gateway"
resource.labels.region=REGION
resource.labels.gateway_name=GATEWAY_NAME
jsonPayload.allocation_status="DROPPED"
  • REGION: 클러스터가 있는 리전의 이름입니다.
  • GATEWAY_NAME: Cloud NAT 게이트웨이의 이름입니다.

이 명령어는 Cloud NAT 게이트웨이에서 삭제된 모든 패킷의 목록을 반환하지만 원인을 식별하지 않습니다.

패킷 손실의 원인 모니터링

손실된 패킷의 원인을 식별하려면 Cloud Monitoring에서 측정항목 관찰자를 쿼리합니다. 패킷은 세 가지 이유 중 하나로 삭제됩니다.

OUT_OF_RESOURCES 또는 ENDPOINT_ALLOCATION_FAILED 오류 코드로 인해 삭제된 패킷을 식별하려면 다음 쿼리를 사용합니다.

fetch nat_gateway
  metric 'router.googleapis.com/nat/dropped_sent_packets_count'
  filter (resource.gateway_name == NAT_NAME)
  align rate(1m)
  every 1m
  group_by [metric.reason],
    [value_dropped_sent_packets_count_aggregate:
       aggregate(value.dropped_sent_packets_count)]

NAT_ALLOCATION_FAILED 오류 코드로 인해 삭제된 패킷을 식별하려면 다음 쿼리를 사용합니다.

fetch nat_gateway
  metric 'router.googleapis.com/nat/nat_allocation_failed'
  group_by 1m,
    [value_nat_allocation_failed_count_true:
       count_true(value.nat_allocation_failed)]
  every 1m

GKE IP 마스커레이딩으로 Cloud NAT 문제 해결

이전 쿼리가 빈 결과를 반환하고 GKE 포드가 외부 IP 주소와 통신할 수 없으면 구성을 문제 해결합니다.

구성 문제 해결
서브넷의 기본 IP 주소 범위에만 적용되도록 구성된 Cloud NAT Cloud NAT가 서브넷의 기본 IP 주소 범위에 대해서만 구성된 경우 클러스터에서 외부 IP 주소로 전송된 패킷에 소스 노드 IP 주소가 있어야 합니다. 이 Cloud NAT 구성에 대한 설명은 다음과 같습니다.
  • 이러한 외부 IP 주소 대상에 IP 마스커레이딩이 적용되는 경우 포드가 외부 IP 주소로 패킷을 전송할 수 있습니다. ip-masq-agent를 배포할 때 nonMasqueradeCIDRs 목록에 대상 IP 주소 및 포트가 포함되지 않는지 확인합니다. 이러한 대상으로 전송되는 패킷은 먼저 소스 노드 IP 주소로 변환된 후 Cloud NAT에서 처리됩니다.
  • 포드가 이 Cloud NAT 구성을 사용해서 모든 외부 IP 주소에 연결할 수 있게 하려면 ip-masq-agent가 배포되었고 nonMasqueradeCIDRs 목록에 클러스터의 노드 및 포드 IP 주소 범위만 포함되었는지 확인합니다. 클러스터 외부의 대상에 전송된 패킷은 먼저 소스 노드 IP 주소로 변환된 후 Cloud NAT에서 처리됩니다.
  • 포드가 일부 외부 IP 주소로 패킷을 전송하지 못하도록 방지하려면 마스커레이딩되지 않도록 해당 주소를 명시적으로 차단해야 합니다. ip-masq-agent가 배포되었으면 차단하려는 외부 IP 주소를 nonMasqueradeCIDRs 목록에 추가합니다. 이러한 대상에 전송된 패킷은 노드의 포드 IP 주소 소스를 원래 상태로 둡니다. 포드 IP 주소는 클러스터 서브넷의 보조 IP 주소 범위에서 시작됩니다. 이 구성에서 Cloud NAT는 이 보조 범위에서 작동하지 않습니다.
포드 IP에 사용된 서브넷의 보조 IP 주소 범위에만 적용되도록 구성된 Cloud NAT

Cloud NAT가 클러스터의 포드 IP에 사용되는 서브넷의 보조 IP 주소 범위에 대해서만 구성된 경우 클러스터에서 외부 IP 주소로 전송된 패킷에 소스 포드 IP 주소가 있어야 합니다. 이 Cloud NAT 구성에 대한 설명은 다음과 같습니다.

  • IP 마스커레이드 에이전트를 사용하면 Cloud NAT에서 처리될 때 패킷의 소스 포드 IP 주소가 손실됩니다. 소스 포드 IP 주소를 유지하려면 nonMasqueradeCIDRs 목록에 대상 IP 주소 범위를 지정합니다. ip-masq-agent가 배포된 상태로 nonMasqueradeCIDRs 목록의 대상에 전송된 패킷은 소스 포드 IP 주소를 보존한 후 Cloud NAT에서 처리됩니다.
  • 포드가 이 Cloud NAT 구성을 사용해서 모든 외부 IP 주소에 연결할 수 있게 하려면 ip-masq-agent가 배포되었고 nonMasqueradeCIDRs 목록이 가능한 한 크게 설정되었는지 확인합니다(0.0.0.0/0은 모든 IP 주소 대상 지정). 모든 대상에 전송된 패킷은 소스 포드 IP 주소를 보존한 후 Cloud NAT에서 처리됩니다.

패킷 손실을 방지하기 위한 최적화

다음 방법으로 패킷 손실을 중단할 수 있습니다.

애플리케이션 최적화

애플리케이션이 동일한 대상 IP 주소 및 포트에 대해 아웃바운드 연결을 여러 번 수행하면 Cloud NAT가 할당된 NAT 소스 주소 및 소스 포트 튜플 수를 사용해서 대상에 수행할 수 있는 모든 연결을 빠르게 소비할 수 있습니다. 이 시나리오에서 애플리케이션의 아웃바운드 패킷 비율을 줄이면 패킷 손실을 줄이는 데 도움이 됩니다.

대상에 대한 동시 연결 수 제한을 포함하여 Cloud NAT가 NAT 소스 주소 및 소스 포트를 사용하여 연결을 수행하는 방법은 포트 및 연결을 참조하세요.

애플리케이션에서 아웃바운드 연결 비율을 줄이면 패킷 손실을 완화하는 데 도움이 될 수 있습니다. 이렇게 하려면 열린 연결을 재사용하면 됩니다. 연결을 재사용하는 일반적인 방법에는 연결 풀링, HTTP/2와 같은 프로토콜을 사용한 연결 다중화, 여러 요청에 재사용되는 영구 연결 설정이 있습니다. 자세한 내용은 포트 및 연결을 참조하세요.

노드 버전이 제어 영역 버전과 호환되지 않음

클러스터의 제어 영역이 실행 중인 Kubernetes 버전을 확인한 다음 클러스터의 노드 풀이 실행 중인 Kubernetes 버전을 확인하세요. 클러스터의 노드 풀 중 제어 영역보다 오래된 부 버전이 2개 초과이면 클러스터에 문제가 발생할 수 있습니다.

GKE팀은 사용자를 대신하여 클러스터 제어 영역의 업그레이드를 주기적으로 수행합니다. 제어 영역은 안정적인 새 Kubernetes 버전으로 업그레이드됩니다. 기본적으로 클러스터 노드는 자동 업그레이드가 사용 설정되어 있으며, 사용 중지하지 않는 것이 좋습니다.

클러스터 노드에 자동 업그레이드가 사용 중지되어 있고 노드 풀 버전을 제어 영역과 호환되는 버전으로 수동으로 업그레이드하지 않으면 자동으로 업그레이드되는 제어 영역과 노드는 결국 호환되지 않게 됩니다. 클러스터의 제어 영역과 노드 간의 비호환성으로 인해 예기치 않은 문제가 발생할 수 있습니다.

Kubernetes 버전 및 버전 차이 지원 정책은 제어 영역보다 최대 2개 부 버전이 낮은 노드와 제어 영역의 호환을 보장합니다. 예를 들어 Kubernetes 1.19 제어 영역은 Kubernetes 1.19, 1.18, 1.17 노드와 호환됩니다. 이 문제를 해결하려면 노드 풀 버전을 제어 영역과 호환되는 버전으로 수동으로 업그레이드하세요.

영향을 받는 노드에서 실행되는 워크로드가 워크로드 프로세스로 인해 중단되는 것이 우려되는 경우 다음 단계를 수행하여 워크로드를 새 노드 풀로 마이그레이션합니다.

  1. 호환되는 버전으로 새 노드 풀을 만듭니다.
  2. 기존 노드 풀의 노드를 차단합니다.
  3. 선택적으로 기존 노드 풀에서 실행되는 워크로드를 업데이트하여 cloud.google.com/gke-nodepool:NEW_NODE_POOL_NAME 라벨의 nodeSelector를 추가합니다. 여기서 NEW_NODE_POOL_NAME은 새 노드 풀의 이름입니다. 이렇게 하면 GKE가 새 노드 풀의 노드에 이러한 워크로드를 배치합니다.
  4. 기존 노드 풀을 드레이닝합니다.
  5. 새 노드 풀에서 워크로드가 성공적으로 실행되는지 확인합니다. 성공적으로 실행될 경우 이전 노드 풀을 삭제할 수 있습니다. 워크로드 중단이 발견되면 기존 노드 풀에서 노드 차단을 취소하고 새 노드를 드레이닝하여 기존 노드에서 워크로드를 다시 예약합니다. 문제 해결을 수행하고 다시 시도합니다.

Cloud Monitoring에 클러스터의 측정항목이 표시되지 않음

프로젝트에서 Cloud Monitoring APICloud Logging API를 활성화했고 Cloud Monitoring에서 프로젝트를 볼 수 있는지 확인합니다.

문제가 계속되면 다음과 같은 가능한 원인을 확인하세요.

  1. 클러스터에서 모니터링을 사용 설정했는지 확인합니다.

    기본적으로 Google Cloud 콘솔과 Google Cloud CLI에서 생성된 클러스터에는 Monitoring이 사용 설정되지만 다음 명령어를 실행하거나 Google Cloud 콘솔에서 클러스터 세부정보를 클릭하여 사용 설정 여부를 확인할 수 있습니다.

    gcloud container clusters describe CLUSTER_NAME
    

    이 명령어의 출력에는 다음과 비슷하게 monitoringConfig 섹션의 enableComponents 목록에 있는 SYSTEM_COMPONENTS가 포함됩니다.

    monitoringConfig:
      componentConfig:
        enableComponents:
        - SYSTEM_COMPONENTS
    

    모니터링이 사용 설정되어 있지 않으면 다음 명령어를 실행하여 사용 설정합니다.

    gcloud container clusters update CLUSTER_NAME --monitoring=SYSTEM
    
  2. 클러스터가 만들어진 지 또는 모니터링이 사용 설정된 지 얼마나 되었나요?

    새 클러스터의 측정항목이 Cloud Monitoring에 표시되는 데 최대 1시간이 걸릴 수 있습니다.

  3. 클러스터에서 실행되는 heapster 또는 gke-metrics-agent(OpenTelemetry Collector)가 "kube-system" 네임스페이스에 있나요?

    클러스터에 리소스가 부족하므로 이 Pod가 워크로드를 예약하지 못할 수 있습니다. kubectl get pods --namespace=kube-system을 호출하고 이름에 heapster 또는 gke-metrics-agent가 있는 Pod를 찾아 Heapster 또는 OpenTelemetry가 실행 중인지 확인합니다.

  4. 클러스터의 제어 영역이 노드와 통신할 수 있나요?

    Cloud Monitoring이 작동하려면 마스터가 노드와 통신해야 합니다. 다음 명령어를 실행하면 마스터가 노드와 통신하는지 확인할 수 있습니다.

    kubectl logs POD_NAME
    

    이 명령어가 오류를 반환하면 SSH 터널이 문제의 원인일 수 있습니다. 자세한 내용은 이 섹션을 참조하세요.

Cloud Logging 에이전트와 관련된 문제가 있으면 문제해결 문서를 참조하세요.

자세한 내용은 로깅 문서를 참조하세요.

공유 VPC 클러스터의 계정 권한 누락

공유 VPC 클러스터의 경우 서비스 프로젝트의 GKE 서비스 계정에 호스트 프로젝트의 호스트 서비스 에이전트 사용자 역할에 대한 바인딩이 있는지 확인합니다. gcloud CLI를 사용하여 이 작업을 수행할 수도 있습니다.

역할 바인딩이 있는지 확인하려면 호스트 프로젝트에서 다음 명령어를 실행합니다.

gcloud projects get-iam-policy PROJECT_ID \
  --flatten="bindings[].members" \
  --format='table(bindings.role)' \
  --filter="bindings.members:SERVICE_ACCOUNT_NAME

다음을 바꿉니다.

  • PROJECT_ID: 호스트 프로젝트 ID입니다.
  • SERVICE_ACCOUNT_NAME: GKE 서비스 계정 이름입니다.

출력에서 roles/container.hostServiceAgentUser 역할을 찾습니다.

ROLE
...
roles/container.hostServiceAgentUser
...

목록에 hostServiceAgentUser 역할이 없으면 호스트 서비스 에이전트 사용자 역할 부여의 안내를 따라 서비스 계정에 바인딩을 추가합니다.

Google Cloud 프로젝트로 기본 서비스 계정 복원

GKE의 기본 서비스 계정인 container-engine-robot이 실수로 프로젝트에서 결합 해제될 수 있습니다. GKE Service Agent는 서비스 계정에 클러스터 리소스를 관리할 권한을 부여하는 Identity and Access Management(IAM) 역할입니다. 서비스 계정에서 이 역할 바인딩을 제거하면 기본 서비스 계정이 프로젝트에서 바인딩 해제되어 애플리케이션 배포와 기타 클러스터 작업 수행이 불가능해질 수 있습니다.

gcloud CLI 또는 Google Cloud 콘솔을 사용하여 프로젝트에서 서비스 계정이 삭제되었는지 확인할 수 있습니다.

gcloud

다음 명령어를 실행합니다.

gcloud projects get-iam-policy PROJECT_ID

PROJECT_ID를 프로젝트 ID로 바꿉니다.

콘솔

Google Cloud 콘솔에서 IAM 및 관리자 페이지로 이동합니다.

명령어나 대시보드에 서비스 계정 중 container-engine-robot이 표시되지 않으면 서비스 계정이 결합 해제된 것입니다.

GKE Service Agent 역할 결합을 삭제했으면 다음 명령어를 실행하여 역할 결합을 복원합니다.

PROJECT_NUMBER=$(gcloud projects describe "PROJECT_ID" --format 'get(projectNumber)')
gcloud projects add-iam-policy-binding PROJECT_ID \
  --member "serviceAccount:service-${PROJECT_NUMBER?}@container-engine-robot.iam.gserviceaccount.com" \
  --role roles/container.serviceAgent

역할 결합이 부여되었는지 확인하려면 다음 명령어를 실행합니다.

gcloud projects get-iam-policy $PROJECT_ID

container.serviceAgent 역할과 함께 서비스 계정 이름이 표시되면 역할 결합이 부여된 것입니다. 예를 들면 다음과 같습니다.

- members:
  - serviceAccount:service-1234567890@container-engine-robot.iam.gserviceaccount.com
  role: roles/container.serviceAgent

Compute Engine 기본 서비스 계정 사용 설정

일반적으로 Compute Engine 기본 서비스 계정인 노드 풀에 사용된 서비스 계정이 사용 중지된 경우 노드가 클러스터에 등록되지 않을 수 있습니다.

gcloud CLI 또는 Google Cloud 콘솔을 사용하여 프로젝트에서 서비스 계정이 사용 중지되었는지 확인할 수 있습니다.

gcloud

다음 명령어를 실행합니다.

gcloud iam service-accounts list  --filter="NAME~'compute' AND disabled=true"

콘솔

Google Cloud 콘솔에서 IAM 및 관리자 페이지로 이동합니다.

명령어 또는 대시보드에 서비스 계정이 사용 중지된 것으로 표시되면 다음 명령어를 실행하여 서비스 계정을 사용 설정합니다.

gcloud iam service-accounts enable PROJECT_ID-compute@developer.gserviceaccount.com

PROJECT_ID를 프로젝트 ID로 바꿉니다.

이렇게 해도 노드 등록 문제가 해결되지 않으면 노드 등록 문제 해결에서 추가 문제 해결 안내를 참조하세요.

노드 할당 가능을 사용 설정한 후 포드가 대기 중 상태에서 멈춤

노드 할당 가능을 사용 설정한 후 pod가 대기 중 상태에서 멈추는 문제가 발생하면 다음 사항에 유의하세요.

1.7.6 버전부터는 GKE에서 Docker 및 운영체제를 포함하여 Kubernetes 오버헤드에 사용할 CPU와 메모리를 예약합니다. Pod에서 각 머신 유형별로 예약 가능한 양에 대한 자세한 내용은 클러스터 아키텍처를 참조하세요.

업그레이드 후 pod가 대기 중이면 다음을 수행하는 것이 좋습니다.

  • pod의 CPU 및 메모리 요청이 최대 사용량을 초과하지 않는지 확인합니다. GKE에서 오버헤드에 사용할 CPU와 메모리를 예약하는 반면 Pod는 이러한 리소스를 요청할 수 없습니다. Pod가 사용량 보다 많은 CPU 또는 메모리를 요청하면 다른 Pod가 이러한 리소스를 요청하지 못하게 되어 클러스터 사용률이 떨어질 수 있습니다. 자세한 내용은 리소스 요청이 있는 pod 예약 방법을 참조하세요.

  • 클러스터 크기를 조정해 봅니다. 자세한 내용은 클러스터 크기 조절을 참조하세요.

  • 클러스터를 다운그레이드하여 이 변경사항을 되돌립니다. 자세한 내용은 클러스터 또는 노드 풀 수동 업그레이드를 참조하세요.

클러스터의 루트 인증 기관이 곧 만료됨

클러스터의 루트 인증 기관이 곧 만료됩니다. 일반적인 클러스터 작업이 중단되지 않도록 하려면 사용자 인증 정보 순환을 수행해야 합니다.

"'Foo' 인스턴스에 'instance-template' 메타데이터가 포함되지 않음" 오류 표시

업그레이드, 확장, 자동 노드 복구 수행이 실패하는 노드 풀의 상태로 "'Foo' 인스턴스에 'instance-template' 메타데이터가 포함되지 않음" 오류가 표시될 수 있습니다.

이 메시지는 GKE에서 할당된 VM 인스턴스의 메타데이터가 손상되었음을 나타냅니다. 이는 일반적으로 커스텀 방식으로 작성된 자동화 또는 스크립트가 새 인스턴스 메타데이터를 추가하려고 시도할 때(예: block-project-ssh-keys) 그리고 값을 추가하거나 업데이트하는 대신 기존 메타데이터를 삭제할 때 발생합니다. 커스텀 메타데이터 설정에서 VM 인스턴스 메타데이터에 대해 알아볼 수 있습니다.

중요한 메타데이터 값(특히 instance-template, kube-labels, kubelet-config, kubeconfig, cluster-name, configure-sh, cluster-uid)이 삭제된 경우 이러한 값이 GKE 운영에 중요하기 때문에 노드 또는 전체 노드 풀이 불안정한 상태로 전환될 수 있습니다.

인스턴스 메타데이터가 손상된 경우 메타데이터를 복구하는 가장 좋은 방법은 손상된 VM 인스턴스가 포함된 노드 풀을 다시 만드는 것입니다. 클러스터에 노드 풀을 추가하고 새 노드 풀에서 노드 수를 늘려야 하며, 다른 노드 풀에서는 노드를 차단하고 삭제해야 합니다. 노드 풀 간의 워크로드 마이그레이션 안내를 참조하세요.

인스턴스 메타데이터를 수정한 사람과 시간을 찾으려면 Compute Engine 감사 로깅 정보를 검토하거나 다음과 비슷한 검색어로 로그 탐색기를 사용해서 로그를 찾을 수 있습니다.

resource.type="gce_instance_group_manager"
protoPayload.methodName="v1.compute.instanceGroupManagers.setInstanceTemplate"

로그에서 요청 시작자 IP 주소 및 사용자 에이전트를 찾을 수 있습니다.

requestMetadata: {
  callerIp: "REDACTED"
  callerSuppliedUserAgent: "google-api-go-client/0.5 GoogleContainerEngine/v1"
}

Cloud KMS 키가 중지된 경우

GKE의 기본 서비스 계정이 Cloud KMS 키에 액세스할 수 없으면 다음 오류 메시지가 표시됩니다.

Cluster problem detected (Kubernetes Engine Service Agent account unable to use CloudKMS key configured for Application Level encryption).

이 문제를 해결하려면 사용 중지된 키 다시 사용 설정을 수행합니다.

GKE의 보안 비밀에 대한 자세한 내용은 애플리케이션 레이어에서 보안 비밀 암호화를 참조하세요.