您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān) 面向K8s設(shè)計(jì)誤區(qū)是怎樣的,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
Kubernetes 是一個具有普遍意義的容器編排工具,它提供了一套基于容器構(gòu)建分布式系統(tǒng)的基礎(chǔ)依賴,其意義等同于 Linux 在操作系統(tǒng)中的地位,可以認(rèn)為是分布式的操作系統(tǒng)。
K8s 提供了 Pod、Service、Volume 等一系列基礎(chǔ)資源定義,為了更好提供擴(kuò)展性,CRD 功能是在 1.7 版本被引入。
用戶可以根據(jù)自己的需求添加自定義的 Kubernetes 對象資源(CRD)。值得注意的是,這里用戶自己添加的 Kubernetes 對象資源都是 native 的都是一等公民,和 Kubernetes 中自帶的、原生的那些 Pod、Deployment 是同樣的對象資源。在 Kubernetes 的 API Server 看來,它們都是存在于 etcd 中的一等資源。
同時(shí),自定義資源和原生內(nèi)置的資源一樣,都可以用 kubectl 來去創(chuàng)建、查看,也享有 RBAC、安全功能。用戶可以開發(fā)自定義控制器來感知或者操作自定義資源的變化。
在自定義資源基礎(chǔ)上,如何實(shí)現(xiàn)自定義資源創(chuàng)建或更新時(shí)的邏輯行為,K8s Operator 提供了相應(yīng)的開發(fā)框架。Operator 通過擴(kuò)展 Kubernetes 定義 Custom Controller,list/watch 對應(yīng)的自定義資源,在對應(yīng)資源發(fā)生變化時(shí),觸發(fā)自定義的邏輯。
Operator 開發(fā)者可以像使用原生 API 進(jìn)行應(yīng)用管理一樣,通過聲明式的方式定義一組業(yè)務(wù)應(yīng)用的期望終態(tài),并且根據(jù)業(yè)務(wù)應(yīng)用的自身特點(diǎn)進(jìn)行相應(yīng)控制器邏輯編寫,以此完成對應(yīng)用運(yùn)行時(shí)刻生命周期的管理并持續(xù)維護(hù)與期望終態(tài)的一致性。
CRD 是 K8s 標(biāo)準(zhǔn)化的資源擴(kuò)展能力,以 Java 為例,int、long、Map、Object 是 Java 內(nèi)置的類,用戶可以自定義 Class 實(shí)現(xiàn)類的擴(kuò)展,CRD 就是 K8s 中的自定義類,CR 就是對應(yīng)類的一個 instance。
Operator 模式 = 自定義類 + 觀察者模式,Operator 模式讓大家編寫 K8s 的擴(kuò)展變得非常簡單快捷,逐漸成為面向 K8s 設(shè)計(jì)的標(biāo)準(zhǔn)。
Operator 提供了標(biāo)準(zhǔn)化的設(shè)計(jì)流程:
使用 SDK 創(chuàng)建一個新的 Operator 項(xiàng)目;
通過添加自定義資源(CRD)定義新的資源 API;
指定使用 SDK API 來 watch 的資源;
自定義 Controller 實(shí)現(xiàn) K8s 協(xié)調(diào)(reconcile)邏輯;
我們團(tuán)隊(duì)(KubeOne 團(tuán)隊(duì))一直在致力于解決復(fù)雜中間件應(yīng)用如何部署到 K8s,自然也是 Operator 模式的踐行者。經(jīng)歷了近 2 年的開發(fā),初步解決了中間件在各個環(huán)境 K8s 的部署,當(dāng)前中間也走了很多彎路,踩了很多坑。
KubeOne 內(nèi)核也經(jīng)歷 3 個大版本的迭代,前 2 次開發(fā)過程基本都是 follow Operator 標(biāo)準(zhǔn)開發(fā)流程進(jìn)行開發(fā)設(shè)計(jì)。遵循一個標(biāo)準(zhǔn)的、典型的 Operator 的設(shè)計(jì)過程,看上去一切都是這么的完美,但是每次設(shè)計(jì)都非常痛苦,踐行 Operator 模式之后,最值得反思和借鑒的就是”有了錘子,看到的只有釘子,簡單總結(jié)一下就是 4 個一切:
一切設(shè)計(jì)皆 YAML;
一切皆合一;
一切皆終態(tài);
一切交互皆 cr。
K8s 的 API 是 YAML 格式,Operator 設(shè)計(jì)流程也是讓大家首先定義 CRD,所以團(tuán)隊(duì)開始設(shè)計(jì)時(shí)直接采用了 YAML 格式。
根據(jù)標(biāo)準(zhǔn)化流程,團(tuán)隊(duì)面向 YAML 設(shè)計(jì)流程大體如下:
1、先根據(jù)已知的數(shù)據(jù)初步整理一個大而全的 YAML,做一下初步的分類,例如應(yīng)用大概包含基礎(chǔ)信息,依賴服務(wù),運(yùn)維邏輯,監(jiān)控采集等,每個分類做一個子部分。
2、開會討論具體的內(nèi)容是否能滿足要求,結(jié)果每次開會都難以形成共識。
因?yàn)榭偸怯行碌男枨鬂M足不了,在討論A時(shí),就有人提到 B、C、D,不斷有新的需求;
每個部分的屬性非常難統(tǒng)一,因?yàn)椴煌膶?shí)現(xiàn)屬性差異較大;
理解不一致,相同名字但使用時(shí)每個人的理解也不同;
3、由于工期很緊,只能臨時(shí)妥協(xié),做一個中間態(tài),后面再進(jìn)一步優(yōu)化。
4、后續(xù)優(yōu)化升級,相同的流程再來一遍,還是很難形成共識。
這是第 2 個版本的設(shè)計(jì):
apiVersion: apps.mwops.alibaba-inc.com/v1alpha1 kind: AppDefinition metadata: labels: app: "A" name: A-1.0 //chart-name+chart-version namespace: kubeone spec: appName: A //chart-name version: 1.0 //chart-version type: apps.mwops.alibaba-inc.com/v1alpha1.argo-helm workloadSettings: //注 workloadSettings 標(biāo)識type應(yīng)該使用的屬性 - name: "deployToK8SName" value: "" - name: "deployToNamespace" value: ${resources:namespace-resource.name} parameterValues: //注 parameterValues標(biāo)識業(yè)務(wù)屬性 - name: "enableTenant" value: "1" - name: "CPU" value: "1" - name: "MEM" value: "2Gi" - name: "jvm" value: "flag;gc" - name: vip.fileserver-edas.ip value: ${resources:fileserver_edas.ip} - name: DB_NAME valueFromConfigMap: name: ${resources:rds-resource.cm-name} expr: ${database} - name: DB_PASSWORD valueFromSecret: name: ${instancename}-rds-secret expr: ${password} - name: object-storage-endpoint value: ${resources:object-storage.endpoint} - name: object-storage-username valueFromSecret: name: ${resources:object-storage.secret-name} expr: ${username} - name: object-storage-password valueFromSecret: name: ${resources:object-storage.secret-name} expr: ${password} - name: redis-endpoint value: ${resources:redis.endpoint} - name: redis-password value: ${resources:redis.password} resources: - name: tolerations type: apps.mwops.alibaba-inc.com/tolerations parameterValues: - name: key value: "sigma.ali/is-ecs" - name: key value: "sigma.ali/resource-pool" - name: namespace-resource type: apps.mwops.alibaba-inc.com/v1alpha1.namespace parameterValues: - name: name value: edas - name: fileserver-edas type: apps.mwops.alibaba-inc.com/v1alpha1.database.vip parameterValues: - name: port value: 21,80,8080,5000 - name: src_port value: 21,80,8080,5000 - name: type value: ClusterIP - name: check_type value: "" - name: uri value: "" - name: ip value: "" - name: test-db type: apps.mwops.alibaba-inc.com/v1alpha1.database.mysqlha parameterValues: - name: name value: test-db - name: user value: test-user - name: password value: test-passwd - name: secret value: test-db-mysqlha-secret - name: service-slb type: apps.mwops.alibaba-inc.com/v1alpha1.slb mode: post-create parameterValues: - name: service value: "serviceA" - name: annotations value: "app:a,version:1.0" - name: external-ip value: - name: service-resource2 type: apps.mwops.alibaba-inc.com/v1alpha1.service parameterValues: - name: second-domain value: edas.console - name: ports value: "80:80" - name: selectors value: "app:a,version:1.0" - name: type value: "loadbalance" - name: service-dns type: apps.mwops.alibaba-inc.com/v1alpha1.dns parameterValues: - name: domain value: edas.server.${global:domain} - name: vip value: ${resources:service-resource2.EXTERNAL-IP} - name: dns-resource type: apps.mwops.alibaba-inc.com/v1alpha1.dns parameterValues: - name: domain value: edas.console.${global:domain} - name: vip value: “127.0.0.1” - name: cni-resource type: apps.mwops.alibaba-inc.com/v1alpha1.cni parameterValues: - name: count value: 4 - name: ip_list value: - name: object-storage type: apps.mwops.alibaba-inc.com/v1alpha1.objectStorage.minio parameterValues: - name: namespace value: test-ns - name: username value: test-user - name: password value: test-password - name: storage-capacity value: 20Gi - name: secret-name value: minio-my-store-access-keys - name: endpoint value: minio-instance-external-service - name: redis type: apps.mwops.alibaba-inc.com/v1alpha1.database.redis parameterValues: - name: cpu value: 500m - name: memory value: 128Mi - name: password value: i_am_a_password - name: storage-capacity value: 20Gi - name: endpoint value: redis-redis-cluster - name: accesskey type: apps.mwops.alibaba-inc.com/v1alpha1.accesskey parameterValues: - name: name value: default - name: userName value: ecs_test@aliyun.com exposes: - name: dns value: ${resources:dns-resource.domain} - name: db-endpoint valueFromConfigmap: name: ${resources:rds-resource.cm-name} expr: ${endpoint}:3306/${database} - name: ip_list value: ${resources:cni-resource.ip_list} - name: object-storage-endpoint value: ${resources:object-storage.endpoint}.${resource:namespace-resource.name} - name: object-storage-username valueFromSecret: name: ${resources:object-storage.secret-name} expr: ${username} - name: object-storage-password valueFromSecret: name: ${resources:object-storage.secret-name} expr: ${password} - name: redis-endpoint value: ${resources:redis.endpoint}.${resource:namespace-resource.name} - name: redis-password value: ${resources:redis.password}
這樣的痛苦難以用語言表達(dá),感覺一切都脫離了掌控,沒有統(tǒng)一的判斷標(biāo)準(zhǔn),設(shè)計(jì)標(biāo)準(zhǔn),公說公有理婆說婆有理,內(nèi)容一直加,字段一直改。事不過三,第三次設(shè)計(jì)時(shí),我們集體討論反思為什么這么難形成共識?為什么每個人理解不同?為什么總是在改?
結(jié)論很一致,沒有面向 YAML 的設(shè)計(jì),只有面向?qū)ο蟮脑O(shè)計(jì),設(shè)計(jì)語言也只有 UML,只有這些歷經(jīng)考驗(yàn)、成熟的設(shè)計(jì)方法論,才是最簡單也是最高效的。
從上面那個一個巨大無比的 YAML 大家可以體會我們設(shè)計(jì)的復(fù)雜,但是這還是不是最痛苦的。最痛苦的是大家拋棄了原有的設(shè)計(jì)流程及設(shè)計(jì)語言,試圖使用一個開放的 Map 來描述一切。當(dāng)設(shè)計(jì)沒有對象,也沒有關(guān)系,只剩下 Map 里一個個屬性,也就無所謂對錯,也無所謂優(yōu)劣。最后爭來爭去,最后不過是再加一個字段,爭了一個寂寞。
那 Operator 先設(shè)計(jì) CRD,再開發(fā) controller 的方式不正確嗎? 答案:部分正確。
與 Java Class 相同,簡單對象不需要經(jīng)過復(fù)雜的設(shè)計(jì)流程,直接設(shè)計(jì) YAML 簡單高效。
在設(shè)計(jì)一個復(fù)雜的體系時(shí),例如:應(yīng)用管理,包含多個對象且對象之間有復(fù)雜的關(guān)系,有復(fù)雜的用戶故事,UML 和面向?qū)ο蟮脑O(shè)計(jì)就顯得非常重要。
設(shè)計(jì)時(shí)只考慮 UML 和領(lǐng)域語言,設(shè)計(jì)完成后,CRD 可以認(rèn)為是 Java 的 Class,或者是數(shù)據(jù)庫的表結(jié)構(gòu),只是最終要實(shí)現(xiàn)時(shí)的一種選擇。而且有很多對象不需要持久化,也不需要通過 Operator 機(jī)制觸發(fā)對應(yīng)的邏輯,就不需要設(shè)計(jì) CRD,而是直接實(shí)現(xiàn)一個 controller 即可。
YAML 是接口或 Class 聲明的一種格式化表達(dá),常規(guī) YAML 要盡可能小,盡可能職責(zé)單一,盡可能抽象。復(fù)雜的 YAML 是對簡單 CRD 資源的一種編排結(jié)果,提供類似一站式資源配套方案。
在第 3 個版本及 PaaS-Core 設(shè)計(jì)時(shí),我們就采取了如下的流程:
UML 用例圖;
梳理用戶故事;
基于用戶故事對齊 Domain Object,確定關(guān)鍵的業(yè)務(wù)對象以及對象間關(guān)系;
需要 Operator 化的對象,每個對象描述為一個 CRD,當(dāng)然 CRD 缺乏接口、繼承等面向?qū)ο蟮哪芰?,可以通過其他方式曲線表達(dá);
不需要 Operator 化的對象,直接編寫 Controller;
為了保證一個應(yīng)用的終態(tài),或者為了使用 gitops 管理一個應(yīng)用,是否應(yīng)該把應(yīng)用相關(guān)的內(nèi)容都放入一個 CRD 或一個 IAC 文件?根據(jù) gitops 設(shè)計(jì),每次變更時(shí)需要下發(fā)整個文件?
案例1: 應(yīng)用 WordPress,需要依賴一個 MySQL,終態(tài)如何定義?
apiVersion: apps.mwops.alibaba-inc.com/v1alpha1kind: AppDefinitionmetadata: labels: app: "WordPress" name: WordPress-1.0 //chart-name+chart-version namespace: kubeonespec: appName: WordPress //chart-name version: 1.0 //chart-version type: apps.mwops.alibaba-inc.com/v1alpha1.argo-helm parameterValues: //注 parameterValues標(biāo)識業(yè)務(wù)屬性 - name: "enableTenant" value: "1" - name: "CPU" value: "1" - name: "MEM" value: "2Gi" - name: "jvm" value: "flag;gc" - name: replicas value: 3 - name: connectstring valueFromConfigMap: name: ${resources:test-db.exposes.connectstring} expr: ${connectstring} - name: db_user_name valueFromSecret: .... resources: - name: test-db //創(chuàng)建一個新的DB type: apps.mwops.alibaba-inc.com/v1alpha1.database.mysqlha parameterValues: - name: cpu value: 2 - name: memory value: 4G - name: storage value: 20Gi - name: username value: myusername - name: password value: i_am_a_password - name: dbname value: wordPress exposes: - name: connectstring - name: username - name: password exposes: - name: dns value: ...
上方的代碼是 wordPress 應(yīng)用的終態(tài)嗎?這個文件包含了應(yīng)用所需要的 DB 的定義和應(yīng)用的定義,只要一次下發(fā)就可以先創(chuàng)建對應(yīng)的數(shù)據(jù)庫,再把應(yīng)用拉起。
案例2:每次變更時(shí),直接修改整個 yaml 的部分內(nèi)容,修改后直接下發(fā)到 K8s,引起不必要的變更。例如:要從 3 個節(jié)點(diǎn)擴(kuò)容到 5 個節(jié)點(diǎn),修改上面 YAML 文件的 replicas 之后,需要下發(fā)整個 YAML。整個下發(fā)的 YAML 經(jīng)過二次解析成底層的 StatefulSet 或 Deployment,解析邏輯升級后,可能會產(chǎn)生不符合預(yù)期的變化,導(dǎo)致所有 Pod 重建。
先回答第一個問題,上方 YAML 文件不是應(yīng)用的終態(tài),而是一個編排,此編排包含了 DB 的定義和應(yīng)用的定義。應(yīng)用的終態(tài)只應(yīng)該包含自己必須的依賴引用,而不包含依賴是如何創(chuàng)建的。因?yàn)檫@個依賴引用可以是新創(chuàng)建的,也可以是一個已有的,也可以是手工填寫的,依賴如何創(chuàng)建與應(yīng)用終態(tài)無關(guān)。
apiVersion: apps.mwops.alibaba-inc.com/v1alpha1 kind: AppDefinition metadata: labels: app: "WordPress" name: WordPress-1.0 //chart-name+chart-version namespace: kubeone spec: appName: WordPress //chart-name version: 1.0 //chart-version name: WordPress-test type: apps.mwops.alibaba-inc.com/v1alpha1.argo-helm parameterValues: //注 parameterValues標(biāo)識業(yè)務(wù)屬性 - .... resources: - name: test-db-secret value: "wordPress1Secret">
創(chuàng)建一個應(yīng)用,就不能先創(chuàng)建 db,再創(chuàng)建應(yīng)用嗎?
可以的,多個對象之間依賴是通過編排實(shí)現(xiàn)的。編排有單個應(yīng)用創(chuàng)建的編排,也有一個復(fù)雜站點(diǎn)創(chuàng)建的編排。以 Argo 為例:
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: wordPress- spec: templates: - name: wordPress steps: # 創(chuàng)建db - - name: wordpress-db template: wordpress-db arguments: parameters: [{name: wordpress-db1}] # 創(chuàng)建應(yīng)用 - - name: template: wordpress arguments: parameters: [{db-sercet: wordpress-db1}]
針對第 2 個案例,是否每次交互都需要下發(fā)全部完整的 YAML?
答案:
編排是一次性的配置,編排文件下發(fā)一次之后,后續(xù)操作都是操作單個對象,例如:變更時(shí),只會單獨(dú)變更 wordPress,或單獨(dú)變更 wordPressDB,而不會一次性同時(shí)變更 2 個對象。
單獨(dú)變更應(yīng)用時(shí),是否需要下發(fā)整個終態(tài) YAML,這個要根據(jù)實(shí)際情況進(jìn)行設(shè)計(jì),值得大家思考。后面會提出針對整個應(yīng)用生命周期狀態(tài)機(jī)的設(shè)計(jì),里面有詳細(xì)的解釋。
CRD 或 IAC 定義時(shí),單個對象的終態(tài)只應(yīng)該包含自身及對依賴的引用。與面向?qū)ο蟮脑O(shè)計(jì)相同,我們不應(yīng)該把所有類的定義都放到一個 Class 里面。
2、不適用場景
多個對象要一次性創(chuàng)建,并且需要按照順序創(chuàng)建,存在依賴關(guān)系,需要通過編排層實(shí)現(xiàn)。
體驗(yàn)了 K8s 的終態(tài)化之后,大家在設(shè)計(jì)時(shí)言必稱終態(tài),仿佛不能用上終態(tài)設(shè)計(jì),不下發(fā)一個 YAML 聲明對象的終態(tài)就是落伍,就是上一代的設(shè)計(jì)。
案例
案例1:應(yīng)用編排
還是以 WordPress 為例,將 WordPressDB 和 WordPress 放在一起進(jìn)行部署,先部署 DB,再創(chuàng)建應(yīng)用。示例 YAML 同上。
案例2:應(yīng)用發(fā)布
應(yīng)用第一次部署及后續(xù)的升級直接下發(fā)一個完整的應(yīng)用 YAML,系統(tǒng)會自動幫你到達(dá)終態(tài)。但為了能夠細(xì)粒度控制發(fā)布的流程,努力在 Deployment 或 StatefulSet 上下功夫,進(jìn)行 partition 的控制,試圖在終態(tài)里增加一點(diǎn)點(diǎn)的交互性。
說到終態(tài),必然要提到命令式、聲明式編程,終態(tài)其實(shí)就是聲明式最終的執(zhí)行結(jié)果。我們先回顧一下命令式、終態(tài)式編程。
1、命令式編程
命令式編程的主要思想是關(guān)注計(jì)算機(jī)執(zhí)行的步驟,即一步一步告訴計(jì)算機(jī)先做什么再做什么。
比如:如果你想在一個數(shù)字集合 collection(變量名) 中篩選大于 5 的數(shù)字,你需要這樣告訴計(jì)算機(jī):
第一步,創(chuàng)建一個存儲結(jié)果的集合變量 results;
第二步,遍歷這個數(shù)字集合 collection;
第三步,一個一個地判斷每個數(shù)字是不是大于 5,如果是就將這個數(shù)字添加到結(jié)果集合變量 results 中。
代碼實(shí)現(xiàn)如下:
List results = new List(); foreach(var num in collection) { if (num > 5) results.Add(num); }
很明顯,這個樣子的代碼是很常見的一種,不管你用的是 C、C++ 還是 C#、Java、Javascript、BASIC、Python、Ruby 等,你都可以以這個方式寫。
聲明式編程是以數(shù)據(jù)結(jié)構(gòu)的形式來表達(dá)程序執(zhí)行的邏輯。它的主要思想是告訴計(jì)算機(jī)應(yīng)該做什么,但不指定具體要怎么做。
SQL 語句就是最明顯的一種聲明式編程的例子,例如:
SELECT * FROM collection WHERE num > 5
除了 SQL,網(wǎng)頁編程中用到的 HTML 和 CSS 也都屬于聲明式編程。
通過觀察聲明式編程的代碼我們可以發(fā)現(xiàn)它有一個特點(diǎn)是它不需要創(chuàng)建變量用來存儲數(shù)據(jù)。
另一個特點(diǎn)是它不包含循環(huán)控制的代碼如 for, while。
換言之:
命令式編程:命令“機(jī)器”如何去做事情(how),這樣不管你想要的是什么(what),它都會按照你的命令實(shí)現(xiàn)。
聲明式編程:告訴“機(jī)器”你想要的是什么(what),讓機(jī)器想出如何去做(how)。
當(dāng)接口越是在表達(dá)“要什么”,就是越聲明式;越是在表達(dá)“要怎樣”,就是越命令式。SQL就是在表達(dá)要什么(數(shù)據(jù)),而不是表達(dá)怎么弄出我要的數(shù)據(jù),所以它就很“聲明式”。
簡單的說,接口的表述方式越接近人類語言——詞匯的串行連接(一個詞匯實(shí)際上是一個概念)——就越“聲明式”;越接近計(jì)算機(jī)語言——“順序+分支+循環(huán)”的操作流程——就越“命令式”。
越是聲明式,意味著下層要做更多的東西,或者說能力越強(qiáng),也意味著效率的損失。越是命令式,意味著上層對下層有更多的操作空間,可以按照自己特定的需求要求下層按照某種方式來處理。
簡單的講,Imperative Programming Language (命令式語言)一般都有 control flow, 并且具有可以和其他設(shè)備進(jìn)行交互的能力。而 Declarative Programming language (聲明式語言) 一般做不到這些。
基于以上的分析,編排或工作流本質(zhì)是一個流程
性控制的過程,一般是一次性的過程,無需強(qiáng)行終態(tài)化,而且建站編排執(zhí)行結(jié)束后,不能保持終態(tài),因?yàn)楹罄m(xù)會根據(jù)單個應(yīng)用進(jìn)行發(fā)布和升級。案例1是一個典型的編排,只是一次性的創(chuàng)建了 2 個對象 DB 和應(yīng)用的終態(tài)。
應(yīng)用發(fā)布其實(shí)是通過一個發(fā)布單或工作流,控制 2 個不同版本的應(yīng)用節(jié)點(diǎn)和流量的終態(tài)化的過程,不應(yīng)該是應(yīng)用終態(tài)的一部分,而是一個獨(dú)立的控制流程。
聲明式或終態(tài)設(shè)計(jì)。
無過多交互,無需關(guān)注底層實(shí)現(xiàn)的場景,即把聲明提供給系統(tǒng)后,系統(tǒng)會自動化達(dá)到聲明所要求的狀態(tài),而不需要人為干預(yù)。
一次性的流程編排,有頻繁交互的控制流程。
命令式和聲明式本就是 2 種互補(bǔ)的編程模式,就像有了面向?qū)ο笾?,有人就鄙視面向過程的編程,現(xiàn)在有了聲明式,就開始鄙視命令式編程,那一屋!
因?yàn)?K8s 的 API 交互只能通過 YAML,導(dǎo)致大家的設(shè)計(jì)都以 cr 為中心,所有的交互都設(shè)計(jì)為下發(fā)一個 cr,通過 watch cr 觸發(fā)對應(yīng)的邏輯。
調(diào)用一個 http 接口或 function,需要下發(fā)一個 cr;
應(yīng)用 crud 都下發(fā)完整 cr;
案例1:是否所有的邏輯都需要下發(fā)一個 cr?
下發(fā) cr 其實(shí)做了比較多的事情,流程很長,效率并不高,流程如下:
通過 API 傳入 cr,cr 保存到 etcd;
觸發(fā) informer;
controller 接收到對應(yīng)的事件,觸發(fā)邏輯;
更新 cr 狀態(tài);
清理 cr,否則會占用 etcd 存儲;
如果需要頻繁的調(diào)用對應(yīng)的接口,盡量通過 sdk 直接調(diào)用。
K8s 對 YAML 操作命令有 create、apply、patch、delete、get 等,但一個應(yīng)用的生命周期狀態(tài)機(jī)不只是這幾個命令可以涵蓋,我們比較一下應(yīng)用狀態(tài)機(jī)(上)和 YAML 狀態(tài)機(jī)(下):
不同的有狀態(tài)應(yīng)用,在收到不同的指令,需要觸發(fā)不同的邏輯,例如:MQ 在收到 stop 指令時(shí),需要先停寫,檢查數(shù)據(jù)是否消費(fèi)完成。如果只是通過 YAML 狀態(tài)機(jī)是無法涵蓋應(yīng)用狀態(tài)機(jī)相關(guān)的 event,所以我們必須打破下發(fā) cr 的模式。對于應(yīng)用來說,理想的交互方式是通過 event driven 應(yīng)用狀態(tài)機(jī)的變化,狀態(tài)發(fā)生變換時(shí)觸發(fā)對應(yīng)的邏輯。
需要持久化,保持終態(tài)的數(shù)據(jù)。
高頻的服務(wù)調(diào)用,無需持久化的數(shù)據(jù)。
復(fù)雜狀態(tài)機(jī)的驅(qū)動。
上述就是小編為大家分享的 面向K8s設(shè)計(jì)誤區(qū)是怎樣的了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。