IT/Infra&Cloud

[gcp] GKE troubleshooting

Hayley Shim 2023. 10. 29. 01:01

안녕하세요. 최근 GCP 내 cluster managed service인 GKE 서비스를 사용하며 경험한 이슈를 공유하기 위해 작성한 글입니다. GKE에 대한 GCP troubleshooting 공식 문서를 참고하면 더 다양한 사례를 알 수 있습니다.

issue) Private GKE to Private GCR image pull error

  • VPC 환경 내 private subnet 대역에 구성한 GKE에서 다른 private subnet 대역에 위치한 GCR 서비스에 있는 image를 pull하지 못하는 에러 발생

[참고 자료]

[1] https://cloud.google.com/kubernetes-engine/docs/troubleshooting#private-registry

[2] https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry

[3] https://cloud.google.com/kubernetes-engine/docs/troubleshooting#container-registry

[4] https://cloud.google.com/kubernetes-engine/docs/troubleshooting#error-403-permissions

Prerequisites

  • Container Registry API 사용
  • image가 이미 비공개 레지스트리에 Push 된 상태
  • 프로젝트에 설치/구성된 Terraform
  • Terraform에 대한 일반적인 이해
  • 프로젝트에 gcloud SDK를 설치/구성

Terraform SA 권한 추가

아래와 같이 GKE 리소스 내에 GCR 이미지를 pull 할 수 있는 서비스 계정을 추가해줍니다.

  • storage.objectViewer (view and get objects, i.e. container images)
  • artifactregistry.reader (view and get artifacts, i.e. container manifests)
terraform {
  ...
}
resource “google_service_account” “gcr_pull” {
  account_id = “service-account-gcr-pull”
  display_name = “Service Account for Pulling images from GCR”
}
resource “google_project_iam_member” “storage_viewer” {
  count = 1
  project = var.project
  role = “roles/storage.objectViewer”
  member = “serviceAccount:${google_service_account.gcr_pull.email}”
}
resource “google_project_iam_member” “artifact_reader” {
  count = 1
  project = var.project
  role = “roles/artifactregistry.reader”
  member = “serviceAccount:${google_service_account.gcr_pull.email}”
}
output "service_account_email" {
  description = "Service account email (for single use)."
  value       = google_service_account.gcr_pull.email
}

서비스 계정이 생성되면 GCR 개인 레지스트리에 서비스 계정으로 인증하기 위한 개인 키를 생성해야 합니다. 이는 CI/CD 파이프라인 및 기타 자동화 프로세스에 유용하게 사용할 수 있습니다.

개인 키는 아래와 같이 gcloud 명령어를 통해 생성하거나 console에서 생성할 수 있습니다.(json 형식)

gcloud iam service-accounts keys create <output_filename> --iam-account=<account_email>

Pulling images on GKE

  • 클러스터 노드는 이전에 만든 서비스 계정을 사용합니다.
  • Kubernetes 리소스는 gcp pull 권한을 가진 서비스 계정의 키를 활용하여 secret을 생성합니다.
# Terraform GKE node pool; adding the service account to you nodes
resource "google_container_node_pool" "node_pool" {
  
  ...
    
    node_config {
    machine_type = var.machine_type
    image_type = var.image_type
    disk_size_gb = var.disk_size_gb
    disk_type = var.disk_type
    preemptible = var.preemptible
    service_account = var.service_account_email
  }
}

secret 설정

kubectl create secret docker-registry gcr-pull-secret \
--namespace my-custom-app \
--docker-server=https://gcr.io \
--docker-username=_json_key \
--docker-password="$(cat service_account_key.json)" \
--docker-email='<service_account_email>'

이제 제공된 네임스페이스에서 secret을 사용할 수 있고 생성된 secret을 사용하도록 pod를 설정할 수 있습니다.

apiVersion: v1
kind: Pod
metadata:
  name: test-private-registry
spec:
  containers:
  - name: private-registry-container
    image: gcr.io/test/my-app:4.5.6
  imagePullSecrets:
  - name: gcr-pull-secret

GKE의 자원 내 GCR에 image를 pull 할 수 있는 권한이 있고 해당 Service Account이 키 값을 가지고 secret을 생성한 후 Pod에 넣어줬기 때문에 이제 Private GKE에서 GCR로부터 이미지를 pull 할 수 있습니다.

issue) Can’t access from local to Private GKE pod service

  • local 환경에서 Private GKE 내 위치한 pod service로 접속이 안되는 상황
  • pod에 istio ingress controller를 통해 internal load balancer를 생성한 상황으로 해당 lb로 접근이 안됨

[참고 자료]

[1] https://cloud.google.com/kubernetes-engine/docs/how-to/internal-load-balance-ingress?hl=ko

[2] https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/

이 경우 local 환경의 On-prem 환경과 GCP VPC 상의 라우팅 연결이 안되어 있어 라우팅 설정을 통해 해결해주었습니다. traceroute 등으로 네트워크 경로확인을 통해 어느 구간까지 통신 연결이 되었는지 확인이 필요합니다.

issue) Can’t access to Pod to other CSP service(AWS Landing zone)

  • 다른 CSP 랜딩존에 있는 서비스로 Pod가 접근하지 못하는 상황

주변의 조언을 통해 아래와 같은 이유로 pod 내에서 low 레벨의 네트워크 트러블슈팅을 확인하기란 쉽지 않다는 얘기를 들었습니다.

  1. cni 별로 통신 방법이 다름
  2. 다른 방식에 맞게 tcpdmp 필터링을 써야됨
  3. kube-proxy 방식(ipvs, ebpf 등)도 차이가 있다면 이 역시 다른 방식으로 확인 필요
  4. service 를 CSP마다 자사의 LB로 처리하게 되면 이 역시 각 환경에 맞게 확인
  5. 오히려 istio 등의 애플리케이션 단위에서 필요한 구간별 문제를 확인하는것이 빠를수도 있음

위와 같은 이유로 쿠버네티스 내부 간 통신 flow 를 전부 따라가면서 확인하는게 쉽지 않은듯합니다. 그럼에도 불구하고 아래와 같이 한번 pod 내에 tcpdump 등을 통해 패킷이 어디까지 나가는지 확인해봤습니다.

pod packect tcpdump
tcpdump -i any -w gke-capture.pcap

wireshark 을 통해 패킷을보니 pod에서 해당 서비스 목적지 ip까지 통신이 되지 않고 gke node 에서 막히는 것으로 파악되었습니다. GCP의 네트워크 연결 테스트 서비스를 통해 source에서 destination 까지 구간별 막힌 방화벽이 있는지 체크해보았으나 GCP 환경 내의 네트워크 이슈는 없었습니다. 다만, gke 클러스터 내에서 외부로 통신이 되지 않아 관련 원인을 찾아봤습니다.

[참고 자료]

[1] https://cloud.google.com/kubernetes-engine/docs/concepts/ip-masquerade-agent?hl=ko

[2] https://cloud.google.com/kubernetes-engine/docs/how-to/ip-masquerade-agent

현재 GCP 상의 Kube 서비스는 Pod, Service IP에 대한 과점 이슈 회피를 위해 비공식 IP 대역(240.0.0.0/4)을 사용했습니다.(gke 버전 1.14.2-gke.1 이상)

위 IP 대역을 사용하면서 VPC 외부 NW(on-prem 또는 다른 CSP의 VPC) 로 통신이 필요한 경우 해당 IP 대역에 대한 routing이 안되는 상황이었습니다. routing이 불가능한 IP 대역에 대해 통신이 필요할 경우 NAT가 되야하는데 기본적으로 설정된 대역과 겹칠 수 있어 수정이 필요합니다.

GKE 기본 비매스커레이드 대상 범위

위를 수정하기 위해 config라는 파일을 생성하고 configmap을 kube-system namespace에 생성해줍니다.

nonMasqueradeCIDRs:
  - 172.16.0.0/12
  - 192.168.0.0/16
  - 100.64.0.0/10
  - 192.0.0.0/24
  - 192.0.2.0/24
  - 192.88.99.0/24
  - 198.18.0.0/15
  - 198.51.100.0/24
  - 203.0.113.0/24
  - 240.0.0.0/4
  - 10.4.192.128/25 #GKE Cluster 대역 추가
masqLinkLocal: true
resyncInterval: 60 #SYNC_INTERVALUNIT_OF_TIME

GKE는 다음 조건에서 IP 매스커레이딩이나 SNAT를 수행합니다.

표준 모드의 클러스터:

위와 같이 GKE에 IP 매스커레이딩을 사용하여 pod에서 전송된 패킷의 소스 IP 주소를 변경하였습니다. pod에서 내보내는 패킷에 IP 매스커레이딩이 적용되면 GKE는 패킷 소스 주소를 pod IP에서 기본 노드의 IP 주소로 변경합니다.

ip-masq-agent ConfigMap을 생성해주고 ip-masq-agent DaemonSet을 재기동해줍니다.

kubectl create configmap ip-masq-agent \
   --namespace=kube-system \
   --from-file=config --namespace kube-system
pod packet capture(정상동작)
pod packet capture(정상동작)

위와 같이 gke pod(240.133.48.60)과 gke node(10.4.192.135)가 정상적인 handshaking을 맺고 gke node 밖으로 NAT를 통해 destination ip(10.1.125.70)까지 통신되는 것을 확인할 수 있습니다.

참고자료

아래와 같이 CSP에서는 VPC 내 연결 테스트를 할 수 있는 서비스를 지원하고 있습니다.

1. 연결테스트

1) GCP

GCP 연결 테스트 화면

2) AWS

2. k8s nw 관련

 

'IT > Infra&Cloud' 카테고리의 다른 글

[aws] IAM identity providers(SAML)  (0) 2023.10.29
[aws] AppStream 2.0  (0) 2023.10.29
[aws] Security  (0) 2023.10.29
[csp]Hierarchy Architecure & API/API Gateway  (0) 2023.10.29
[gcp] GKE Implementation & CLI Configuration  (0) 2023.10.29