https://gitee.com/zongzw/client-go-helloworld

所有代码示例及运行方式都在这个链接中。

网上讲解 informer和events原理的文章很多,但缺少入门级的使用示例,所以,我把它总结为代码,供初学者上手,先有个感性认识再说别的。

main.go

package main

import (
	"fmt"
	"os"
	"os/signal"
	"time"

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

// 处理信号,并及时关闭stopCh
func handleSignals(stopCh chan struct{}) {
	chSigs = make(chan os.Signal)
	signal.Notify(chSigs, os.Interrupt)
	<-chSigs
	close(stopCh)
}

var (
	stopCh      chan struct{}
	chSigs      chan os.Signal
	cfgInformer cache.SharedIndexInformer
	recorder    events.EventRecorder
)

func main() {

	stopCh = make(chan struct{})
	go handleSignals(stopCh)

	if len(os.Args) != 2 {
		fmt.Println("Usage: <program> <kube.config>")
		return
	}

	// 创建clientset,共informer和events 共用。
	kubeConf := os.Args[1]
	config, err := clientcmd.BuildConfigFromFlags("", kubeConf)
	if nil != err {
		panic(err)
	}
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}

	// Labelselector可以用来过滤仅需要关注的资源
	// matchLabelSelector := func(opts *metav1.ListOptions) {
	// 	// opts.LabelSelector = "somelabel=xyz"
	// }
	sharedInformerFactory := informers.NewSharedInformerFactoryWithOptions(
		clientset,
		30*time.Second,
		informers.WithNamespace("default"), // for test: limit resource scope to default.
		// informers.WithTweakListOptions(matchLabelSelector),
	)

	// 创建针对configmap的informer
	cfgInformer = sharedInformerFactory.Core().V1().ConfigMaps().Informer()

	// 为informer添加处理函数
	cfgInformer.AddEventHandler(&cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			abc := obj.(*v1.ConfigMap)
			fmt.Printf("add %s %s\n", abc.Namespace, abc.Name)
			recorder.Eventf(abc, nil, v1.EventTypeNormal, "Deployed", "", "object addition has been notified by informer")
		},
		UpdateFunc: func(old, cur interface{}) {
			orig := old.(*v1.ConfigMap)
			newa := cur.(*v1.ConfigMap)
			if orig.GetUID() != newa.GetUID() || orig.GetResourceVersion() != newa.GetResourceVersion() {
				fmt.Printf("%s %s -> %s %s\n", orig.Namespace, orig.Name, newa.Namespace, newa.Name)
				recorder.Eventf(newa, nil, v1.EventTypeNormal, "Deployed", "", "object update has been notified by informer")
			}
		},
		DeleteFunc: func(obj interface{}) {
			abc := obj.(*v1.ConfigMap)
			fmt.Printf("delete %s %s\n", abc.Namespace, abc.Name)
			recorder.Eventf(abc, nil, v1.EventTypeNormal, "Deployed", "", "object deletion has been notified by informer")
		},
	})

	// 创建EventRecorder 过程。
	eba := events.NewEventBroadcasterAdapter(clientset)
	recorder = eba.NewRecorder("my-event-recorder")

	// 开始工作
	eba.StartRecordingToSink(stopCh)
	sharedInformerFactory.Start(stopCh)

	doNilLoop()
}

func doNilLoop() {
	for {
		select {
		case <-stopCh:
			return
		case <-time.After(1 * time.Second):
			// do nothing
		}
	}
}

编译文件Makefile

# 编译两个平台的二进制静态文件,即不链接任何动态链接库。
binary_build:
	CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
	go build -ldflags '-s -w --extldflags "-static -fpic"' -o test-standalone-linux; \
	CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 \
	go build -ldflags '-s -w --extldflags "-static -fpic"' -o test-standalone-darwin

制作docker image启动:Dockerfile

# docker build -t test-standalone:latest -f Dockerfile .
#   因为编译出来的test-standalone-linux 不存在外部依赖,我们可以使用alpine:latest
#   作为base image,这样做出来的docker image只有40.3MB
FROM alpine:latest

COPY test-standalone-linux /
# 默认使用/kube.config 作为启动参数,详见程序实现main.go 和 docker-compose.yml 的卷部分volumes
CMD ["/test-standalone-linux", "/kube.config"]

运行示例及展示效果:docker-compose.yml

version: '3'
services:
  test-standalone:
    image: test-standalone:latest
    volumes:
      - /Users/zong/.kube/config:/kube.config

# 启动方式:
# docker-compose up -d --remove-orphans --force-recreate

# 之后,可以使用 docker logs查看日志
# docker logs -f client-go-helloworld_test-standalone_1

# 当我们使用以下命令和文件创建新的configmap的时候,就可以看到docker logs输出的日志。

# $ kubectl apply -f test.yaml

# 日志如下
  # add default cm-canary-template-configmap
  # delete default cm-canary-template-configmap

# 在k8s的event中也可以看到相关的时间报告。

# $ kubectl get events

  # LAST SEEN     TYPE     REASON       OBJECT               MESSAGE
  #   50s         Normal   Deployed     configmap/cm-canary  object addition has been notified by informer
  #   43s         Normal   Deployed     configmap/cm-canary  object deletion has been notified by informer

测试用test.yaml


---

apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-canary
  namespace: default
data:
  template: "abcdef"

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐