在k8s本身的組件中,kube-scheduler和kube-manager-controller兩個組件是有leader選舉的,這個選舉機制是k8s對于這兩個組件的高可用保障。即正常情況下kube-scheduler或kube-manager-controller組件的多個副本只有一個是處于業務邏輯運行狀態,其它副本則不斷的嘗試去獲取鎖,去競爭leader,直到自己成為leader。如果正在運行的leader因某種原因導致當前進程退出,或者鎖丟失,則由其它副本去競爭新的leader,獲取leader繼而執行業務邏輯。
不光是k8s本身組件用到了這個選舉策略,我們自己定義的服務同樣可以用這個算法去實現選主。在k8s client包中就提供了接口供用戶使用。代碼路徑在client-go/tools/leaderelection下。
leaderelection 主要是利用了k8s API操作的原子性實現了一個分布式鎖,在不斷的競爭中進行選舉。選中為leader的進行才會執行具體的業務代碼,這在k8s中非常的常見,而且我們很方便的利用這個包完成組件的編寫,從而實現組件的高可用,比如部署為一個多副本的Deployment,當leader的pod退出后會重新啟動,可能鎖就被其他pod獲取繼續執行。
以es operator為例,使用endpoint說明leader選舉:
1、首先operator配置文件中可以設置是否開啟選舉(默認開啟)
- operator-manager
- --v=5
- --leader-elect=true
- --operators=escluster
- --lock-object-name=escluster
- --lock-object-namespace={{ .Release.Namespace }}
2、定義一個controller的主控制邏輯,可以是一個函數,比如run(ctx context.Context)
在沒有開啟選舉情況下,那么直接運行run;
3、如果開啟選舉:
定義該進程唯一id,比如hostname;
根據鎖類型new一個鎖實體,比如這里使用endpoint:
func DefaultLeaderElectionConfiguration() v1alpha1.LeaderElectionConfiguration {
return v1alpha1.LeaderElectionConfiguration{
LeaderElect: false,
LeaseDuration: metav1.Duration{Duration: DefaultLeaseDuration},
RenewDeadline: metav1.Duration{Duration: DefaultRenewDeadline},
RetryPeriod: metav1.Duration{Duration: DefaultRetryPeriod},
ResourceLock: rl.EndpointsResourceLock,
LockObjectNamespace: DefaultLockObjectNamespace,
LockObjectName: DefaultLockObjectName,
}
}
設計鎖競爭的控制邏輯,callback里面定義搶占鎖后執行的業務邏輯(比如這里執行run);進程退出執行的邏輯;產生新的鎖執行的邏輯等:
leaderelection.RunOrDie(context.TODO(), leaderelection.LeaderElectionConfig{
Lock: rl,
LeaseDuration: s.LeaderElection.LeaseDuration.Duration,
RenewDeadline: s.LeaderElection.RenewDeadline.Duration,
RetryPeriod: s.LeaderElection.RetryPeriod.Duration,
Callbacks: leaderelection.LeaderCallbacks{
OnStartedLeading: run,
OnStoppedLeading: func() {
klog.Fatalf("leaderelection lost")
},
},
WatchDog: electionChecker,
Name: s.LeaderElection.LockObjectName,
})
4、某進程搶占鎖后,查詢對應ns中ep,內容如下:
apiVersion: v1
kind: Endpoints
metadata:
annotations:
control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"elasticsearch-operator-cb4bbc85f-wnjx4","leaseDurationSeconds":15,"acquireTime":"2022-12-19T08:22:42Z","renewTime":"2023-01-31T11:53:01Z","leaderTransitions":0}'
creationTimestamp: "2022-12-19T08:21:15Z"
name: escluster
namespace: middleware-operator
resourceVersion: "165028190"
selfLink: /api/v1/namespaces/middleware-operator/endpoints/escluster
uid: 3ffc4bae-0433-4a78-9ef1-44c57891b95b