欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用client go實(shí)現(xiàn)自定義控制器的方法

 更新時(shí)間:2022年05月12日 09:47:59   作者:油膩中年李大鵝  
本文我們來(lái)使用client-go實(shí)現(xiàn)一個(gè)自定義控制器,通過(guò)判斷service的Annotations屬性是否包含ingress/http,如果包含則創(chuàng)建ingress,如果不包含則不創(chuàng)建,對(duì)client go自定義控制器相關(guān)知識(shí)感興趣的朋友一起看看吧

介紹

我們已經(jīng)知道,Service對(duì)集群之外暴露服務(wù)的主要方式有兩種:NodePort和LoadBalancer,但是這兩種方式,都有一定的缺點(diǎn):

  • NodePort方式的缺點(diǎn)是會(huì)占用很多集群機(jī)器的端口,那么當(dāng)集群服務(wù)變多的時(shí)候,這個(gè)缺點(diǎn)就愈發(fā)明顯。
  • LoadBalancer的缺點(diǎn)是每個(gè)Service都需要一個(gè)LB,浪費(fèi),麻煩,并且需要Kubernetes之外的設(shè)備的支持。

基于這種現(xiàn)狀,Kubernetes提供了Ingress資源對(duì)象,Ingress只需要一個(gè)NodePort或者一個(gè)LB就可以滿足暴露多個(gè)Service的需求。

客戶端首先對(duì) 域名 執(zhí)行 DNS 解析,得到 Ingress Controller 所在節(jié)點(diǎn)的 IP,然后客戶端向 Ingress Controller 發(fā)送 HTTP 請(qǐng)求,然后根據(jù) Ingress 對(duì)象里面的描述匹配域名,找到對(duì)應(yīng)的 Service 對(duì)象,并獲取關(guān)聯(lián)的 Endpoints 列表,將客戶端的請(qǐng)求轉(zhuǎn)發(fā)給其中一個(gè) Pod。

本文我們來(lái)使用client-go實(shí)現(xiàn)一個(gè)自定義控制器,通過(guò)判斷serviceAnnotations屬性是否包含ingress/http,如果包含則創(chuàng)建ingress,如果不包含則不創(chuàng)建。而且如果存在ingress則進(jìn)行刪除。

具體實(shí)現(xiàn)

首先我們創(chuàng)建項(xiàng)目。

$ mkdir ingress-manager && cd ingress-manager
$ go mod init ingress-manager
# 由于控制器部分的內(nèi)容比較多,將它們單獨(dú)放到pkg目錄下
$ mkdir pkg
# 最終項(xiàng)目目錄結(jié)構(gòu)如下
.
├── go.mod
├── go.sum
├── main.go
└── pkg
    └── controller.go

接著我們來(lái)實(shí)現(xiàn)controller部分:

package pkg
import (
	"context"
	apiCoreV1 "k8s.io/api/core/v1"
	netV1 "k8s.io/api/networking/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	informersCoreV1 "k8s.io/client-go/informers/core/v1"
	informersNetV1 "k8s.io/client-go/informers/networking/v1"
	"k8s.io/client-go/kubernetes"
	coreV1 "k8s.io/client-go/listers/core/v1"
	v1 "k8s.io/client-go/listers/networking/v1"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/workqueue"
	"reflect"
	"time"
)
const (
	workNum  = 5  // 工作的節(jié)點(diǎn)數(shù)
	maxRetry = 10 // 最大重試次數(shù) 
)
// 定義控制器
type Controller struct {
	client        kubernetes.Interface
	ingressLister v1.IngressLister
	serviceLister coreV1.ServiceLister
	queue         workqueue.RateLimitingInterface
}
// 初始化控制器
func NewController(client kubernetes.Interface, serviceInformer informersCoreV1.ServiceInformer, ingressInformer informersNetV1.IngressInformer) Controller {
	c := Controller{
		client:        client,
		ingressLister: ingressInformer.Lister(),
		serviceLister: serviceInformer.Lister(),
		queue:         workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "ingressManager"),
	}
	// 添加事件處理函數(shù)
	serviceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc:    c.addService,
		UpdateFunc: c.updateService,
	})
	ingressInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		DeleteFunc: c.deleteIngress,
	})
	return c
}
// 入隊(duì)
func (c *Controller) enqueue(obj interface{}) {
	key, err := cache.MetaNamespaceKeyFunc(obj)
	if err != nil {
		runtime.HandleError(err)
	}
	c.queue.Add(key)
}
func (c *Controller) addService(obj interface{}) {
	c.enqueue(obj)
}
func (c *Controller) updateService(oldObj, newObj interface{}) {
	// todo 比較annotation
	// 這里只是比較了對(duì)象是否相同,如果相同,直接返回
	if reflect.DeepEqual(oldObj, newObj) {
		return
	}
	c.enqueue(newObj)
}
func (c *Controller) deleteIngress(obj interface{}) {
	ingress := obj.(*netV1.Ingress)
	ownerReference := metaV1.GetControllerOf(ingress)
	if ownerReference == nil {
		return
	}
	// 判斷是否為真的service
	if ownerReference.Kind != "Service" {
		return
	}
	c.queue.Add(ingress.Namespace + "/" + ingress.Name)
}
// 啟動(dòng)控制器,可以看到開了五個(gè)協(xié)程,真正干活的是worker
func (c *Controller) Run(stopCh chan struct{}) {
	for i := 0; i < workNum; i++ {
		go wait.Until(c.worker, time.Minute, stopCh)
	}
	<-stopCh
}
func (c *Controller) worker() {
	for c.processNextItem() {
	}
}
// 業(yè)務(wù)真正處理的地方
func (c *Controller) processNextItem() bool {
	// 獲取key
	item, shutdown := c.queue.Get()
	if shutdown {
		return false
	}
	defer c.queue.Done(item)
  // 調(diào)用業(yè)務(wù)邏輯
	err := c.syncService(item.(string))
	if err != nil {
    // 對(duì)錯(cuò)誤進(jìn)行處理
		c.handlerError(item.(string), err)
		return false
	}
	return true
}

func (c *Controller) syncService(item string) error {
	namespace, name, err := cache.SplitMetaNamespaceKey(item)
	if err != nil {
		return err
	}
	// 獲取service
	service, err := c.serviceLister.Services(namespace).Get(name)
	if err != nil {
		if errors.IsNotFound(err) {
			return nil
		}
		return err
	}
	// 新增和刪除
	_, ok := service.GetAnnotations()["ingress/http"]
	ingress, err := c.ingressLister.Ingresses(namespace).Get(name)
	if err != nil && !errors.IsNotFound(err) {
		return err
	}
	if ok && errors.IsNotFound(err) {
		// 創(chuàng)建ingress
		ig := c.constructIngress(service)
		_, err := c.client.NetworkingV1().Ingresses(namespace).Create(context.TODO(), ig, metaV1.CreateOptions{})
		if err != nil {
			return err
		}
	} else if !ok && ingress != nil {
		// 刪除ingress
		err := c.client.NetworkingV1().Ingresses(namespace).Delete(context.TODO(), name, metaV1.DeleteOptions{})
		if err != nil {
			return err
		}
	}
	return nil
}
func (c *Controller) handlerError(key string, err error) {
	// 如果出現(xiàn)錯(cuò)誤,重新加入隊(duì)列,最大處理10次
	if c.queue.NumRequeues(key) <= maxRetry {
		c.queue.AddRateLimited(key)
		return
	}
	runtime.HandleError(err)
	c.queue.Forget(key)
}
func (c *Controller) constructIngress(service *apiCoreV1.Service) *netV1.Ingress {
	// 構(gòu)造ingress
	pathType := netV1.PathTypePrefix
	ingress := netV1.Ingress{}
	ingress.ObjectMeta.OwnerReferences = []metaV1.OwnerReference{
		*metaV1.NewControllerRef(service, apiCoreV1.SchemeGroupVersion.WithKind("Service")),
	}
	ingress.Namespace = service.Namespace
	ingress.Name = service.Name
	ingress.Spec = netV1.IngressSpec{
		Rules: []netV1.IngressRule{
			{
				Host: "example.com",
				IngressRuleValue: netV1.IngressRuleValue{
					HTTP: &netV1.HTTPIngressRuleValue{
						Paths: []netV1.HTTPIngressPath{
							{
								Path:     "/",
								PathType: &pathType,
								Backend: netV1.IngressBackend{
									Service: &netV1.IngressServiceBackend{
										Name: service.Name,
										Port: netV1.ServiceBackendPort{
											Number: 80,
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}
	return &ingress
}

接下來(lái)我們來(lái)實(shí)現(xiàn)main:

package main
import (
	"ingress-manager/pkg"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)
func main() {
	// 獲取config
	// 先嘗試從集群外部獲取,獲取不到則從集群內(nèi)部獲取
	var config, err = clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
	if err != nil {
		clusterConfig, err := rest.InClusterConfig()
		if err != nil {
			panic(err)
		}
		config = clusterConfig
	}
	// 通過(guò)config創(chuàng)建 clientSet
	clientSet, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err)
	}
	// 通過(guò) client 創(chuàng)建 informer,添加事件處理函數(shù)
	factory := informers.NewSharedInformerFactory(clientSet, 0)
	serviceInformer := factory.Core().V1().Services()
	ingressInformer := factory.Networking().V1().Ingresses()
	newController := pkg.NewController(clientSet, serviceInformer, ingressInformer)
	// 啟動(dòng) informer
	stopCh := make(chan struct{})
	factory.Start(stopCh)
	factory.WaitForCacheSync(stopCh)
	newController.Run(stopCh)
}

測(cè)試

首先創(chuàng)建deploy和service:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      app: my-nginx
  template:
    metadata:
      labels:
        app: my-nginx
    spec:
      containers:
        - name: my-nginx
          image: nginx:1.17.1
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    app: my-nginx
spec:
  ports:
    - port: 80
      protocol: TCP
      name: http
  selector:
    app: my-nginx

創(chuàng)建完成后進(jìn)行查看:

$ kubectl get deploy,service,ingress
NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-nginx          1/1     1            1           7m
NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   78d
service/my-nginx     ClusterIP   10.105.32.46   <none>        80/TCP    7m

上面的命令我分別獲取deploy,service,ingress,但是只獲取到了deployservice,這符合我們的預(yù)期。接著我們給service/m-nginx中的annotations添加ingress/http: nginx

$ kubectl edit service/my-nginx
apiVersion: v1
kind: Service
metadata:
  annotations:
    ingress/http: nginx
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"my-nginx"},"name":"my-nginx","namespace":"default"},"spec":{"ports":[{"name":"http","port":80,"protocol":"TCP"}],"selector":{"app":"my-nginx"}}}
      ......
service/my-nginx edited

重新進(jìn)行查看:

$ kubectl get deploy,service,ingress
NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/demo-deployment   1/1     1            1           41d
deployment.apps/my-nginx          1/1     1            1           11m
NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   78d
service/my-nginx     ClusterIP   10.105.32.46   <none>        80/TCP    11m
NAME                                 CLASS    HOSTS         ADDRESS   PORTS   AGE
ingress.networking.k8s.io/my-nginx   <none>   example.com             80      19s

接著我們?cè)賮?lái)測(cè)試下,將ingress/http: nginx注釋掉,看看ingress是否會(huì)自動(dòng)刪除:

$ kubectl get deploy,service,ingress
NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/demo-deployment   1/1     1            1           41d
deployment.apps/my-nginx          1/1     1            1           19m
NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   78d
service/my-nginx     ClusterIP   10.105.32.46   <none>        80/TCP    19m

我們發(fā)現(xiàn)和我們預(yù)期的效果一樣。

如果service被刪除了,ingress肯定也是不會(huì)存在的。這個(gè)這里就不多演示了。有興趣可以自行測(cè)試下。

到此這篇關(guān)于使用client-go實(shí)現(xiàn)自定義控制器的文章就介紹到這了,更多相關(guān)client-go自定義控制器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • go語(yǔ)言靜態(tài)庫(kù)的編譯和使用方法

    go語(yǔ)言靜態(tài)庫(kù)的編譯和使用方法

    這篇文章主要介紹了go語(yǔ)言靜態(tài)庫(kù)的編譯和使用方法,本文以windows平臺(tái)為例,通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • GO語(yǔ)言常用的文件讀取方式

    GO語(yǔ)言常用的文件讀取方式

    這篇文章主要介紹了GO語(yǔ)言常用的文件讀取方式,涉及一次性讀取、分塊讀取與逐行讀取等方法,是非常實(shí)用的技巧,需要的朋友可以參考下
    2014-12-12
  • golang croncli 定時(shí)器命令詳解

    golang croncli 定時(shí)器命令詳解

    定時(shí)器是執(zhí)行任務(wù)時(shí)的常用功能,配置系統(tǒng)的定時(shí)任務(wù)太麻煩,所以就想用golang簡(jiǎn)單實(shí)現(xiàn)一個(gè)定時(shí)器命令,包括定時(shí)器命令格式、定時(shí)執(zhí)行命令的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧
    2022-03-03
  • glow工具在命令行讀取Markdown好物分享

    glow工具在命令行讀取Markdown好物分享

    這篇文章主要為大家介紹了一款實(shí)用的命令行工具glow,這個(gè)CLI工具可以在命令行讀取Markdown,這對(duì)于碼農(nóng)來(lái)說(shuō)非常友好,使用起來(lái)也非常舒爽
    2022-07-07
  • GO語(yǔ)言臨界資源安全問(wèn)題的深入理解

    GO語(yǔ)言臨界資源安全問(wèn)題的深入理解

    臨界資源安全問(wèn)題也就是以往我們常聽到的線程安全問(wèn)題,本文詳細(xì)的介紹了GO語(yǔ)言臨界資源安全問(wèn)題的深入理解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Golang標(biāo)準(zhǔn)庫(kù)binary詳解

    Golang標(biāo)準(zhǔn)庫(kù)binary詳解

    這篇文章主要介紹了Golang標(biāo)準(zhǔn)庫(kù)binary的相關(guān)資料,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • 一文帶你了解GO語(yǔ)言中方法的應(yīng)用

    一文帶你了解GO語(yǔ)言中方法的應(yīng)用

    GO?語(yǔ)言中的方法實(shí)際上和函數(shù)是類似的,只不過(guò)在函數(shù)的基礎(chǔ)上多了一個(gè)參數(shù),這篇文章主要為大家介紹一下GO語(yǔ)言中方法的應(yīng)用,需要的可以參考下
    2023-09-09
  • 精選Golang高頻面試題和答案分享

    精選Golang高頻面試題和答案分享

    這篇文章給大家整理了17道Go語(yǔ)言中的高頻面試題和答案詳解,每道題都給出了代碼示例,方便大家更好的理解,需要的小伙伴可以收藏一下
    2023-06-06
  • go面向?qū)ο蠓绞讲僮鱆SON庫(kù)實(shí)現(xiàn)四則運(yùn)算

    go面向?qū)ο蠓绞讲僮鱆SON庫(kù)實(shí)現(xiàn)四則運(yùn)算

    這篇文章主要為大家介紹了go面向?qū)ο蠓绞讲僮鱆SON庫(kù)實(shí)現(xiàn)四則運(yùn)算的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • GO Cobra Termui庫(kù)開發(fā)終端命令行小工具輕松上手

    GO Cobra Termui庫(kù)開發(fā)終端命令行小工具輕松上手

    這篇文章主要為大家介紹了GO語(yǔ)言開發(fā)終端命令行小工具,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01

最新評(píng)論