공부하고 기록하는, 경제학과 출신 개발자의 노트

학습일지/kubernetes

kubernetes Dynamic Informers with client-go

inspirit941 2023. 7. 25. 14:46
반응형

Watching Kubernetes custom resources with dynamic informers & golang

https://youtu.be/fBY8sVVjM2s

k8s Operator를 만들 때, CRD의 reconcile 로직을 적용하기 위해 Get / List Loop를 쓰는 경우가 있다.

  • ineffective / slow way to find changes.
    • 예컨대 리소스가 backoff 상태라면 Get / List 요청을 보내는 주기가 갈수록 느려진다.
    • 리소스가 많을 경우 pagination 등... 고려할 것들이 늘어남
    • client go에서 제공하는 (shared) cache를 사용해서 보완하기도 함
  • 위의 방식들보다 더 나은, InformerFactory를 사용해서 Watcher를 만드는 방법
    • Watcher: Event Stream that is dynamically connected; like a pipe from API server to your Implementation.
      • send back & forth events over GRPC.
      • get Real-time updates. Restful Request를 매번 주고받는 게 아니라 single Event Stream을 받는다.
  • client go에서 informer 관련 구현체는 문서화가 덜 되어 있는 편임.

https://aly.arriqaaq.com/kubernetes-informers/

 

A Deep Dive Into Kubernetes Informers

I wanted to understand more about how Kubernetes controllers are implemented. Building controllers with controller-runtime [https://github.com/kubernetes-sigs/kubebuilder] is pretty easy but it masks many details on how the event-oriented architecture of c

aly.arriqaaq.com

Screenshot-2021-10-03-at-12 07 12-PM

 

구현할 것: Dynamic Shared Informer Factory.

package main
import (
"log"
"os"
"time"
"github.com/open-feature/open-feature-operator/apis/core/v1alpha1"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/dynamic/dynamicinformer"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
)
func buildConfiguration() (*rest.Config, error) {
kubeconfig := os.Getenv("KUBECONFIG")
var clusterConfig *rest.Config
var err error
if kubeconfig != "" {
clusterConfig, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
} else {
clusterConfig, err = rest.InClusterConfig()
}
if err != nil {
return nil, err
}
return clusterConfig, nil
}
func main() {
clusterConfig, err := buildConfiguration()
if err != nil {
panic(err)
}
// traditional k8s client 대신 dynamic 패키지 사용.
clusterClient, err := dynamic.NewForConfig(clusterConfig)
if err != nil {
log.Fatalln(err)
}
// CRD operator에서 제공하는 Resource 정보.
resource := v1alpha1.GroupVersion.WithResource("featureflagconfigurations")
// shared Informer factory 생성. look at several different clsuter resources simultaneously.
//// resync time: cache between listing.
factory := dynamicinformer.NewFilteredDynamicSharedInformerFactory(clusterClient,
time.Minute, "", nil)
informer := factory.ForResource(resource).Informer()
// event handler 추가.
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
log.Println("AddFunc")
},
UpdateFunc: func(oldObj, newObj interface{}) {
log.Println("UpdateFunc")
// 이벤트 발생했을 때 interface{}를 필요한 리소스로 매핑하는 형태로 사용 가능.
// ex)
// var featureflagObject v1alpha1.FeatureFlagConfiguration
//err := runtime.DefaultUnstructuredConverter.FromUnstructured(newObj, (*unstructured.Unstructured).Object, &featureflagObject)
// if err != nil {
// log.Println(err.Error())
// }
},
DeleteFunc: func(obj interface{}) {
log.Println("DeleteFunc")
},
})
// informer에 context를 추가하거나 inline channel을 넣는다.
informer.Run(make(chan struct{}))
}
view raw main.go hosted with ❤ by GitHub

 

 

더 자세한 내용은 https://blog.dsb.dev/posts/creating-dynamic-informers/ 서 확인할 수 있다.

 

Go: Creating Dynamic Kubernetes Informers

Introduction Recently, I published v1.0.0 of Kollect, a dynamic Kubernetes informer that publishes changes in cluster resources to a configurable event bus. At the heart of this project is a dynamic informer, a method of handling add/update/delete notifica

blog.dsb.dev

 

반응형