国产精品天干天干,亚洲毛片在线,日韩gay小鲜肉啪啪18禁,女同Gay自慰喷水

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

【K8S】etcd-operator 解析與實戰(zhàn)

2022-07-24 14:26 作者:九霄如歌  | 我要投稿


公眾號: 鳴霄溪

簡介

通過將 etcd 集群定義為一個 K8S CRD,etcd-operator 負責 etcd 集群的創(chuàng)建與運維。

它主要包含三個controller:

  1. cluster-operator: 負責自動化創(chuàng)建,銷毀,升級,自動擴縮容,故障遷移etcd集群

  2. backup-operator: 負責對etcd的數(shù)據(jù)進行定時備份,備份后端支持遠程存儲,如aliyun oss存儲

  3. restore-operator: 負責通過備份數(shù)據(jù)恢復etcd集群


operator 流程分析


  1. 創(chuàng)建 EtcdCluster CRD;

  2. 創(chuàng)建 EtcdCluster 的 Informer 來處理 EtcdCluster 增刪改事件;

  3. 當用戶提交 EtcdCluster 創(chuàng)建請求;創(chuàng)建 Etcd 集群初始節(jié)點;根據(jù)期望的 Etcd 集群 size 創(chuàng)建并加入成員節(jié)點;

  4. 當用戶提交 EtcdCluster 更新(?鏡像版本 / 集群 pod size 等更新)請求:調(diào)整集群到期望狀態(tài);

  5. 當用戶提交 EtcdCluster 刪除請求:無需操作,由垃圾回收自動刪除節(jié)點;

  6. Etcd 集群數(shù)據(jù)的備份及恢復分別由 EtcdBackup 和 EtcdRestore 的 Operator 實現(xiàn);


源碼結(jié)構(gòu)


├── cmd # 程序入口
│?? ├── backup-operator # 備份集群用的 Operator
│?? ├── operator # 集群 Operator
│?? └── restore-operator # 恢復集群用的 Operator
├── example # 一些示例文件
│?? ├── deployment.yaml # 部署 Operator
│?? ├── etcd-backup-operator # 備份用 Operator 相關
│?? ├── etcd-restore-operator # 恢復用 Operator 相關
│?? ├── example-etcd-cluster-nodeport-service.json
│?? ├── example-etcd-cluster.yaml # 部署 Etcd 集群
│?? ├── rbac # 用于創(chuàng)建 RBAC 規(guī)則
│?? └── tls # 部署 TLS 連接版的 Etcd 集群
├── hack # 提供一些開發(fā)相關的腳本
├── pkg # 主要源碼
│?? ├── apis # EtcdCluster API 組定義
│?? ├── backup # 操作備份恢復源相關的實現(xiàn)
│?? ├── chaos # 集群容災測試相關
│?? ├── cluster # 集群控制實現(xiàn)
│?? │?? ├── cluster.go # Etcd 集群的實際維護
│?? │?? ├── metrics.go # 監(jiān)控相關
│?? │?? ├── reconcile.go # 節(jié)點的創(chuàng)建或刪除
│?? │?? └── upgrade.go # 節(jié)點的升級
│?? ├── controller # EtcdCluster Controller 實現(xiàn)
│?? │?? ├── backup-operator # 備份集群用的 Operator 實現(xiàn)
│?? │?? ├── restore-operator # 恢復集群用的 Operator 實現(xiàn)
│?? │?? ├── controller.go # 事件處理 Handler
│?? │?? ├── informer.go # 創(chuàng)建 Informer 監(jiān)聽 EtcdCluster 增刪改事件
│?? │?? ├── metrics.go # Prometheus 數(shù)據(jù)統(tǒng)計
│?? ├── generated # K8S 工具生成的代碼
│?? └── util # 一些工具,操作 Pod 對象,Etcd API 調(diào)用等

Controller 初始化

創(chuàng)建 EtcdCluster Controller:

func run(ctx context.Context) {??//?用于測試?Etcd?集群容災狀況,僅用于測試環(huán)境 ?startChaos(context.Background(), cfg.KubeCli, cfg.Namespace, chaosLevel) ?// 創(chuàng)建 Controller 并開始控制循環(huán) ?c := controller.New(cfg) ?err := c.Start() ?logrus.Fatalf("controller Start() failed: %v", err)}


創(chuàng)建 EtcdCluster CRD:

func (c *Controller) Start() error { ?... ?// 等待 EtcdCluster CRD 創(chuàng)建完成 ?for { ? ?err := c.initResource() ? ?if err == nil { ? ? ?break ? ?} ? ?... ? ?time.Sleep(initRetryWaitTime) ?} ?... ?c.run() ?...}


創(chuàng)建 Informer 處理 EctdCluster 事件:

func (c *Controller) run() { ?... ?// EctdCluster 對象的增刪改都會調(diào)用 handleClusterEvent 來處理 ?_, informer := cache.NewIndexerInformer(source, &api.EtcdCluster{}, 0, cache.ResourceEventHandlerFuncs{ ? ?AddFunc: ? ?c.onAddEtcdClus, ? ?UpdateFunc: c.onUpdateEtcdClus, ? ?DeleteFunc: c.onDeleteEtcdClus, ?}, cache.Indexers{}) ?... ?// TODO:以后可以使用 Queue 來避免阻塞 ?informer.Run(ctx.Done())}


處理事件類型循環(huán):

func (c *Controller) handleClusterEvent(event *Event) (bool, error) { ?... ?// 集群失效后,從維護的集群集合中刪除 ?if clus.Status.IsFailed() { ? ?... ? ?if event.Type == kwatch.Deleted { ? ? ?delete(c.clusters, getNamespacedName(clus)) ? ? ?return false, nil ? ?} ? ?... ?}??... ?switch event.Type { ?case kwatch.Added: ? ?... ? ?// 創(chuàng)建 Etcd 集群 ? ?nc := cluster.New(c.makeClusterConfig(), clus) ? ?... ? ?c.clusters[getNamespacedName(clus)] = nc ? ?... ?case kwatch.Modified: ? ?... ? ?// 更新 Etcd 集群 ? ?c.clusters[getNamespacedName(clus)].Update(clus) ? ?... ?case kwatch.Deleted: ? ?... ? ?// 刪除 Etcd 集群 ? ?c.clusters[getNamespacedName(clus)].Delete() ? ?delete(c.clusters, getNamespacedName(clus)) ? ?... ?} ?return false, nil}



Controller 控制循環(huán)

  1. 收到 EtcdCluster 創(chuàng)建事件,則創(chuàng)建一個新的集群

func New(config Config, cl *api.EtcdCluster) *Cluster { ?c := &Cluster{ ? ?... ?} ?go func() { ? ?// 初始化集群 ? ?if err := c.setup(); err != nil { ? ? ?... ? ?} ? ?// 開始集群節(jié)點控制循環(huán) ? ?c.run() ?}() ?return c}


  1. 為集群創(chuàng)建初始節(jié)點

func (c *Cluster) startSeedMember() error { ?m := &etcdutil.Member{ ? ?Name: ? ? ? ? k8sutil.UniqueMemberName(c.cluster.Name), ? ?Namespace: ? ?c.cluster.Namespace, ? ?SecurePeer: ? c.isSecurePeer(), ? ?SecureClient: c.isSecureClient(), ?} ?ms := etcdutil.NewMemberSet(m) ?if err := c.createPod(ms, m, "new"); err != nil { ?... ?_, err := c.eventsCli.Create(k8sutil.NewMemberAddEvent(m.Name, c.cluster)) ?...}


  1. 為集群創(chuàng)建兩個 Headless Service


  • CreateClientService:用于 Etcd 客戶端的訪問;

  • CreatePeerService:用于節(jié)點間訪問;

func (c *Cluster) setupServices() error { ?err := k8sutil.CreateClientService(c.config.KubeCli, c.cluster.Name, c.cluster.Namespace, c.cluster.AsOwner()) ?... ?return k8sutil.CreatePeerService(c.config.KubeCli, c.cluster.Name, c.cluster.Namespace, c.cluster.AsOwner())}

  1. 在控制循環(huán)中創(chuàng)建或刪除成員節(jié)點以達到集群期望狀態(tài)


每隔 reconcileInterval??秒調(diào)整一次集群狀態(tài) reconcile():

  • 將集群節(jié)點數(shù)調(diào)整到期望的 size;reconcileMembers()

  • 刪除所有不屬于集群中的成員節(jié)點;

  • 創(chuàng)建集群中缺失的成員節(jié)點;

  • 如果集群未達到法定節(jié)點數(shù),則退出并報錯;

  • 將集群節(jié)點調(diào)整到期望的 Etcd 版本;upgradeOneMember()

  • 修改 Pod 對象的 Image 后請求 patch;

Etcd 節(jié)點的啟動方式


  • 在啟動節(jié)點 Pod 時,其中的 init container 會等到 Pod DNS 解析可用后才會啟動 Etcd 容器;

  • 從 MemberSet 中找到其他成員的 DNS 名稱并配置 --initial-cluster 參數(shù)后啟動 Etcd 容器;

  • Etcd Operator 部署 Etcd 集群,采用的是靜態(tài)集群(Static)的方式。




可以看到,在 etcd 集群啟動參數(shù)(比如:initial-cluster)里,Etcd Operator 只會使用 Pod 的 DNS 記錄,而不是它的 IP 地址。

這當然是因為,在 Operator 生成上述啟動命令的時候,Etcd 的 Pod 還沒有被創(chuàng)建出來,它的 IP 地址自然也無從談起。


每個 Cluster 對象,都會事先創(chuàng)建一個與該 EtcdCluster 同名的 Headless Service。這樣,Etcd Operator 在接下來的所有創(chuàng)建 Pod 的步驟里,就都可以使用 Pod 的 DNS 記錄來代替它的 IP 地址了。

func newEtcdPod(m *etcdutil.Member, initialCluster []string, clusterName, state, token string, cs api.ClusterSpec) *v1.Pod { ?... ?pod := &v1.Pod{ ? ?... ? ?Spec: v1.PodSpec{ ? ? ?InitContainers: []v1.Container{{ ? ? ? ?... ? ? ? ?Command: []string{"/bin/sh", "-c", fmt.Sprintf(` ? ? ? ? ?TIMEOUT_READY=%d ? ? ? ? ?while ( ! nslookup %s ) ? ? ? ? ?do ? ? ? ? ? ?# If TIMEOUT_READY is 0 we should never time out and exit ? ? ? ? ? ?TIMEOUT_READY=$(( TIMEOUT_READY-1 )) ? ? ? ? ? ? ? ? ? ? ? ?if [ $TIMEOUT_READY -eq 0 ]; ? ? ? ? ? ? ? ?then ? ? ? ? ? ? ? ? ? ?echo "Timed out waiting for DNS entry" ? ? ? ? ? ? ? ? ? ?exit 1 ? ? ? ? ? ? ? ?fi ? ? ? ? ? ?sleep 1 ? ? ? ? ?done`, DNSTimeout, m.Addr())}, ? ? ?}}, ? ? ?Containers: ? ?[]v1.Container{container}, ? ? ?... ? ?}, ?} ?...}


ACK 集群部署實戰(zhàn)

選用 ACK 版本:v1.20.11-aliyun.1

安裝etcd operator


CoreDNS 無法解析 etcd pod 的 IP,部署在 init container 等待 Pod DNS ?解析 hang ?住了。


附錄:使用 Kubebuilder demo

kubebuilder 是生成 k8s operator 的腳手架工具,本 demo 介紹使用 kubebuilder 快速搭建一個 operator 項目。


  1. 初始化項目:

kubebuilder init --domain my.domain --repo my.domain/guestbook

kubebuilder create api --group webapp --version v1 --kind Guestbook


? ?guestbook tree
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── api
│?? └── v1
│?? ? ? ├── groupversion_info.go
│?? ? ? ├── guestbook_types.go
│?? ? ? └── zz_generated.deepcopy.go
├── bin
│?? └── controller-gen
├── config
│?? ├── crd
│?? │?? ├── kustomization.yaml
│?? │?? ├── kustomizeconfig.yaml
│?? │?? └── patches
│?? │?? ? ? ├── cainjection_in_guestbooks.yaml
│?? │?? ? ? └── webhook_in_guestbooks.yaml
│?? ├── default
│?? │?? ├── kustomization.yaml
│?? │?? ├── manager_auth_proxy_patch.yaml
│?? │?? └── manager_config_patch.yaml
│?? ├── manager
│?? │?? ├── controller_manager_config.yaml
│?? │?? ├── kustomization.yaml
│?? │?? └── manager.yaml
│?? ├── prometheus
│?? │?? ├── kustomization.yaml
│?? │?? └── monitor.yaml
│?? ├── rbac
│?? │?? ├── auth_proxy_client_clusterrole.yaml
│?? │?? ├── auth_proxy_role.yaml
│?? │?? ├── auth_proxy_role_binding.yaml
│?? │?? ├── auth_proxy_service.yaml
│?? │?? ├── guestbook_editor_role.yaml
│?? │?? ├── guestbook_viewer_role.yaml
│?? │?? ├── kustomization.yaml
│?? │?? ├── leader_election_role.yaml
│?? │?? ├── leader_election_role_binding.yaml
│?? │?? ├── role_binding.yaml
│?? │?? └── service_account.yaml
│?? └── samples
│?? ? ? └── webapp_v1_guestbook.yaml
├── controllers
│?? ├── guestbook_controller.go
│?? └── suite_test.go
├── go.mod
├── go.sum
├── hack
│?? └── boilerplate.go.txt
└── main.go

13 directories, 38 files

  1. 部署 CRD

? ?guestbook make install

? ?guestbook kubectl get crd |grep my.domain
guestbooks.webapp.my.domain ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2022-05-04T08:58:36Z



可以看到 CRD 已經(jīng)創(chuàng)建成功,但是 CR ?實例還沒創(chuàng)建。


  1. 創(chuàng)建 CR 實例:

? ?guestbook kubectl apply -f config/samples/
guestbook.webapp.my.domain/guestbook-sample created



4.本地運行 operator :

? ?guestbook make run...go fmt ./...go vet ./...go run ./main.goI0504 16:59:38.598884 ? 16635 request.go:665] Waited for 1.020466713s due to client-side throttling, not priority and fairness, request: GET:https://59.110.25.213:6443/apis/metrics.alibabacloud.com/v1alpha1?timeout=32s1.6516547788561852e+09 ?INFO ?controller-runtime.metrics ?Metrics server is starting to listen ?{"addr": ":8090"}1.6516547788572779e+09 ?INFO ?setup ?starting manager1.651654778857989e+09 ?INFO ?Starting server ?{"path": "/metrics", "kind": "metrics", "addr": "[::]:8090"}1.6516547788579981e+09 ?INFO ?Starting server ?{"kind": "health probe", "addr": "[::]:8089"}1.651654778858467e+09 ?INFO ?controller.guestbook ?Starting EventSource ?{"reconciler group": "webapp.my.domain", "reconciler kind": "Guestbook", "source": "kind source: *v1.Guestbook"}1.651654778858505e+09 ?INFO ?controller.guestbook ?Starting Controller ?{"reconciler group": "webapp.my.domain", "reconciler kind": "Guestbook"}1.6516547799614458e+09 ?INFO ?controller.guestbook ?Starting workers ?{"reconciler group": "webapp.my.domain", "reconciler kind": "Guestbook", "worker count": 1}

后續(xù)可以繼續(xù)將 operator 部署到 k8s 上




【K8S】etcd-operator 解析與實戰(zhàn)的評論 (共 條)

分享到微博請遵守國家法律
营山县| 肥乡县| 永修县| 宾阳县| 志丹县| 靖江市| 淳化县| 呼图壁县| 公安县| 岑溪市| 阳东县| 灵川县| 安义县| 漠河县| 阿巴嘎旗| 定兴县| 凤山市| 湟源县| 隆子县| 宜州市| 潍坊市| 安义县| 洛扎县| 东源县| 苏州市| 拜城县| 恩平市| 汾西县| 乡城县| 婺源县| 彰化县| 孟州市| 教育| 清远市| 玉门市| 尚志市| 稻城县| 西安市| 新昌县| 凭祥市| 中宁县|