利用kubernetes资源锁完成自己的HA应用

博客 分享
0 249
张三
张三 2022-06-29 01:01:06
悬赏:0 积分 收藏

利用kubernetes资源锁完成自己的HA应用

Backgroud

前一章中,对kubernetes的选举原理进行了深度剖析,下面就通过一个example来实现一个,利用kubernetes提供的选举机制完成的高可用应用。

对于此章需要提前对一些概念有所了解后才可以继续看下去

  • leader election mechanism
  • RBCA
  • Pod runtime mechanism

Implementation

代码实现

如果仅仅是使用Kubernetes中的锁,实现的代码也只有几行而已。

package mainimport (	"context"	"flag"	"fmt"	"os"	"os/signal"	"syscall"	"time"	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"	clientset "k8s.io/client-go/kubernetes"	"k8s.io/client-go/rest"	"k8s.io/client-go/tools/clientcmd"	"k8s.io/client-go/tools/leaderelection"	"k8s.io/client-go/tools/leaderelection/resourcelock"	"k8s.io/klog/v2")func buildConfig(kubeconfig string) (*rest.Config, error) {	if kubeconfig != "" {		cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig)		if err != nil {			return nil, err		}		return cfg, nil	}	cfg, err := rest.InClusterConfig()	if err != nil {		return nil, err	}	return cfg, nil}func main() {	klog.InitFlags(nil)	var kubeconfig string	var leaseLockName string	var leaseLockNamespace string	var id string	// 初始化客户端的部分	flag.StringVar(&kubeconfig, "kubeconfig", "", "absolute path to the kubeconfig file")	flag.StringVar(&id, "id", "", "the holder identity name")	flag.StringVar(&leaseLockName, "lease-lock-name", "", "the lease lock resource name")	flag.StringVar(&leaseLockNamespace, "lease-lock-namespace", "", "the lease lock resource namespace")	flag.Parse()	if leaseLockName == "" {		klog.Fatal("unable to get lease lock resource name (missing lease-lock-name flag).")	}	if leaseLockNamespace == "" {		klog.Fatal("unable to get lease lock resource namespace (missing lease-lock-namespace flag).")	}	config, err := buildConfig(kubeconfig)	if err != nil {		klog.Fatal(err)	}	client := clientset.NewForConfigOrDie(config)	run := func(ctx context.Context) {		// 实现的业务逻辑,这里仅仅为实验,就直接打印了		klog.Info("Controller loop...")		for {			fmt.Println("I am leader, I was working.")			time.Sleep(time.Second * 5)		}	}	// use a Go context so we can tell the leaderelection code when we	// want to step down	ctx, cancel := context.WithCancel(context.Background())	defer cancel()	// 监听系统中断	ch := make(chan os.Signal, 1)	signal.Notify(ch, os.Interrupt, syscall.SIGTERM)	go func() {		<-ch		klog.Info("Received termination, signaling shutdown")		cancel()	}()	// 创建一个资源锁	lock := &resourcelock.LeaseLock{		LeaseMeta: metav1.ObjectMeta{			Name:      leaseLockName,			Namespace: leaseLockNamespace,		},		Client: client.CoordinationV1(),		LockConfig: resourcelock.ResourceLockConfig{			Identity: id,		},	}	// 开启一个选举的循环	leaderelection.RunOrDie(ctx, leaderelection.LeaderElectionConfig{		Lock:            lock,		ReleaseOnCancel: true,		LeaseDuration:   60 * time.Second,		RenewDeadline:   15 * time.Second,		RetryPeriod:     5 * time.Second,		Callbacks: leaderelection.LeaderCallbacks{			OnStartedLeading: func(ctx context.Context) {				// 当选举为leader后所运行的业务逻辑				run(ctx)			},			OnStoppedLeading: func() {				// we can do cleanup here				klog.Infof("leader lost: %s", id)				os.Exit(0)			},			OnNewLeader: func(identity string) { // 申请一个选举时的动作				if identity == id {					return				}				klog.Infof("new leader elected: %s", identity)			},		},	})}

注:这种lease锁只能在in-cluster模式下运行,如果需要类似二进制部署的程序,可以选择endpoint类型的资源锁。

生成镜像

这里已经制作好了镜像并上传到dockerhub(cylonchau/leaderelection:v0.0.2)上了,如果只要学习运行原理,则忽略此步骤

FROM golang:alpine AS builderMAINTAINER cylonWORKDIR /electionCOPY . /electionENV GOPROXY https://goproxy.cn,directRUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o elector main.goFROM alpine AS runnerWORKDIR /go/electorCOPY --from=builder /election/elector .VOLUME ["/election"]ENTRYPOINT ["./elector"]

准备资源清单

默认情况下,Kubernetes运行的pod在请求Kubernetes集群内资源时,默认的账户是没有权限的,默认服务帐户无权访问协调 API,因此我们需要创建另一个serviceaccount并相应地设置 对应的RBAC权限绑定;在清单中配置上这个sa,此时所有的pod就会有协调锁的权限了

apiVersion: v1kind: ServiceAccountmetadata:  name: sa-leaderelection---apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:  name: leaderelectionrules:  - apiGroups:      - coordination.k8s.io    resources:      - leases    verbs:      - '*'---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:  name: leaderelectionroleRef:  apiGroup: rbac.authorization.k8s.io  kind: Role  name: leaderelectionsubjects:  - kind: ServiceAccount    name: sa-leaderelection---apiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: leaderelection  name: leaderelection  namespace: defaultspec:  replicas: 3  selector:    matchLabels:      app: leaderelection  template:    metadata:      labels:        app: leaderelection    spec:      containers:        - image: cylonchau/leaderelection:v0.0.2          imagePullPolicy: IfNotPresent          command: ["./elector"]          args:          - "-id=$(POD_NAME)"          - "-lease-lock-name=test"          - "-lease-lock-namespace=default"          env:          - name: POD_NAME            valueFrom:              fieldRef:                apiVersion: v1                fieldPath: metadata.name          name: elector      serviceAccountName: sa-leaderelection

集群中运行

执行完清单后,当pod启动后,可以看到会创建出一个 lease

$ kubectl get leaseNAME   HOLDER                            AGEtest   leaderelection-5644c5f84f-frs5n   1s$ kubectl describe leaseName:         testNamespace:    defaultLabels:       <none>Annotations:  <none>API Version:  coordination.k8s.io/v1Kind:         LeaseMetadata:  Creation Timestamp:  2022-06-28T16:39:45Z  Managed Fields:    API Version:  coordination.k8s.io/v1    Fields Type:  FieldsV1    fieldsV1:      f:spec:        f:acquireTime:        f:holderIdentity:        f:leaseDurationSeconds:        f:leaseTransitions:        f:renewTime:    Manager:         elector    Operation:       Update    Time:            2022-06-28T16:39:45Z  Resource Version:  131693  Self Link:         /apis/coordination.k8s.io/v1/namespaces/default/leases/test  UID:               bef2b164-a117-44bd-bad3-3e651c94c97bSpec:  Acquire Time:            2022-06-28T16:39:45.931873Z  Holder Identity:         leaderelection-5644c5f84f-frs5n  Lease Duration Seconds:  60  Lease Transitions:       0  Renew Time:              2022-06-28T16:39:55.963537ZEvents:                    <none>

通过其持有者的信息查看对应pod(因为程序中对holder Identity设置的是pod的名称),实际上是工作的pod。

如上实例所述,这是利用Kubernetes集群完成的leader选举的方案,虽然这不是最完美解决方案,但这是一种简单的方法,因为可以无需在集群上部署更多东西或者进行大量的代码工作就可以利用Kubernetes集群来完成一个高可用的HA应用。

posted @ 2022-06-29 00:47 Cylon 阅读(2) 评论(0) 编辑 收藏 举报
回帖
    张三

    张三 (王者 段位)

    821 积分 (2)粉丝 (41)源码

     

    温馨提示

    亦奇源码

    最新会员