Kubernetes

client-go library의 Reflector, Informer, Indexer 역할

DevOps Engineer 2025. 3. 2. 11:15
728x90

client-go 라이브러리는 Kubernetes API와 상호 작용하기 위한 Go 라이브러리이며, 클라이언트 애플리케이션이 Kubernetes 리소스를 효율적으로 관리할 수 있도록 도와줍니다.
이 중에서 Reflector, Informer, Indexer는 Kubernetes API 데이터를 효율적으로 캐싱하고 동기화하는 핵심 컴포넌트입니다.

 

1️⃣ Reflector

🔹 개념

  • Reflector는 Kubernetes API 서버에서 특정 리소스를 감시하고, 변경 사항을 감지하여 로컬 캐시(Store)에 데이터를 동기화하는 역할을 합니다.
  • API 서버의 watch 기능을 사용하여 새로운 리소스, 수정된 리소스, 삭제된 리소스를 감지합니다.

🔹 동작 방식

  1. API 서버에 LIST 요청을 보내 기존 리소스를 가져옵니다.
  2. API 서버의 WATCH 스트림을 감시하여 변경 사항을 실시간으로 감지합니다.
  3. 변경된 데이터를 Store에 업데이트합니다.

🔹 예제 코드 (Reflector 사용)

package main

import (
	"context"
	"fmt"
	"time"

	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
)

func main() {
	// Kubernetes 클라이언트 생성
	config, _ := rest.InClusterConfig()
	client, _ := dynamic.NewForConfig(config)

	// 감시할 리소스 설정 (예: Pods)
	gvr := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}

	// Reflector 생성 및 실행
	store := cache.NewStore(cache.MetaNamespaceKeyFunc)
	reflector := cache.NewReflector(
		cache.NewListWatchFromClient(client.Resource(gvr), "pods", "", cache.Indexers{}),
		&cache.ResourceEventHandlerFuncs{},
		store,
		5*time.Minute,
	)

	stopCh := make(chan struct{})
	go reflector.Run(stopCh)

	// 일정 시간 후 캐시 확인
	time.Sleep(10 * time.Second)
	for _, obj := range store.List() {
		fmt.Println(obj)
	}
}

 

🔹 주요 특징

  • API 서버 부하 감소: 클라이언트가 계속해서 API 서버를 호출하지 않고, Reflector가 최신 상태를 유지함.
  • 고속 데이터 조회: Reflector는 Store를 사용해 데이터를 캐싱하므로 빠르게 조회 가능.
  • WATCH 스트림 활용: API 서버의 watch 기능을 사용하여 변경 사항을 실시간으로 반영.

 

2️⃣ Informer

🔹 개념

  • Informer는 Reflector를 내부적으로 사용하며, Kubernetes 리소스의 변경 사항을 감지하고 이를 애플리케이션에 알리는 역할을 합니다.
  • 이벤트 기반으로 작동하며, AddFunc, UpdateFunc, DeleteFunc 핸들러를 통해 변경 사항을 감지할 수 있습니다.

🔹 동작 방식

  1. Reflector를 사용하여 Kubernetes API 서버에서 데이터를 가져옴.
  2. 데이터를 로컬 캐시에 저장하고, 필요한 경우 Indexer를 사용해 검색을 최적화함.
  3. 리소스 변경 이벤트가 발생하면 EventHandlerFuncs를 통해 콜백 함수를 호출.

🔹 예제 코드 (Informer 사용)

package main

import (
	"context"
	"fmt"
	"time"

	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

func main() {
	// Kubernetes 클라이언트 생성
	config, _ := rest.InClusterConfig()
	clientset, _ := kubernetes.NewForConfig(config)

	// Shared Informer Factory 생성 (Pod 리소스 감시)
	factory := informers.NewSharedInformerFactory(clientset, 30*time.Second)
	podInformer := factory.Core().V1().Pods().Informer()

	// 이벤트 핸들러 등록
	podInformer.AddEventHandler(
		cache.ResourceEventHandlerFuncs{
			AddFunc: func(obj interface{}) {
				fmt.Println("Pod 추가됨:", obj)
			},
			UpdateFunc: func(oldObj, newObj interface{}) {
				fmt.Println("Pod 업데이트됨:", newObj)
			},
			DeleteFunc: func(obj interface{}) {
				fmt.Println("Pod 삭제됨:", obj)
			},
		},
	)

	// Informer 실행
	stopCh := make(chan struct{})
	go podInformer.Run(stopCh)

	// 실행 지속
	wait.NeverStop()
}

 

🔹 주요 특징

  • Reflector 포함: API 서버에서 데이터를 가져오고 Watch 스트림을 유지.
  • 비동기 이벤트 처리: 리소스가 변경될 때만 핸들러가 실행됨.
  • 고성능 데이터 조회: 내부적으로 캐시와 Indexer를 사용하여 API 서버 호출을 최소화.

 

3️⃣ Indexer

🔹 개념

  • Indexer는 Informer가 관리하는 캐시 데이터를 특정 키 값으로 인덱싱하여 빠르게 검색할 수 있도록 도와줍니다.
  • 기본적으로 Informer는 cache.Store를 사용하지만, Indexer를 추가하면 다양한 기준으로 데이터를 효율적으로 검색 가능합니다.

🔹 동작 방식

  1. Informer가 데이터를 받아 캐시에 저장할 때 Indexer도 함께 업데이트됨.
  2. 특정 키 또는 필터 기준을 기반으로 빠르게 데이터 조회 가능.

🔹 예제 코드 (Indexer 사용)

package main

import (
	"fmt"

	v1 "k8s.io/api/core/v1"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
)

func main() {
	// Kubernetes 클라이언트 생성
	config, _ := rest.InClusterConfig()
	clientset, _ := kubernetes.NewForConfig(config)

	// Shared Informer Factory 생성
	factory := informers.NewSharedInformerFactory(clientset, 0)
	podInformer := factory.Core().V1().Pods().Informer()

	// Indexer 추가 (Pod의 Node 이름을 키로 저장)
	indexer := podInformer.GetIndexer()
	indexer.AddIndexers(cache.Indexers{
		"nodeName": func(obj interface{}) ([]string, error) {
			pod := obj.(*v1.Pod)
			return []string{pod.Spec.NodeName}, nil
		},
	})

	// Informer 실행
	stopCh := make(chan struct{})
	go podInformer.Run(stopCh)

	// 일정 시간 대기 후 Indexer 검색
	// 특정 노드에서 실행 중인 Pod 조회
	nodePods, _ := indexer.ByIndex("nodeName", "worker-node-1")
	fmt.Println("worker-node-1에서 실행 중인 Pod 목록:", nodePods)
}

 

🔹 주요 특징

  • 고속 검색 가능: 특정 필드(예: nodeName)로 데이터 검색 속도를 개선.
  • API 서버 부하 감소: API 서버를 직접 호출하지 않고 캐시에서 데이터 조회 가능.
  • 사용자 정의 인덱스 가능: 여러 개의 키를 기반으로 데이터를 조회할 수 있음.

 

정리

💡 Informer는 Reflector를 포함하고, Indexer는 Informer의 캐시를 최적화하는 역할을 한다! 🚀

 
 
728x90