上周,抽空聽了兩場云棲大會(一場關(guān)于k8s 云原生的發(fā)展趨勢,一場是關(guān)于k8s安全的話題), 這幾年, 容器領(lǐng)域的技術(shù),發(fā)展太快了,工具層出不窮 , 也越來越容易使用了, 逐漸替代了一些硬件的功能; 傳統(tǒng)的運(yùn)維正面臨前所未有的挑戰(zhàn), 如果不了解這個(gè)領(lǐng)域的技術(shù),未來可想而知

451 研究說未來 76%的企業(yè)將上云, 你覺得呢 ?
Auther: Makr.wei
當(dāng)年Twitter飛速增長期,服務(wù)器的擴(kuò)容常常跟不上用戶的爆炸式增長,所以經(jīng)常會出現(xiàn)宕機(jī),這時(shí)候會出現(xiàn)一只小鳥拉著鯨魚的圖片, 就是著名的失敗之鯨, 08/09年的Twitter,那絕對是Twitter的一段暗黑歷史,可愛的失敗鯨因此得以頻頻出鏡。它不僅僅是宕機(jī)的標(biāo)識,也象征了Twitter的程序猿在修復(fù)程序之時(shí),這些粉絲真誠的相信Twitter會越來越好。

Twitter 急需一個(gè)資源管理系統(tǒng)來幫助他們擺脫可怕的“失敗之鯨”,09年,參考Google Borg的開源工具M(jìn)esos,進(jìn)入了Twitter的視野,被用于解決宕機(jī)問題。同時(shí),幾位大牛開始游說Google全球數(shù)據(jù)中心網(wǎng)絡(luò)的負(fù)責(zé)人開放Borg,對于“是否要把運(yùn)營Goolgle的秘密武器作為開源技術(shù)拱手讓人?”這個(gè)問題讓Google管理層十分糾結(jié),一直猶豫不決, 但最終,谷歌批準(zhǔn)發(fā)起開源項(xiàng)目Kubernetes(開源版的Borg),把這一重要工具貢獻(xiàn)給世界,從此,Kubernetes和Docker成為黃金搭檔,迅速傳播開來。正是因?yàn)閗8s社區(qū)的高度活躍,以及功能快速迭代, 在2019年5月,Twitter宣布放棄已經(jīng)管理300000臺主機(jī),使用了十年之久的Mesos, 轉(zhuǎn)投Kubernetes社區(qū)。
基于Cloud-native的Kubernetes是當(dāng)今最流行的應(yīng)用架構(gòu),相關(guān)技術(shù)通過模塊化和復(fù)雜度轉(zhuǎn)移,來減輕研發(fā)的痛苦。
從頭開始創(chuàng)建微服務(wù),或者把大系統(tǒng)拆解成微服務(wù),可參考很多重要的理論文章和實(shí)踐經(jīng)驗(yàn)。這些實(shí)踐都基于 Eric Evans 的 Domain-Drive Design, 和有界上下文(Bounded Context)和聚合的理論文章。 Bounded Context 為我們把大模型分解為各種小組件提供依據(jù), 通過聚合有界內(nèi)容組成模塊,并定義事務(wù)邊界。無論是否是分布式微服務(wù)系統(tǒng),都圍繞組織架構(gòu),體系結(jié)構(gòu)和運(yùn)行時(shí)狀態(tài)提供解決方案,除了領(lǐng)域模型之外,還有一系列復(fù)雜的問題需要我們考慮。
Docker和Kubernetes,為我們提供了很多新的元素和抽象工具解決分布式系統(tǒng)的問題,為分布式系統(tǒng)帶來了大量的便利,不過,遵循Garbage in ,Garbage out 定律,我們放進(jìn)容器的是垃圾,那么,我們也將得到一個(gè)超級垃圾體。

- 代碼層面: 每一個(gè)參數(shù),方法,實(shí)例化對象都在將來的長期運(yùn)維中起到非常重要的影響,無論使用什么容器工具,開發(fā)團(tuán)隊(duì)交付物都非常重要。程序員要盡可能的寫出邏輯清晰的代碼,完成足夠的自動化測試,持續(xù)重構(gòu)提升代碼質(zhì)量,這是一個(gè)具備工匠精神的程序員的本分。
- 領(lǐng)域設(shè)計(jì): 領(lǐng)域驅(qū)動的設(shè)計(jì)是讓軟件實(shí)現(xiàn)盡可能貼近真實(shí)世界的一種思想。這個(gè)技術(shù)是OOP理論的延展,準(zhǔn)確的業(yè)務(wù)模型,清晰的事務(wù)邊界,易用的接口和豐富的API,是容器自動化的基礎(chǔ)。
- 微服務(wù)架構(gòu), 為設(shè)計(jì)持續(xù)變化的分布式系統(tǒng),提供了有價(jià)值的規(guī)范和實(shí)踐指導(dǎo),這些原則可以幫助實(shí)現(xiàn)常規(guī)的系統(tǒng)需求,比如動態(tài)擴(kuò)展、彈性伸縮和快速跌代
- 容器可以幫助我們快速的搭建一套標(biāo)準(zhǔn)的分布式系統(tǒng), 模塊構(gòu)建和容器復(fù)用是實(shí)現(xiàn)Cloud-native 應(yīng)用的一個(gè)先決條件,當(dāng)容器數(shù)量不斷增長,維護(hù)系統(tǒng)正常運(yùn)行,管理各種資源就需要一個(gè)強(qiáng)大的編排工具。
Cloud native用于描述自動化,集成化,微系統(tǒng)化,模塊化和工具化的大規(guī)模服務(wù)平臺。
Distributed Primitives
JVM在本地操作系統(tǒng)進(jìn)程中編譯運(yùn)行,而Kubernetes提供分布式系統(tǒng)的基本單元和運(yùn)行工具,可分布運(yùn)行在多個(gè)Node的進(jìn)程中,增加了一種高維視角。
我們?nèi)匀恍枰褂肙OP構(gòu)建系統(tǒng)的組件,但是我們可用Kubernetes的基本元素完成一些系統(tǒng)間的行為
基本元素和分布式基本元素有些共性,但不能直接替換,他們工作在不同系統(tǒng)的層面,比如,容器化,我們?nèi)匀恍枰褂肑ava編寫程序,但我們可以用 K8s 中的Cron Job 來替代Java中的ExecutorService的實(shí)現(xiàn)
Container
容器是Cloud-native的一個(gè)基本構(gòu)建單元,相對于OOP,容器的Image可以類比Class,而Container則類似于Object,我們可以繼承Class,同樣的的Image也可以繼承其它的Image; Object可以組裝功能,同理可以將相互協(xié)作的Container放入Pod來進(jìn)行容器組合。k8s可以像Jvm一樣實(shí)現(xiàn)多主機(jī)交互,并負(fù)責(zé)資源的運(yùn)行和管理。Container初始化像Java的構(gòu)造函數(shù), DaemonSets 類似于java后臺線程(Daemon thread)。Pod有時(shí)類似于IOC框架,當(dāng)多個(gè)容器共享生命周期,可以直接相互訪問。
- Container是單個(gè)業(yè)務(wù)的功能單元
- Image屬于團(tuán)隊(duì),擁有自己的發(fā)布周期
- Image有自己的運(yùn)行時(shí)依賴和資源需求
- Image是自包含,自定義的,承載運(yùn)行時(shí)依賴
- Image是不可變的,一旦創(chuàng)建,不可更改,且已完成配置
- Image已完成運(yùn)行時(shí)依賴和資源需求
- Image擁有明確的定義的Api來暴露功能
- Container是一次性的,隨時(shí)可以安全的擴(kuò)容和縮減
除了上面這些特點(diǎn)之外,Image業(yè)務(wù)模塊創(chuàng)建是基于參數(shù)化的,以便于在不同環(huán)境復(fù)用。并且Image也必須實(shí)現(xiàn)參數(shù)化以適應(yīng)各種應(yīng)用場景。 原子化,模塊化, 可復(fù)用化的Image,類似于編程語言中的類庫
Pods
容器的Image提供單一功能單元,屬于單個(gè)團(tuán)隊(duì),具有獨(dú)立的發(fā)布周期,并提供部署和運(yùn)行時(shí)資源隔離。 大多數(shù)情況下,一個(gè)微服務(wù)對應(yīng)于一個(gè)Image。
但是,Cloud-Native 提供了一個(gè)新元素來管理Kubernetes中一組容器的生命周期,它被稱為Pod。 Pod是一組容器調(diào)度,部署和運(yùn)行的原子單元。 一個(gè)Pod里的所有容器始終安排在同一Node上,無論是擴(kuò)展還是Node遷移,都可以一起部署,還可以共享文件系統(tǒng),網(wǎng)絡(luò)和NameSpace。 這個(gè)聯(lián)合體生命周期內(nèi)允許Pod中的容器通過文件系統(tǒng)相互交互或者網(wǎng)絡(luò)交互。
在開發(fā)和創(chuàng)建期,微服務(wù)對應(yīng)于一個(gè)開發(fā)團(tuán)隊(duì)的鏡像,在運(yùn)行時(shí),微服務(wù)呈現(xiàn)為一個(gè)Pod,Pod是部署,編排,伸縮的單位,無論是擴(kuò)展還是遷移,運(yùn)行容器的唯一方法是通過Pod。

Pod的一些特性
- Pod是調(diào)度任務(wù)的最小單元。 調(diào)度程序會嘗試尋找滿足Pod里的容器資源的Node。如果創(chuàng)建包含多個(gè)Container的Pod,調(diào)度程序會尋找滿足所有container資源的Node。
- 托管容器, 同一Pod中的容器有獨(dú)特交互方式,最常見的通信方式包括使用共享本地文件系統(tǒng)交換數(shù)據(jù),網(wǎng)絡(luò)層交互,或使用主機(jī)進(jìn)程間通信(IPC)機(jī)制進(jìn)行高性能交互
- Pod具有屬于它的所有容器共享的IP地址,名稱和端口范圍。必須仔細(xì)配置同一Pod中的容器以避免端口沖突,就像同一主機(jī)上并行的Unix進(jìn)程一樣。
Pod是我們的應(yīng)用程序在Kubernetes系統(tǒng)的原子單元,不能直接訪問,那么,我們該如何訪問Pod的應(yīng)用呢? 答案是Service
Service
Pods 可以隨時(shí)啟動或者銷毀,比如在對Pod擴(kuò)容或者縮減,健康心跳失敗,或者遷移Node時(shí)。Pod的IP的地址只有在Pod啟動后才會生效,假設(shè)當(dāng)前運(yùn)行的Node出問題,Pod也可能會自動遷移到其它Node。這就意味著Pod的生命周期中IP地址可能會發(fā)生變化,如果這時(shí)另外一個(gè)Pod里的資源,通過IP地址訪問被遷移的POD里的資源,就會發(fā)生異常,而Service就可以作為隔離層隔離這種差異,實(shí)現(xiàn)自動的服務(wù)發(fā)現(xiàn)。
這就是Kubernetes Services發(fā)揮作用的地方。Service是一個(gè)簡單但功能強(qiáng)大的Kubernetes抽象層,它將Service名稱永久綁定到IP地址和端口上。 因此,Service代表訪問應(yīng)用程序的入口點(diǎn)。在最常見的場景中,Service充當(dāng)一組Pod的入口點(diǎn),但情況可能并非總是如此。 Service是一個(gè)通用元素,它也可能指向Kubernetes集群外部的資源。因此,Service可用于服務(wù)發(fā)現(xiàn)和負(fù)載平衡,允許在不影響服務(wù)使用者的情況下改變Pod。
Label
通過上面的內(nèi)容,我們可以知道微服務(wù)在創(chuàng)建時(shí)時(shí)一個(gè)容器,運(yùn)行時(shí)是一個(gè)Pod,那么,是么是由多個(gè)微服務(wù)組成的應(yīng)用系統(tǒng)呢 ? 在這里,kubernetes提供了另外兩個(gè)元素,可以幫助我們定義應(yīng)用程序的概念:標(biāo)簽和名稱空間。
在微服務(wù)出現(xiàn)之前,應(yīng)用程序是具有版本控制和發(fā)布周期的單體部署單元。應(yīng)用程序的采用.war,.ear或其打包格式。 但隨后,應(yīng)用程序被拆分為微服務(wù),這些微服務(wù)是獨(dú)立開發(fā),發(fā)布,運(yùn)行,設(shè)置或擴(kuò)展的。 使用微服務(wù),應(yīng)用程序的概念會減少,并且我們不再需要在應(yīng)用程序級別執(zhí)行關(guān)鍵構(gòu)建工作。但是,如果您仍需要一種方法來制定某些獨(dú)立服務(wù)屬于某個(gè)應(yīng)用程序,則可以使用標(biāo)簽。讓我們假設(shè)我們將一個(gè)單體應(yīng)用程序拆分為三個(gè)微服務(wù),將另一個(gè)應(yīng)用程序拆分為兩個(gè)微服務(wù)。
現(xiàn)在,我們有五個(gè)Pod定義(可能還有更多的Pod實(shí)例),這些定義獨(dú)立于開發(fā)和運(yùn)行時(shí)的觀點(diǎn)。但是,我們可能仍需要指出前三個(gè)Pod代表一個(gè)應(yīng)用程序,而另外兩個(gè)Pod代表另一個(gè)應(yīng)用程序。甚至Pod也可以是獨(dú)立的,提供一個(gè)業(yè)務(wù)功能,但他們可能相互依賴。 例如,一個(gè)Pod負(fù)責(zé)前端的容器,另外兩個(gè)Pod負(fù)責(zé)提供后端接口。如果這些Pod中的任何停機(jī),那么從業(yè)務(wù)角度來看,應(yīng)用程序是不可用的。使用標(biāo)簽選擇器給我們能夠查詢和識別一組Pod,并作為一個(gè)邏輯單元進(jìn)行管理 ,下圖顯示了如何使用標(biāo)簽對分布式應(yīng)用程序的各個(gè)部分進(jìn)行分組 。

- ReplicaSet使用Label來保持特定Pod的某些實(shí)例運(yùn)行。 這意味著每個(gè)Pod定義都需要具有用于調(diào)度的唯一標(biāo)簽組合
- 調(diào)度程序也大量使用標(biāo)簽。 調(diào)度程序使用標(biāo)簽來共置或傳播Pod,以將Pod放置在滿足Pods要求的節(jié)點(diǎn)上
- Label可以指示一組Pod的邏輯分組,并為它們提供應(yīng)用程序標(biāo)識。
除了前面的典型用例之外,標(biāo)簽還可用于存儲元數(shù)據(jù)。很難準(zhǔn)確的說標(biāo)簽可以用于什么,但最好有足夠的標(biāo)簽描述Pod的所有重要特征。 例如,使用標(biāo)簽來指明應(yīng)用程序的邏輯分組,業(yè)務(wù)特征和關(guān)鍵性,指定的運(yùn)行時(shí)依賴等等
調(diào)度程序可以使用這些標(biāo)簽進(jìn)行更細(xì)粒度的調(diào)度,或者可以通過命令行使用相同的標(biāo)簽來大規(guī)模地管理匹配的Pod。 但是,我們不應(yīng)該過分夸大并提前添加太多標(biāo)簽。我們應(yīng)該根據(jù)實(shí)際需要創(chuàng)建標(biāo)簽。刪除標(biāo)簽風(fēng)險(xiǎn)很大,因?yàn)闆]有很明確的方法可以表明標(biāo)簽的用途,此類操作可能導(dǎo)致的不可預(yù)知的影響
對于金融系統(tǒng),監(jiān)管對機(jī)房內(nèi)服務(wù)器劃分,訪問權(quán)限,安全級別有嚴(yán)格的指導(dǎo)。通過標(biāo)簽定義,我們可以分配哪些Pod在指定節(jié)點(diǎn)(或者說指定的物理機(jī),機(jī)柜)上創(chuàng)建。

Annotations
Annotation與Label類似,也使用key/value鍵值對的形式進(jìn)行定義。Label具有嚴(yán)格的命名規(guī)則,它定義的是Kubernetes對象的元數(shù)據(jù)(Metadata),并且用于Label Selector。Annotation則是用戶任意定義的“附加”信息,以便于外部工具進(jìn)行查找。
用Annotation來記錄的信息包括:
- build信息、release信息、Docker鏡像信息等,例如時(shí)間戳、release id號、PR號、鏡像hash值、docker registry地址等;
- 日志庫、監(jiān)控庫、分析庫等資源庫的地址信息;
- 程序調(diào)試工具信息,例如工具名稱、版本號等;
- 團(tuán)隊(duì)的聯(lián)系信息,例如電話號碼、負(fù)責(zé)人名稱、網(wǎng)址等
Namespaces
Namespaces是Kubernetes系統(tǒng)中的另一個(gè)非常重要的概念,通過將系統(tǒng)內(nèi)部的對象“分配”到不同的Namespace中,形成邏輯上分組的不同項(xiàng)目、小組或用戶組,當(dāng)不同的分組在整個(gè)集群中使用共享資源的同時(shí),還能被分別管理。
Kubernetes集群在啟動后,會創(chuàng)建一個(gè)名為“default”的Namespace,通過Kubectl可以查看到。
- Namespaces用于k8s的資源管理
- Namespaces為Container,Pod,Service或ReplicaSet等資源提供工作范圍。資源名稱在Namespaces中必須是唯一的,而且不能跨越它們。
- 默認(rèn)情況下,Namespaces為資源提供界限,但不會隔離這些資源,阻止一個(gè)資源訪問另一個(gè)資源。例如,只要Pod IP地址已知,開發(fā)Namespaces中的Pod就可以從生產(chǎn)Namespaces訪問另一個(gè)Pod。但是,如果需要,還有Kubernetes插件可提供網(wǎng)絡(luò)隔離,以實(shí)現(xiàn)跨Namespaces的真正多租戶模式。
- 每個(gè)k8s服務(wù)必須有Namespaces,有相應(yīng)的DNS地址,Namespaces的命名格式如<service-name>.<namespace-name> .svc.cluster.local。所有k8s服務(wù)的URI都含有NameSpaces的名稱地址。這個(gè)類似java 里class的package name, 作用也非常類似。
- 用ResourceQuotas約束Namespaces的資源。集群管理員可以使用ResourceQuotas控制Namespaces中創(chuàng)建的各種對象個(gè)數(shù)。 例如,開發(fā)人員可以限定Namespaces只允許5個(gè)ConfigMaps,5個(gè)Secrets,5個(gè)Services,5個(gè)ReplicaSet,5個(gè)PersistentVolumeClaims和10個(gè)Pod
- 用ResourceQuotas指定NameSpaces 資源配比。 例如,在容量為32 GB RAM和16個(gè)內(nèi)核的群集中,可以為生產(chǎn)環(huán)境NameSpaces分配一半資源(16 GB RAM和8個(gè)內(nèi)核),然后分配8 GB RAM和4個(gè)內(nèi)核,4 GB RAM和2個(gè)內(nèi)核用于開發(fā),測試的NameSpaces。
PersistentVolume & PersistentVolumeClaims
PersistentVolume(PV)在集群中是由管理員配置的網(wǎng)絡(luò)存儲。 PV是容量插件,如Volumes,其生命周期獨(dú)立于使用PV的任何單個(gè)pod。PV在k8s集群中的作用類似我們經(jīng)常在Linux服務(wù)器上掛載的NFS,可以很方便的做mount 映射
PersistentVolumeClaim(PVC)是由用戶進(jìn)行存儲的請求。 它類似于pod。 Pod可以請求特定級別的資源(CPU和內(nèi)存)。 指定可用資源的大小和訪問模式(例如,可以一次讀/寫或多次只讀)。
雖然PersistentVolumeClaims允許用戶端使用抽象存儲資源,對于不同的問題,用戶端通常需要使用不同資源(例如性能)。集群管理員要能夠提供各種PersistentVolumes不同的方式,不僅僅是大小和訪問模式,但用戶端不需要了解這些數(shù)據(jù)卷實(shí)現(xiàn)的細(xì)節(jié)。
PV是群集中的資源。PVC是對這些資源的請求,并且還充當(dāng)對資源可用性檢查。PV和PVC之間的相互作用遵循以下生命周期:Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling
- 準(zhǔn)備Provisioning---通過集群外的存儲系統(tǒng)或者云平臺來提供存儲持久化支持。
- 靜態(tài)提供Static:集群管理員創(chuàng)建多個(gè)PV。 它們攜帶可供集群用戶使用的真實(shí)存儲的詳細(xì)信息。
- 動態(tài)提供Dynamic:當(dāng)管理員創(chuàng)建的靜態(tài)PV都不匹配用戶的PersistentVolumeClaim時(shí),集群可能會嘗試為PVC動態(tài)配置卷。 此配置基于StorageClasses:PVC必須請求一個(gè)類,并且管理員必須已創(chuàng)建并配置該類才能進(jìn)行動態(tài)配置。
- 綁定Binding---用戶創(chuàng)建pvc并指定需要的資源和訪問模式。在找到可用pv之前,pvc會保持未綁定狀態(tài)。
使用Using---用戶可在pod中像volume一樣使用pvc。 - 釋放Releasing---用戶刪除pvc來回收存儲資源,pv將變成“released”狀態(tài)。由于還保留著之前的數(shù)據(jù),這些數(shù)據(jù)需要根據(jù)不同的策略來處理,否則這些存儲資源無法被其他pvc使用。
- 回收Recycling---pv可以設(shè)置三種回收策略:保留(Retain),回收(Recycle)和刪除(Delete)。
- 保留策略:允許人工處理保留的數(shù)據(jù)。
- 刪除策略:將刪除pv和外部關(guān)聯(lián)的存儲資源,需要插件支持。
- 回收策略:將執(zhí)行清除操作,之后可以被新的pvc使用,需要插件支持。
下面這張圖是k8s元素相互關(guān)系的直觀體現(xiàn)

K8S是一個(gè)完備的分布式系統(tǒng)支撐平臺,具有完備的集群管理能力,多層次的安全防護(hù)和準(zhǔn)入機(jī)制、多租戶應(yīng)用支撐能力、透明的服務(wù)注冊和發(fā)現(xiàn)機(jī)制、內(nèi)建智能負(fù)載均衡器、強(qiáng)大的故障發(fā)現(xiàn)和自我修復(fù)能力、服務(wù)滾動升級和在線擴(kuò)容能力、可擴(kuò)展的資源自動調(diào)度機(jī)制以及多粒度的資源配額管理能力。同時(shí)Kubernetes提供完善的管理工具,涵蓋了包括開發(fā)、部署測試、運(yùn)維監(jiān)控在內(nèi)的各個(gè)環(huán)節(jié), 減輕了以往運(yùn)維手工操作的痛苦,為DevOps思想提供了強(qiáng)力的支撐。
