核心概念
Master:集群的控制和管理
Kubernetes里的Master指的是集群控制節(jié)點,在每個Kubernetes集群里都需要有一個Master來負責整個集群的管理和控制,基本上Kubernetes的所有控制命令都發(fā)給它痒筒,它負責具體的執(zhí)行過程草则,我們后面執(zhí)行的所有命令基本都是在Master上運行的梧疲。Master通常會占據(jù)一個獨立的服務器(高可用部署建議用3臺服務器)邮丰,主要原因是它太重要了霸奕,是整個集群的“首腦”帮毁,如果它宕機或者不可用实苞,那么對集群內(nèi)容器應用的管理都將失效。
在Master上運行著以下關(guān)鍵進程
-
Kubernetes API Server(kube-apiserver):
- 提供了HTTP Rest接口的關(guān)鍵服務進程烈疚,是Kubernetes里所有資源的增黔牵、刪、改爷肝、查等操作的唯一入口猾浦,也是集群控制的入口進程。
-
Kubernetes Controller Manager(kube-controller-manager):
- Kubernetes里所有資源對象的自動化控制中心灯抛,可以將其理解為資源對象的“大總管”金赦。
-
Kubernetes Scheduler(kube-scheduler):
- 負責資源調(diào)度(Pod調(diào)度)的進程,相當于公交公司的“調(diào)度室”对嚼。
另外夹抗,在Master上通常還需要部署etcd服務,因為Kubernetes里的所有資源對象的數(shù)據(jù)都被保存在etcd中纵竖。
Node:接收Master分配的工作負載
除了Master漠烧,Kubernetes集群中的其他機器被稱為Node,在較早的版本中也被稱為Minion靡砌。與Master一樣已脓,Node可以是一臺物理主機,也可以是一臺虛擬機通殃。Node是Kubernetes集群中的工作負載節(jié)點度液,每個Node都會被Master分配一些工作負載(Docker容器),當某個Node宕機時,其上的工作負載會被Master自動轉(zhuǎn)移到其他節(jié)點上恨诱。
在每個Node上都運行著以下關(guān)鍵進程
-
kubelet:
- 負責Pod對應的容器的創(chuàng)建媳瞪、啟停等任務,同時與Master密切協(xié)作照宝,實現(xiàn)集群管理的基本功能蛇受。
-
kube-proxy:
- 實現(xiàn)Kubernetes Service的通信與負載均衡機制的重要組件。
-
Docker Engine(docker):
- Docker引擎厕鹃,負責本機的容器創(chuàng)建和管理工作兢仰。
工作方式
- Node可以在運行期間動態(tài)增加到Kubernetes集群中,前提是在這個節(jié)點上已經(jīng)正確安裝剂碴、配置和啟動了上述關(guān)鍵進程把将,在默認情況下kubelet會向Master注冊自己,這也是Kubernetes推薦的Node管理方式忆矛。
- 一旦Node被納入集群管理范圍察蹲,kubelet進程就會定時向Master匯報自身的情報,例如操作系統(tǒng)催训、Docker版本洽议、機器的CPU和內(nèi)存情況,以及當前有哪些Pod在運行等漫拭,這樣Master就可以獲知每個Node的資源使用情況亚兄,并實現(xiàn)高效均衡的資源調(diào)度策略。
- 而某個Node在超過指定時間不上報信息時采驻,會被Master判定為“失聯(lián)”审胚,Node的狀態(tài)被標記為不可用(Not Ready),隨后Master會觸發(fā)“工作負載大轉(zhuǎn)移”的自動流程礼旅。
我們可以執(zhí)行下述命令查看在集群中有多少個Node:
然后膳叨,通過kubectl describe node <node_name>查看某個Node的詳細信息:
上述命令展示了Node的如下關(guān)鍵信息。
◎ Node的基本信息:名稱各淀、標簽懒鉴、創(chuàng)建時間等。
◎ Node當前的運行狀態(tài):Node啟動后會做一系列的自檢工作碎浇,比如磁盤空間是否不足(DiskPressure)临谱、內(nèi)存是否不足(MemoryPressure)稿存、網(wǎng)絡是否正常(NetworkUnavailable)撞叽、PID資源是否充足(PIDPressure)陶缺。在一切正常時設置Node為Ready狀態(tài)(Ready=True)垃杖,該狀態(tài)表示Node處于健康狀態(tài)驴娃,Master將可以在其上調(diào)度新的任務了(如啟動Pod)损肛。
◎ Node的主機地址與主機名虏两。
◎ Node上的資源數(shù)量:描述Node可用的系統(tǒng)資源喊衫,包括CPU、內(nèi)存數(shù)量跟磨、最大可調(diào)度Pod數(shù)量等间聊。
◎ Node可分配的資源量:描述Node當前可用于分配的資源量。
◎ 主機系統(tǒng)信息:包括主機ID抵拘、系統(tǒng)UUID哎榴、Linux kernel版本號、操作系統(tǒng)類型與版本僵蛛、Docker版本號尚蝌、kubelet與kube-proxy的版本號等。
◎ 當前運行的Pod列表概要信息充尉。
◎ 已分配的資源使用概要信息飘言,例如資源申請的最低、最大允許使用量占系統(tǒng)總量的百分比驼侠。
◎ Node相關(guān)的Event信息姿鸿。
Pod:一組相關(guān)的docker容器
Pod是Kubernetes最重要的基本概念,每個Pod都有一個特殊的被稱為“根容器”的Pause容器泪电。Pause容器對應的鏡像屬于Kubernetes平臺的一部分般妙,除了Pause容器,每個Pod還包含一個或多個緊密相關(guān)的用戶業(yè)務容器相速。
為什么Kubernetes會設計出一個全新的Pod的概念并且Pod有這樣特殊的組成結(jié)構(gòu)?
-
簡單的對容器組整體進行判斷
- 在一組容器作為一個單元的情況下鲜锚,我們難以簡單地對“整體”進行判斷及有效地行動突诬。比如,一個容器死亡了芜繁,此時算是整體死亡么旺隙?是N/M的死亡率么?引入業(yè)務無關(guān)并且不易死亡的Pause容器作為Pod的根容器骏令,以它的狀態(tài)代表整個容器組的狀態(tài)蔬捷,就簡單、巧妙地解決了這個難題榔袋。
-
解決業(yè)務關(guān)聯(lián)容器組之間的共享問題
- Pod里的多個業(yè)務容器共享Pause容器的IP周拐,共享Pause容器掛接的Volume,這樣既簡化了密切關(guān)聯(lián)的業(yè)務容器之間的通信問題凰兑,也很好地解決了它們之間的文件共享問題妥粟。
在Kubernetes里,一個Pod里的容器與另外主機上的Pod容器能夠直接通信
Kubernetes為每個Pod都分配了唯一的IP地址吏够,稱之為Pod IP勾给,一個Pod里的多個容器共享Pod IP地址滩报。Kubernetes要求底層網(wǎng)絡支持集群內(nèi)任意兩個Pod之間的TCP/IP直接通信,這通常采用虛擬二層網(wǎng)絡技術(shù)來實現(xiàn)播急,例如Flannel脓钾、Open vSwitch等。
Pod其實有兩種類型
-
靜態(tài)Pod(Static Pod)
- 其比較特殊桩警,它并沒被存放在Kubernetes的etcd存儲里可训,而是被存放在某個具體的Node上的一個具體文件中,并且只在此Node上啟動生真、運行沉噩。
-
普通的Pod
-
普通的Pod一旦被創(chuàng)建,就會被放入etcd中存儲柱蟀,隨后會被Kubernetes Master調(diào)度到某個具體的Node上并進行綁定(Binding)川蒙,隨后該Pod被對應的Node上的kubelet進程實例化成一組相關(guān)的Docker容器并啟動。在默認情況下长已,當Pod里的某個容器停止時畜眨,Kubernetes會自動檢測到這個問題并且重新啟動這個Pod(重啟Pod里的所有容器),如果Pod所在的Node宕機术瓮,就會將這個Node上的所有Pod重新調(diào)度到其他節(jié)點上康聂。Pod、容器與Node的關(guān)系如圖所示胞四。
image.png
-
-
普通pod的工作流程:
- 一旦被創(chuàng)建恬汁,就會被放入etcd中存儲,隨后會被Kubernetes Master調(diào)度到某個具體的Node上并進行綁定(Binding)辜伟;
- 該Pod被對應的Node上的kubelet進程實例化成一組相關(guān)的Docker容器并啟動氓侧;
- 在默認情況下,當Pod里的某個容器停止時导狡,Kubernetes會自動檢測到這個問題并且重新啟動這個Pod(重啟Pod里的所有容器)约巷,如果Pod所在的Node宕機,就會將這個Node上的所有Pod重新調(diào)度到其他節(jié)點上旱捧;
Kubernetes里的所有資源對象都可以采用YAML或者JSON格式的文件來定義或描述
下面是我們在之前的Hello World例子里用到的myweb這個Pod的資源定義文件:
- Kind
- 為Pod表明這是一個Pod的定義
- metadata
- name屬性為Pod的名稱
- 標簽:在metadata里還能定義資源對象的標簽独郎,這里聲明myweb擁有一個name=myweb的標簽。
- spec: 容器組的定義
- 定義Pod里所包含的容器組枚赡,這里定義了一個名為myweb氓癌、對應鏡像為kubeguide/tomcat-app:v1的容器,該容器注入了名為MYSQL_SERVICE_HOST='mysql'和MYSQL_SERVICE_PORT='3306'的環(huán)境變量(env關(guān)鍵字)标锄,并且在8080端口(containerPort)啟動容器進程顽铸。
- Endpoint:Pod的IP加上這里的容器端口(containerPort),組成了一個新的概念—Endpoint料皇,它代表此Pod里的一個服務進程的對外通信地址谓松。一個Pod也存在具有多個Endpoint的情況星压,比如當我們把Tomcat定義為一個Pod時,可以對外暴露管理端口與服務端口這兩個Endpoint鬼譬。
- Pod Volume
- 我們所熟悉的Docker Volume在Kubernetes里也有對應的概念—Pod Volume娜膘,后者有一些擴展,比如可以用分布式文件系統(tǒng)GlusterFS實現(xiàn)后端存儲功能优质;
- Pod Volume是被定義在Pod上竣贪,然后被各個容器掛載到自己的文件系統(tǒng)中的。
- Event
- 這里順便提一下Kubernetes的Event概念巩螃。Event是一個事件的記錄演怎,記錄了事件的最早產(chǎn)生時間、最后重現(xiàn)時間避乏、重復次數(shù)爷耀、發(fā)起者、類型拍皮,以及導致此事件的原因等眾多信息歹叮。
-
Event通常會被關(guān)聯(lián)到某個具體的資源對象上,是排查故障的重要參考信息铆帽,之前我們看到Node的描述信息包括了Event咆耿,而Pod同樣有Event記錄,當我們發(fā)現(xiàn)某個Pod遲遲無法創(chuàng)建時爹橱,可以用kubectl describe pod xxxx來查看它的描述信息萨螺,以定位問題的成因,比如下面這個Event記錄信息表明Pod里的一個容器被探針檢測為失敗一次:
image.png
為每個pod的計算資源設置限額
可以為pod計算資源設置的配額
cpu
CPU的資源單位為CPU(Core)的數(shù)量愧驱,是一個絕對值而非相對值屑迂。
對于絕大多數(shù)容器來說,一個CPU的資源配額相當大冯键,所以在Kubernetes里通常以千分之一的CPU配額為最小單位,用m來表示庸汗。通常一個容器的CPU配額被定義為100~300m惫确,即占用0.1~0.3個CPU。由于CPU配額是一個絕對值蚯舱,所以無論在擁有一個Core的機器上改化,還是在擁有48個Core的機器上,100m這個配額所代表的CPU的使用量都是一樣的枉昏。
-
memory
- 與CPU配額類似陈肛,Memory配額也是一個絕對值,它的單位是內(nèi)存字節(jié)數(shù)兄裂。
在Kubernetes里句旱,一個計算資源進行配額限定時需要設定以下兩個參數(shù)
- Requests:
- 該資源的最小申請量阳藻,系統(tǒng)必須滿足要求。
- Limits:
- 該資源最大允許使用的量谈撒,不能被突破腥泥,當容器試圖使用超過這個量的資源時,可能會被Kubernetes“殺掉”并重啟啃匿。
? 通常蛔外,我們會把Requests設置為一個較小的數(shù)值,符合容器平時的工作負載情況下的資源需求溯乒,而把Limit設置為峰值負載情況下資源占用的最大量夹厌。
下面這段定義表明MySQL容器申請最少0.25個CPU及64MiB內(nèi)存,在運行過程中MySQL容器所能使用的資源配額為0.5個CPU及128MiB內(nèi)存:
Label:對一組資源通過標簽的形式加以聚合
Label(標簽)是Kubernetes系統(tǒng)中另外一個核心概念裆悄。
一個Label是一個key=value的鍵值對矛纹,其中key與value由用戶自己指定。
-
Label可以被附加到各種資源對象上灯帮,
- 例如Node崖技、Pod、Service钟哥、RC等迎献,一個資源對象可以定義任意數(shù)量的Label,同一個Label也可以被添加到任意數(shù)量的資源對象上腻贰。Label通常在資源對象定義時確定吁恍,也可以在對象創(chuàng)建后動態(tài)添加或者刪除。
我們可以通過給指定的資源對象捆綁一個或多個不同的Label來實現(xiàn)多維度的資源分組管理功能播演,以便靈活冀瓦、方便地進行資源分配、調(diào)度写烤、配置翼闽、部署等管理工作。
例如洲炊,部署不同版本的應用到不同的環(huán)境中感局;監(jiān)控和分析應用(日志記錄、監(jiān)控暂衡、告警)等询微。
一些常用的Label示例如下
- 版本標簽:"release":"stable"、"release":"canary"狂巢。
- 環(huán)境標簽:"environment":"dev"撑毛、"environment":"qa"、"environment":"production"唧领。
- 架構(gòu)標簽:"tier":"frontend"藻雌、"tier":"backend"雌续、"tier":"middleware"。
- 分區(qū)標簽:"partition":"customerA"蹦疑、"partition":"customerB"西雀。
- 質(zhì)量管控標簽:"track":"daily"、"track":"weekly"歉摧。
Label Selector
Label相當于我們熟悉的“標簽”艇肴。給某個資源對象定義一個Label,就相當于給它打了一個標簽叁温,隨后可以通過Label Selector(標簽選擇器)查詢和篩選擁有某些Label的資源對象再悼,Kubernetes通過這種方式實現(xiàn)了類似SQL的簡單又通用的對象查詢機制。
Label Selector可以被類比為SQL語句中的where查詢條件膝但,例如冲九,name=redis-slave這個Label Selector作用于Pod時,可以被類比為select * from pod where pod’s name =‘redis-slave’這樣的語句跟束。
兩種Label Selector表達式:
- 基于等式的(Equality-based):采用等式類表達式匹配標簽
- name=redis-slave:匹配所有具有標簽name=redis-slave的資源對象莺奸。
- env!=production:匹配所有不具有標簽env=production的資源對象,比如env=test就是滿足此條件的標簽之一冀宴。
- 基于集合的(Set-based):使用集合操作類表達式匹配標簽
- name in(redis-master, redis-slave):匹配所有具有標簽name=redis-master或者name=redis-slave的資源對象灭贷。
-
name not in(php-frontend):匹配所有不具有標簽name=php-frontend的資源對象。
可以通過多個Label Selector表達式的組合實現(xiàn)復雜的條件選擇略贮,多個表達式之間用“甚疟,”進行分隔即可,幾個條件之間是“AND”的關(guān)系逃延,即同時滿足多個條件览妖,比如下面的例子:
image.png
例子
以myweb Pod為例讹挎,Label被定義在其metadata中:
管理對象RC和Service則通過Selector字段設置需要關(guān)聯(lián)Pod的Label:
其他管理對象如Deployment菩貌、ReplicaSet、DaemonSet和Job則可以在Selector中使用基于集合的篩選條件定義棚瘟,例如:
matchLabels用于定義一組Label拄丰,與直接寫在Selector中的作用相同桅打;
matchExpressions用于定義一組基于集合的篩選條件,可用的條件運算符包括In愈案、NotIn、Exists和DoesNotExist鹅搪。
注釋
1.如果同時設置了matchLabels和matchExpressions
則兩組條件為AND關(guān)系站绪,即需要同時滿足所有條件才能完成Selector的篩選。
2.Label Selector在Kubernetes中的重要使用場景如下丽柿。
- kube-controller進程通過在資源對象RC上定義的Label Selector來篩選要監(jiān)控的Pod副本數(shù)量恢准,使Pod副本數(shù)量始終符合預期設定的全自動控制流程魂挂。(使pod副本數(shù)量符合預期設置)
- kube-proxy進程通過Service的Label Selector來選擇對應的Pod,自動建立每個Service到對應Pod的請求轉(zhuǎn)發(fā)路由表馁筐,從而實現(xiàn)Service的智能負載均衡機制涂召。(通過自動建立service對應pod的路由表,實現(xiàn)智能負載均衡)
- 通過對某些Node定義特定的Label敏沉,并且在Pod定義文件中使用NodeSelector這種標簽調(diào)度策略果正,kube-scheduler進程可以實現(xiàn)Pod定向調(diào)度的特性。
復雜的例子
在前面的例子中盟迟,我們只使用了一個name=XXX的Label Selector秋泳。看一個更復雜的例子:假設為Pod定義了3個Label:release攒菠、env和role迫皱,不同的Pod定義了不同的Label值,如果設置“role=frontend”的Label Selector辖众,則會選取到Node 1和Node 2上的Pod卓起。
如果設置“release=beta”的Label Selector,則會選取到Node 2和Node 3上的Pod凹炸,如圖所示戏阅。
總之,使用Label可以給對象創(chuàng)建多組標簽还惠,Label和Label Selector共同構(gòu)成了Kubernetes系統(tǒng)中核心的應用模型饲握,使得被管理對象能夠被精細地分組管理,同時實現(xiàn)了整個集群的高可用性蚕键。
Replication Controller:聲明pod的副本數(shù)并在任意時刻都符合這個預期值
RC是Kubernetes系統(tǒng)中的核心概念之一救欧,簡單來說,它其實定義了一個期望的場景锣光,即聲明某種Pod的副本數(shù)量在任意時刻都符合某個預期值笆怠。
RC的定義包括如下幾個部分
- Pod期待的副本數(shù)量。
- 用于篩選目標Pod的Label Selector誊爹。
- 當Pod的副本數(shù)量小于預期數(shù)量時蹬刷,用于創(chuàng)建新Pod的Pod模板(template)。
一個完整的RC例子
下面是一個完整的RC定義的例子频丘,即確保擁有tier=frontend標簽的這個Pod(運行Tomcat容器)在整個Kubernetes集群中始終只有一個副本:
作用
- 在我們定義了一個RC并將其提交到Kubernetes集群中后办成,Master上的Controller Manager組件就得到通知,定期巡檢系統(tǒng)中當前存活的目標Pod搂漠,并確保目標Pod實例的數(shù)量剛好等于此RC的期望值迂卢;
- 如果有過多的Pod副本在運行,系統(tǒng)就會停掉一些Pod,否則系統(tǒng)會再自動創(chuàng)建一些Pod而克。
- 可以說靶壮,通過RC,Kubernetes實現(xiàn)了用戶應用集群的高可用性员萍,并且大大減少了系統(tǒng)管理員在傳統(tǒng)IT環(huán)境中需要完成的許多手工運維工作(如主機監(jiān)控腳本腾降、應用監(jiān)控腳本、故障恢復腳本等)碎绎。
Kubernetes如何通過RC來實現(xiàn)Pod副本數(shù)量自動控制的機制
下面以有3個Node的集群為例螃壤,說明Kubernetes如何通過RC來實現(xiàn)Pod副本數(shù)量自動控制的機制。
假如在我們的RC里定義redis-slave這個Pod需要保持兩個副本混卵,系統(tǒng)將可能在其中的兩個Node上創(chuàng)建Pod映穗。
上圖描述了在兩個Node上創(chuàng)建redis-slave Pod的情形。
假設Node 2上的Pod 2意外終止幕随,則根據(jù)RC定義的replicas數(shù)量2蚁滋,Kubernetes將會自動創(chuàng)建并啟動一個新的Pod,以保證在整個集群中始終有兩個redis-slave Pod運行赘淮。
系統(tǒng)可能選擇Node 3或者Node 1來創(chuàng)建一個新的Pod
此外辕录,在運行時,我們可以通過修改RC的副本數(shù)量梢卸,來實現(xiàn)Pod的動態(tài)縮放(Scaling)走诞,這可以通過執(zhí)行kubectl scale命令來一鍵完成:
Scaling的執(zhí)行結(jié)果如圖
使用的注意事項
- 刪除RC并不會影響通過該RC已創(chuàng)建好的Pod。
- 為了刪除所有Pod蛤高,可以設置replicas的值為0蚣旱,然后更新該RC。另外戴陡,kubectl提供了stop和delete命令來一次性刪除RC和RC控制的全部Pod塞绿。
- 通過RC機制很容易地實現(xiàn)了滾動升級
- 應用升級時,通常會使用一個新的容器鏡像版本替代舊版本恤批。我們希望系統(tǒng)平滑升級异吻,比如在當前系統(tǒng)中有10個對應的舊版本的Pod,則最佳的系統(tǒng)升級方式是舊版本的Pod每停止一個喜庞,就同時創(chuàng)建一個新版本的Pod诀浪,在整個升級過程中此消彼長,而運行中的Pod數(shù)量始終是10個延都,幾分鐘以后雷猪,當所有的Pod都已經(jīng)是新版本時,系統(tǒng)升級完成晰房。通過RC機制春宣,Kubernetes很容易就實現(xiàn)了這種高級實用的特性酵颁,被稱為“滾動升級”(Rolling Update),具體的操作方法后面會說明月帝。
- Replica Set與RC的區(qū)別
-
Replication Controller由于與Kubernetes代碼中的模塊Replication Controller同名,同時“Replication Controller”無法準確表達它的本意幽污,所以在Kubernetes 1.2中嚷辅,升級為另外一個新概念—Replica Set,官方解釋其為“下一代的RC”距误。Replica Set與RC當前的唯一區(qū)別是簸搞,Replica Sets支持基于集合的Label selector(Set-basedselector),而RC只支持基于等式的Label Selector(equality-based selector)准潭,這使得Replica Set的功能更強趁俊。下面是等價于之前RC例子的Replica Set的定義(省去了Pod模板部分的內(nèi)容):
image.png
-
- kubectl命令行工具適用于RC的絕大部分命令同樣適用于Replica Set。
- 此外刑然,我們當前很少單獨使用Replica Set寺擂,它主要被Deployment這個更高層的資源對象所使用,從而形成一整套Pod創(chuàng)建泼掠、刪除怔软、更新的編排機制。我們在使用Deployment時择镇,無須關(guān)心它是如何創(chuàng)建和維護Replica Set的挡逼,這一切都是自動發(fā)生的。
- Replica Set與Deployment這兩個重要的資源對象逐步替代了之前RC的作用腻豌,是Kubernetes 1.3里Pod自動擴容(伸縮)這個告警功能實現(xiàn)的基礎家坎,也將繼續(xù)在Kubernetes未來的版本中發(fā)揮重要的作用。
最后總結(jié)一下RC(Replica Set)的一些特性與作用
- 在大多數(shù)情況下吝梅,我們通過定義一個RC實現(xiàn)Pod的創(chuàng)建及副本數(shù)量的自動控制虱疏。
- 在RC里包括完整的Pod定義模板。
- RC通過Label Selector機制實現(xiàn)對Pod副本的自動控制憔涉。
- 通過改變RC里的Pod副本數(shù)量订框,可以實現(xiàn)Pod的擴容或縮容。
- 通過改變RC里Pod模板中的鏡像版本兜叨,可以實現(xiàn)Pod的滾動升級穿扳。
Deployment:更好地解決Pod的編排問題
Deployment是Kubernetes在1.2版本中引入的新概念,用于更好地解決Pod的編排問題国旷。為此矛物,Deployment在內(nèi)部使用了Replica Set來實現(xiàn)目的,無論從Deployment的作用與目的跪但、YAML定義履羞,還是從它的具體命令行操作來看,我們都可以把它看作RC的一次升級,兩者的相似度超過90%忆首。
Deployment相對于RC的一個最大升級是我們可以隨時知道當前Pod“部署”的進度爱榔。實際上由于一個Pod的創(chuàng)建、調(diào)度糙及、綁定節(jié)點及在目標Node上啟動對應的容器這一完整過程需要一定的時間详幽,所以我們期待系統(tǒng)啟動N個Pod副本的目標狀態(tài),實際上是一個連續(xù)變化的“部署過程”導致的最終狀態(tài)浸锨。
Deployment的典型使用場景有以下幾個
- 創(chuàng)建一個Deployment對象來生成對應的Replica Set并完成Pod副本的創(chuàng)建唇聘。
- 檢查Deployment的狀態(tài)來看部署動作是否完成(Pod副本數(shù)量是否達到預期的值)。
- 更新Deployment以創(chuàng)建新的Pod(比如鏡像升級)柱搜。
- 如果當前Deployment不穩(wěn)定迟郎,則回滾到一個早先的Deployment版本。
- 暫停Deployment以便于一次性修改多個PodTemplateSpec的配置項聪蘸,之后再恢復Deployment宪肖,進行新的發(fā)布。
- 擴展Deployment以應對高負載宇姚。
- 查看Deployment的狀態(tài)匈庭,以此作為發(fā)布是否成功的指標。
- 清理不再需要的舊版本ReplicaSets浑劳。
Deployment的定義與Replica Set的定義很類似
除了API聲明與Kind類型等有所區(qū)別阱持,Deployment的定義與Replica Set的定義很類似:
下面通過運行一些例子來直觀地感受Deployment的概念。創(chuàng)建一個名為tomcat-deployment.yaml的Deployment描述文件魔熏,內(nèi)容如下:
常用命令
1.創(chuàng)建
運行下述命令創(chuàng)建Deployment:
指定名字tomcat-deploy
2.查看deployments信息
運行下述命令查看Deployment的信息:
注釋
對上述輸出中涉及的數(shù)量解釋如下衷咽。
- DESIRED:Pod副本數(shù)量的期望值,即在Deployment里定義的Replica蒜绽。
- CURRENT:當前Replica的值镶骗,實際上是Deployment創(chuàng)建的Replica Set里的Replica值,這個值不斷增加躲雅,直到達到DESIRED為止鼎姊,表明整個部署過程完成。
- UP-TO-DATE:最新版本的Pod的副本數(shù)量相赁,用于指示在滾動升級的過程中相寇,有多少個Pod副本已經(jīng)成功升級。
- AVAILABLE:當前集群中可用的Pod副本數(shù)量钮科,即集群中當前存活的Pod數(shù)量唤衫。
3.查看deployments對應的rs
運行下述命令查看對應的Replica Set,我們看到它的命名與Deployment的名稱有關(guān)系:
4.查看創(chuàng)建的pod
我們發(fā)現(xiàn)Pod的命名以Deployment對應的Replica Set的名稱為前綴绵脯,這種命名很清晰地表明了一個Replica Set創(chuàng)建了哪些Pod佳励,對于Pod滾動升級這種復雜的過程來說休里,很容易排查錯誤
5.查看水平擴展過程
運行kubectl describe deployments,可以清楚地看到Deployment控制的Pod的水平擴展過程赃承,具體內(nèi)容后面會說妙黍。
pod的管理對象
Pod的管理對象,除了RC和Deployment瞧剖,還包括ReplicaSet废境、DaemonSet、StatefulSet筒繁、Job等,分別用于不同的應用場景中巴元,將在后面進行詳細介紹毡咏。
Horizontal Pod Autoscaler:自動觸發(fā)擴縮容
產(chǎn)生背景
- 通過手工執(zhí)行kubectl scale命令,我們可以實現(xiàn)Pod擴容或縮容逮刨。如果僅僅到此為止呕缭,顯然不符合谷歌對Kubernetes的定位目標—自動化、智能化修己。在谷歌看來恢总,分布式系統(tǒng)要能夠根據(jù)當前負載的變化自動觸發(fā)水平擴容或縮容,因為這一過程可能是頻繁發(fā)生的睬愤、不可預料的片仿,所以手動控制的方式是不現(xiàn)實的。
- 因此尤辱,在Kubernetes的1.0版本實現(xiàn)后砂豌,就有人在默默研究Pod智能擴容的特性了,并在Kubernetes 1.1中首次發(fā)布重量級新特性—Horizontal Pod Autoscaling(Pod橫向自動擴容光督,HPA)阳距。在Kubernetes 1.2中HPA被升級為穩(wěn)定版本(apiVersion: autoscaling/v1),但仍然保留了舊版本(apiVersion: extensions/v1beta1)结借。Kubernetes從1.6版本開始筐摘,增強了根據(jù)應用自定義的指標進行自動擴容和縮容的功能,API版本為autoscaling/v2alpha1船老,并不斷演進援雇。
HPA實現(xiàn)原理
- HPA與之前的RC、Deployment一樣哀九,也屬于一種Kubernetes資源對象咽斧。
- 通過追蹤分析指定RC控制的所有目標Pod的負載變化情況,來確定是否需要有針對性地調(diào)整目標Pod的副本數(shù)量舀锨,這是HPA的實現(xiàn)原理坎匿。
當前替蔬,HPA有以下兩種方式作為Pod負載的度量指標
-
CPUUtilizationPercentage承桥。
-
CPUUtilizationPercentage是一個算術(shù)平均值,即目標Pod所有副本自身的CPU利用率的平均值根悼。一個Pod自身的CPU利用率是該Pod當前CPU的使用量除以它的Pod Request的值凶异。
- 比如定義一個Pod的Pod Request為0.4,而當前Pod的CPU使用量為0.2挤巡,則它的CPU使用率為50%剩彬,這樣就可以算出一個RC控制的所有Pod副本的CPU利用率的算術(shù)平均值了。
- 如果某一時刻CPUUtilizationPercentage的值超過80%矿卑,則意味著當前Pod副本數(shù)量很可能不足以支撐接下來更多的請求喉恋,需要進行動態(tài)擴容,而在請求高峰時段過去后粪摘,Pod的CPU利用率又會降下來瀑晒,此時對應的Pod副本數(shù)應該自動減少到一個合理的水平。
- 如果目標Pod沒有定義Pod Request的值徘意,則無法使用CPUUtilizationPercentage實現(xiàn)Pod橫向自動擴容苔悦。除了使用CPUUtilizationPercentage,Kubernetes從1.2版本開始也在嘗試支持應用程序自定義的度量指標玖详。
-
-
應用程序自定義的度量指標,比如服務在每秒內(nèi)的相應請求數(shù)(TPS或QPS)向臀。
在CPUUtilizationPercentage計算過程中使用到的Pod的CPU使用量通常是1min內(nèi)的平均值,通常通過查詢Heapster監(jiān)控子系統(tǒng)來得到這個值,所以需要安裝部署Heapster会喝,這樣便增加了系統(tǒng)的復雜度和實施HPA特性的復雜度译红。
-
因此,從1.7版本開始,Kubernetes自身孵化了一個基礎性能數(shù)據(jù)采集監(jiān)控框架——Kubernetes Monitoring Architecture已卷,從而更好地支持HPA和其他需要用到基礎性能數(shù)據(jù)的功能模塊讳癌。在Kubernetes Monitoring Architecture中,Kubernetes定義了一套標準化的API接口Resource Metrics API骤菠,以方便客戶端應用程序(如HPA)從Metrics Server中獲取目標資源對象的性能數(shù)據(jù)祭阀。
- 例如容器的CPU和內(nèi)存使用數(shù)據(jù)袍啡。到了Kubernetes 1.8版本颖系,Resource Metrics API被升級為metrics.k8s.io/v1beta1,已經(jīng)接近生產(chǎn)環(huán)境中的可用目標了强缘。
HPA定義的一個具體例子
下面是HPA定義的一個具體例子:
根據(jù)上面的定義商虐,我們可以知道這個HPA控制的目標對象為一個名為php-apache的Deployment里的Pod副本劫哼,當這些Pod副本的CPUUtilizationPercentage的值超過90%時會觸發(fā)自動動態(tài)擴容行為疫向,在擴容或縮容時必須滿足的一個約束條件是Pod的副本數(shù)為1~10侈询。
除了可以通過直接定義YAML文件并且調(diào)用kubectrl create的命令來創(chuàng)建一個HPA資源對象的方式温技,還可以通過下面的簡單命令行直接創(chuàng)建等價的HPA對象:
后面會給出一個完整的HPA例子來說明其用法和功能
StatefulSet:管理有狀態(tài)資源對象
在Kubernetes系統(tǒng)中蜓堕,Pod的管理對象RC慕淡、Deployment、DaemonSet和Job都面向無狀態(tài)的服務。但現(xiàn)實中有很多服務是有狀態(tài)的勒葱,特別是一些復雜的中間件集群,例如MySQL集群、MongoDB集群钠署、Akka集群狸棍、ZooKeeper集很多服務是有狀態(tài)的,特別是一些復雜的中間件集群,例如MySQL集群、MongoDB集群、Akka集群、ZooKeeper集群等,這些應用集群有4個共同點肪凛。
(1)每個節(jié)點都有固定的身份ID辽社,通過這個ID伟墙,集群中的成員可以相互發(fā)現(xiàn)并通信。
(2)集群的規(guī)模是比較固定的滴铅,集群規(guī)模不能隨意變動戳葵。
(3)集群中的每個節(jié)點都是有狀態(tài)的浦妄,通常會持久化數(shù)據(jù)到永久存儲中。
(4)如果磁盤損壞堡距,則集群里的某個節(jié)點無法正常運行亡电,集群功能受損。
如果通過RC或Deployment控制Pod副本數(shù)量來實現(xiàn)上述有狀態(tài)的集群捌省,就會發(fā)現(xiàn)第1點是無法滿足的斤寂,因為Pod的名稱是隨機產(chǎn)生的,Pod的IP地址也是在運行期才確定且可能有變動的状飞,我們事先無法為每個Pod都確定唯一不變的ID勤揩。另外,為了能夠在其他節(jié)點上恢復某個失敗的節(jié)點惹苗,這種集群中的Pod需要掛接某種共享存儲,為了解決這個問題,Kubernetes從1.4版本開始引入了PetSet這個新的資源對象仰挣,并且在1.5版本時更名為StatefulSet严嗜,StatefulSet從本質(zhì)上來說,可以看作Deployment/RC的一個特殊變種漫玄。
特性
StatefulSet里的每個Pod都有穩(wěn)定茄蚯、唯一的網(wǎng)絡標識,可以用來發(fā)現(xiàn)集群內(nèi)的其他成員睦优。假設StatefulSet的名稱為kafka渗常,那么第1個Pod叫kafka-0,第2個叫kafka-1汗盘,以此類推凳谦。
StatefulSet控制的Pod副本的啟停順序是受控的,操作第n個Pod時衡未,前n-1個Pod已經(jīng)是運行且準備好的狀態(tài)尸执。
StatefulSet里的Pod采用穩(wěn)定的持久化存儲卷,通過PV或PVC來實現(xiàn)缓醋,刪除Pod時默認不會刪除與StatefulSet相關(guān)的存儲卷(為了保證數(shù)據(jù)的安全)如失。
-
需要聲明每個StatefulSet屬于哪個Headless Service
- StatefulSet除了要與PV卷捆綁使用以存儲Pod的狀態(tài)數(shù)據(jù),還要與Headless Service配合使用送粱,即在每個StatefulSet定義中都要聲明它屬于哪個Headless Service褪贵。
- Headless Service與普通Service的關(guān)鍵區(qū)別在于,它沒有Cluster IP抗俄,如果解析Headless Service的DNS域名脆丁,則返回的是該Service對應的全部Pod的Endpoint列表。
-
StatefulSet在Headless Service的基礎上又為StatefulSet控制的每個Pod實例都創(chuàng)建了一個DNS域名动雹,這個域名的格式為:
image.png
比如一個3節(jié)點的Kafka的StatefulSet集群對應的Headless Service的名稱為kafka槽卫,StatefulSet的名稱為kafka,則StatefulSet里的3個Pod的DNS名稱分別為kafka-0.kafka胰蝠、kafka-1.kafka歼培、kafka-3.kafka,這些DNS名稱可以直接在集群的配置文件中固定下來茸塞。
Service:kubernetes的微服務
概述
Service服務也是Kubernetes里的核心資源對象之一躲庄,Kubernetes里的每個Service其實就是我們經(jīng)常提起的微服務架構(gòu)中的一個微服務。
Pod钾虐、RC與Service的邏輯關(guān)系
Kubernetes的Service定義了一個服務的訪問入口地址噪窘,前端的應用(Pod)通過這個入口地址訪問其背后的一組由Pod副本組成的集群實例,Service與其后端Pod副本集群之間則是通過Label Selector來實現(xiàn)無縫對接的效扫。RC的作用實際上是保證Service的服務能力和服務質(zhì)量始終符合預期標準倔监。
Kubernetes Service
通過分析无切、識別并建模系統(tǒng)中的所有服務為微服務—Kubernetes Service,我們的系統(tǒng)最終由多個提供不同業(yè)務能力而又彼此獨立的微服務單元組成的丐枉,服務之間通過TCP/IP進行通信,從而形成了強大而又靈活的彈性網(wǎng)格掘托,擁有強大的分布式能力瘦锹、彈性擴展能力、容錯能力闪盔,程序架構(gòu)也變得簡單和直觀許多弯院,如圖所示
客戶端如何訪問服務?
理論上的實現(xiàn)方案:負載均衡器
既然每個Pod都會被分配一個單獨的IP地址泪掀,而且每個Pod都提供了一個獨立的Endpoint(Pod IP+ContainerPort)以被客戶端訪問听绳,現(xiàn)在多個Pod副本組成了一個集群來提供服務,那么客戶端如何來訪問它們呢异赫?一般的做法是部署一個負載均衡器(軟件或硬件)椅挣,為這組Pod開啟一個對外的服務端口如8000端口,并且將這些Pod的Endpoint列表加入8000端口的轉(zhuǎn)發(fā)列表塔拳,客戶端就可以通過負載均衡器的對外IP地址+服務端口來訪問此服務鼠证。客戶端的請求最后會被轉(zhuǎn)發(fā)到哪個Pod靠抑,由負載均衡器的算法所決定量九。
Kubernetes的做法
-
kube-proxy
- Kubernetes也遵循上述常規(guī)做法,運行在每個Node上的kube-proxy進程其實就是一個智能的軟件負載均衡器颂碧,負責把對Service的請求轉(zhuǎn)發(fā)到后端的某個Pod實例上荠列,并在內(nèi)部實現(xiàn)服務的負載均衡與會話保持機制。
-
每個Service都被分配了一個全局唯一的虛擬IP地址:Cluster IP
- 但Kubernetes發(fā)明了一種很巧妙又影響深遠的設計:Service沒有共用一個負載均衡器的IP地址载城,每個Service都被分配了一個全局唯一的虛擬IP地址肌似,這個虛擬IP被稱為Cluster IP。這樣一來诉瓦,每個服務就變成了具備唯一IP地址的通信節(jié)點锈嫩,服務調(diào)用就變成了最基礎的TCP網(wǎng)絡通信問題。
-
Service的Name與Service的Cluster IP地址做一個DNS域名映射
- 我們知道垦搬,Pod的Endpoint地址會隨著Pod的銷毀和重新創(chuàng)建而發(fā)生改變呼寸,因為新Pod的IP地址與之前舊Pod的不同。而Service一旦被創(chuàng)建猴贰,Kubernetes就會自動為它分配一個可用的Cluster IP对雪,而且在Service的整個生命周期內(nèi),它的Cluster IP不會發(fā)生改變米绕。于是瑟捣,服務發(fā)現(xiàn)這個棘手的問題在Kubernetes的架構(gòu)里也得以輕松解決:只要用Service的Name與Service的Cluster IP地址做一個DNS域名映射即可完美解決問題〔鲆眨現(xiàn)在想想,這真是一個很棒的設計迈套。
例子
單端口
上述內(nèi)容定義了一個名為tomcat-service的Service捐祠,它的服務端口為8080,擁有“tier=frontend”這個Label的所有Pod實例都屬于它桑李,運行下面的命令進行創(chuàng)建:
我們之前在tomcat-deployment.yaml里定義的Tomcat的Pod剛好擁有這個標簽踱蛀,所以剛才創(chuàng)建的tomcat-service已經(jīng)對應一個Pod實例,運行下面的命令可以查看tomcatservice的Endpoint列表贵白,其中172.17.1.3是Pod的IP地址率拒,端口8080是Container暴露的端口:
你可能有疑問:“說好的Service的Cluster IP呢?怎么沒有看到禁荒?”運行下面的命令即可看到tomct-service被分配的Cluster IP及更多的信息:
在spec.ports的定義中猬膨,targetPort屬性用來確定提供該服務的容器所暴露(EXPOSE)的端口號,即具體業(yè)務進程在容器內(nèi)的targetPort上提供TCP/IP接入呛伴;port屬性則定義了Service的虛端口勃痴。前面定義Tomcat服務時沒有指定targetPort,則默認targetPort與port相同热康。
多端口
很多服務都存在多個端口的問題召耘,通常一個端口提供業(yè)務服務,另外一個端口提供管理服務褐隆,比如Mycat污它、Codis等常見中間件。Kubernetes Service支持多個Endpoint庶弃,在存在多個Endpoint的情況下衫贬,要求每個Endpoint都定義一個名稱來區(qū)分。下面是Tomcat多端口的Service定義樣例:
多端口為什么需要給每個端口都命名呢歇攻?這就涉及Kubernetes的服務發(fā)現(xiàn)機制了固惯,接下來進行講解。
Kubernetes的服務發(fā)現(xiàn)機制
任何分布式系統(tǒng)都會涉及“服務發(fā)現(xiàn)”這個基礎問題缴守,大部分分布式系統(tǒng)都通過提供特定的API接口來實現(xiàn)服務發(fā)現(xiàn)功能葬毫,但這樣做會導致平臺的侵入性比較強,也增加了開發(fā)屡穗、測試的難度贴捡。Kubernetes則采用了直觀樸素的思路去解決這個棘手的問題。
首先村砂,每個Kubernetes中的Service都有唯一的Cluster IP及唯一的名稱烂斋,而名稱是由開發(fā)者自己定義的,部署時也沒必要改變,所以完全可以被固定在配置中汛骂。接下來的問題就是如何通過Service的名稱找到對應的Cluster IP罕模。
通過Service的名稱找到對應的Cluster IP的實現(xiàn)方式
1.每個Service都生成一些對應的Linux環(huán)境變量(ENV)
最早時Kubernetes采用了Linux環(huán)境變量解決這個問題,即每個Service都生成一些對應的Linux環(huán)境變量(ENV)帘瞭,并在每個Pod的容器啟動時自動注入這些環(huán)境變量淑掌。以下是tomcat-service產(chǎn)生的環(huán)境變量條目:
在上述環(huán)境變量中,比較重要的是前3個環(huán)境變量蝶念∨淄螅可以看到,每個Service的IP地址及端口都有標準的命名規(guī)范祸轮,遵循這個命名規(guī)范,就可以通過代碼訪問系統(tǒng)環(huán)境變量來得到所需的信息侥钳,實現(xiàn)服務調(diào)用适袜。
2.把服務名作為DNS域名
考慮到通過環(huán)境變量獲取Service地址的方式仍然不太方便、不夠直觀舷夺,后來Kubernetes通過Add-On增值包引入了DNS系統(tǒng)苦酱,把服務名作為DNS域名,這樣程序就可以直接使用服務名來建立通信連接了给猾。目前疫萤,Kubernetes上的大部分應用都已經(jīng)采用了DNS這種新興的服務發(fā)現(xiàn)機制,后面會講解如何部署DNS系統(tǒng)敢伸。
外部系統(tǒng)訪問Service的問題
Kubernetes里的3種IP
為了更深入地理解和掌握Kubernetes扯饶,我們需要弄明白Kubernetes里的3種IP,這3種IP分別如下尾序。
-
Node IP:Node的IP地址
- Node IP是Kubernetes集群中每個節(jié)點的物理網(wǎng)卡的IP地址每币,是一個真實存在的物理網(wǎng)絡,所有屬于這個網(wǎng)絡的服務器都能通過這個網(wǎng)絡直接通信兰怠,不管其中是否有部分節(jié)點不屬于這個Kubernetes集群李茫。
- 這也表明在Kubernetes集群之外的節(jié)點訪問Kubernetes集群之內(nèi)的某個節(jié)點或者TCP/IP服務時揭保,都必須通過Node IP通信俭厚。
-
Pod IP:Pod的IP地址
- Pod IP是每個Pod的IP地址象踊,它是Docker Engine根據(jù)docker0網(wǎng)橋的IP地址段進行分配的继榆,通常是一個虛擬的二層網(wǎng)絡略吨,前面說過鞠苟,Kubernetes要求位于不同Node上的Pod都能夠彼此直接通信当娱,所以Kubernetes里一個Pod里的容器訪問另外一個Pod里的容器時跨细,就是通過Pod IP所在的虛擬二層網(wǎng)絡進行通信的,而真實的TCP/IP流量是通過Node IP所在的物理網(wǎng)卡流出的云头。
-
Cluster IP:Service的IP地址。
-
它也是一種虛擬的IP昏滴,但更像一個“偽造”的IP網(wǎng)絡,原因有以下幾點:
- Cluster IP僅僅作用于Kubernetes Service這個對象姻几,并由Kubernetes管理和分配IP地址(來源于Cluster IP地址池)抚恒。
- Cluster IP無法被Ping俭驮,因為沒有一個“實體網(wǎng)絡對象”來響應。
- Cluster IP只能結(jié)合Service Port組成一個具體的通信端口逸嘀,單獨的Cluster IP不具備TCP/IP通信的基礎,并且它們屬于Kubernetes集群這樣一個封閉的空間绳姨,集群外的節(jié)點如果要訪問這個通信端口脑蠕,則需要做一些額外的工作迂求。
- 在Kubernetes集群內(nèi)揩局,Node IP網(wǎng)、Pod IP網(wǎng)與Cluster IP網(wǎng)之間的通信,采用的是Kubernetes自己設計的一種編程方式的特殊路由規(guī)則县忌,與我們熟知的IP路由有很大的不同装获。
-
NodePort
根據(jù)上面的分析和總結(jié)饱溢,我們基本明白了:Service的Cluster IP屬于Kubernetes集群內(nèi)部的地址,無法在集群外部直接使用這個地址肋杖。那么矛盾來了:實際上在我們開發(fā)的業(yè)務系統(tǒng)中肯定多少有一部分服務是要提供給Kubernetes集群外部的應用或者用戶來使用的,典型的例子就是Web端的服務模塊,比如上面的tomcat-service肉拓,那么用戶怎么訪問它?
采用NodePort是解決上述問題的最直接驻售、有效的常見做法。以tomcat-service為例,在Service的定義里做如下擴展即可(見代碼中的粗體部分):
其中,nodePort:31002這個屬性表明手動指定tomcat-service的NodePort為31002存哲,否則Kubernetes會自動分配一個可用的端口察滑。接下來在瀏覽器里訪問http://<nodePortIP>:31002/,就可以看到Tomcat的歡迎界面了饲化,如圖所示
NodePort的實現(xiàn)方式是在Kubernetes集群里的每個Node上都為需要外部訪問的Service開啟一個對應的TCP監(jiān)聽端口,外部系統(tǒng)只要用任意一個Node的IP地址+具體的NodePort端口號即可訪問此服務,在任意Node上運行netstat命令族奢,就可以看到有NodePort端口被監(jiān)聽:
NodePort還沒有完全解決外部訪問Service的所有問題
但NodePort還沒有完全解決外部訪問Service的所有問題卜高,比如負載均衡問題掺涛。假如在我們的集群中有10個Node,則此時最好有一個負載均衡器,外部的請求只需訪問此負載均衡器的IP地址减拭,由負載均衡器負責轉(zhuǎn)發(fā)流量到后面某個Node的NodePort上修陡,如圖所示
Load balancer組件獨立于Kubernetes集群之外,通常是一個硬件的負載均衡器,或者是以軟件方式實現(xiàn)的绢记,例如HAProxy或者Nginx。對于每個Service,我們通常需要配置一個對應的Load balancer實例來轉(zhuǎn)發(fā)流量到后端的Node上骏啰,這的確增加了工作量及出錯的概率。于是Kubernetes提供了自動化的解決方案,如果我們的集群運行在谷歌的公有云GCE上草丧,那么只要把Service的type=NodePort改為type=LoadBalancer,Kubernetes就會自動創(chuàng)建一個對應的Load balancer實例并返回它的IP地址供外部客戶端使用。其他公有云提供商只要實現(xiàn)了支持此特性的驅(qū)動岖赋,則也可以達到上述目的汁汗。此外,裸機上的類似機制(Bare Metal Service Load Balancers)也在被開發(fā)。
Job:批處理
批處理任務通常并行(或者串行)啟動多個計算進程去處理一批工作項(work item)扁藕,在處理完成后,整個批處理任務結(jié)束。從1.2版本開始痕支,Kubernetes支持批處理類型的應用儒陨,我們可以通過Kubernetes Job這種新的資源對象定義并啟動一個批處理任務Job椭员。與RC容劳、Deployment蚜印、ReplicaSet哟冬、DaemonSet類似,Job也控制一組Pod容器翰灾。從這個角度來看,Job也是一種特殊的Pod副本自動控制器
Job控制Pod副本與RC等控制器的工作機制有以下重要差別:
-
Job所控制的Pod副本是短暫運行的可以將其視為一組Docker容器
- 其中的每個Docker容器都僅僅運行一次。當Job控制的所有Pod副本都運行結(jié)束時,對應的Job也就結(jié)束了峭竣。Job在實現(xiàn)方式上與RC等副本控制器不同哲银,Job生成的Pod副本是不能自動重啟的滥比,對應Pod副本的RestartPoliy都被設置為Never。因此,當對應的Pod副本都執(zhí)行完成時村视,相應的Job也就完成了控制使命,即Job生成的Pod在Kubernetes中是短暫存在的站刑。
- Kubernetes在1.5版本之后又提供了類似crontab的定時任務——CronJob愕宋,解決了某些批處理任務需要定時反復執(zhí)行的問題囤捻。
-
Job所控制的Pod副本的工作模式能夠多實例并行計算
- 以TensorFlow框架為例,可以將一個機器學習的計算任務分布到10臺機器上,在每臺機器上都運行一個worker執(zhí)行計算任務,這很適合通過Job生成10個Pod副本同時啟動運算取逾。
Volume:Pod中能夠被多個容器訪問的共享目錄
Volume(存儲卷)是Pod中能夠被多個容器訪問的共享目錄债蜜。
Kubernetes的Volume概念儒洛、用途和目的與Docker的Volume比較類似唐含,但兩者不能等價滚秩。
- 首先,Kubernetes中的Volume被定義在Pod上,然后被一個Pod里的多個容器掛載到具體的文件目錄下;
- 其次,Kubernetes中的Volume與Pod的生命周期相同石挂,但與容器的生命周期不相關(guān)痹愚,當容器終止或者重啟時,Volume中的數(shù)據(jù)也不會丟失蛔糯。
- 最后里伯,Kubernetes支持多種類型的Volume,例如GlusterFS疾瓮、Ceph等先進的分布式文件系統(tǒng)。
聲明一個Volume
Volume的使用也比較簡單飒箭,在大多數(shù)情況下狼电,我們先在Pod上聲明一個Volume,然后在容器里引用該Volume并掛載(Mount)到容器里的某個目錄上弦蹂。舉例來說肩碟,我們要給之前的Tomcat Pod增加一個名為datavol的Volume,并且掛載到容器的/mydata-data目錄上凸椿,則只要對Pod的定義文件做如下修正即可(注意代碼中的粗體部分):
除了可以讓一個Pod里的多個容器共享文件削祈、讓容器的數(shù)據(jù)寫到宿主機的磁盤上或者寫文件到網(wǎng)絡存儲中,Kubernetes的Volume還擴展出了一種非常有實用價值的功能,即容器配置文件集中化定義與管理髓抑,這是通過ConfigMap這種新的資源對象來實現(xiàn)的咙崎,后面會詳細說明。
Kubernetes提供了非常豐富的Volume類型
-
emptyDir:臨時使用的目錄且初始內(nèi)容為空
-
一個emptyDir Volume是在Pod分配到Node時創(chuàng)建的吨拍。從它的名稱就可以看出褪猛,它的初始內(nèi)容為空,并且無須指定宿主機上對應的目錄文件羹饰,因為這是Kubernetes自動分配的一個目錄伊滋,當Pod從Node上移除時,emptyDir中的數(shù)據(jù)也會被永久刪除队秩。emptyDir的一些用途如下:
- 臨時空間笑旺,例如用于某些應用程序運行時所需的臨時目錄,且無須永久保留馍资。
- 長時間任務的中間過程CheckPoint的臨時保存目錄筒主。
- 一個容器需要從另一個容器中獲取數(shù)據(jù)的目錄(多容器共享目錄)。
-
-
hostPath:hostPath為在Pod上掛載宿主機上的文件或目錄
-
hostPath為在Pod上掛載宿主機上的文件或目錄迷帜,它通澄锸妫可以用于以下幾方面。
- 容器應用程序生成的日志文件需要永久保存時戏锹,可以使用宿主機的高速文件系統(tǒng)進行存儲冠胯。
- 需要訪問宿主機上Docker引擎內(nèi)部數(shù)據(jù)結(jié)構(gòu)的容器應用時,可以通過定義hostPath為宿主機/var/lib/docker目錄锦针,使容器內(nèi)部應用可以直接訪問Docker的文件系統(tǒng)荠察。
-
在使用這種類型的Volume時,需要注意以下幾點奈搜。
- 在不同的Node上具有相同配置的Pod悉盆,可能會因為宿主機上的目錄和文件不同而導致對Volume上目錄和文件的訪問結(jié)果不一致。
- 如果使用了資源配額管理馋吗,則Kubernetes無法將hostPath在宿主機上使用的資源納入管理焕盟。
-
在下面的例子中使用宿主機的/data目錄定義了一個hostPath類型的Volume:
image.png
-
-
gcePersistentDisk:使用谷歌公有云提供的永久磁盤(Persistent Disk,PD)存放Volume的數(shù)據(jù)
使用這種類型的Volume表示使用谷歌公有云提供的永久磁盤(Persistent Disk宏粤,PD)存放Volume的數(shù)據(jù)脚翘,它與emptyDir不同,PD上的內(nèi)容會被永久保存绍哎,當Pod被刪除時来农,PD只是被卸載(Unmount),但不會被刪除崇堰。需要注意的是沃于,你需要先創(chuàng)建一個PD涩咖,才能使用gcePersistentDisk。
-
使用gcePersistentDisk時有以下一些限制條件繁莹。
- Node(運行kubelet的節(jié)點)需要是GCE虛擬機檩互。
- 這些虛擬機需要與PD存在于相同的GCE項目和Zone中。
-
通過gcloud命令即可創(chuàng)建一個PD:
image.png
-
定義gcePersistentDisk類型的Volume的示例如下:
image.png
-
-
awsElasticBlockStore:使用亞馬遜公有云提供的EBS Volume存儲數(shù)據(jù)
與GCE類似蒋困,該類型的Volume使用亞馬遜公有云提供的EBS Volume存儲數(shù)據(jù)盾似,需要先創(chuàng)建一個EBS Volume才能使用awsElasticBlockStore敬辣。
-
使用awsElasticBlockStore的一些限制條件如下雪标。
- Node(運行kubelet的節(jié)點)需要是AWS EC2實例。
- 這些AWS EC2實例需要與EBS Volume存在于相同的region和availability-zone中溉跃。
- EBS只支持單個EC2實例掛載一個Volume村刨。
-
通過aws ec2 create-volume命令可以創(chuàng)建一個EBS Volume
image.png -
定義awsElasticBlockStore類型的Volume的示例如下:
image.png
-
NFS
-
使用NFS網(wǎng)絡文件系統(tǒng)提供的共享目錄存儲數(shù)據(jù)時,我們需要在系統(tǒng)中部署一個NFS Server撰茎。定義NFS類型的Volume的示例如下:
image.png
-
-
其他類型的Volume
- iscsi:使用iSCSI存儲設備上的目錄掛載到Pod中嵌牺。
- flocker:使用Flocker管理存儲卷。
- glusterfs:使用開源GlusterFS網(wǎng)絡文件系統(tǒng)的目錄掛載到Pod中龄糊。
- rbd:使用Ceph塊設備共享存儲(Rados Block Device)掛載到Pod中逆粹。
- gitRepo:通過掛載一個空目錄,并從Git庫clone一個git repository以供Pod使用炫惩。
- secret:一個Secret Volume用于為Pod提供加密的信息僻弹,你可以將定義在Kubernetes中的Secret直接掛載為文件讓Pod訪問。Secret Volume是通過TMFS(內(nèi)存文件系統(tǒng))實現(xiàn)的他嚷,這種類型的Volume總是不會被持久化的蹋绽。
Persistent Volume:kubernetes集群的網(wǎng)絡存儲
之前提到的Volume是被定義在Pod上的,屬于計算資源的一部分筋蓖,而實際上卸耘,網(wǎng)絡存儲是相對獨立于計算資源而存在的一種實體資源。比如在使用虛擬機的情況下粘咖,我們通常會先定義一個網(wǎng)絡存儲蚣抗,然后從中劃出一個“網(wǎng)盤”并掛接到虛擬機上。Persistent Volume(PV)和與之相關(guān)聯(lián)的Persistent Volume Claim(PVC)也起到了類似的作用瓮下。
與Volume的區(qū)別
PV可以被理解成Kubernetes集群中的某個網(wǎng)絡存儲對應的一塊存儲翰铡,它與Volume類似,但有以下區(qū)別唱捣。
- PV只能是網(wǎng)絡存儲两蟀,不屬于任何Node,但可以在每個Node上訪問震缭。
- PV并不是被定義在Pod上的赂毯,而是獨立于Pod之外定義的。
- PV目前支持的類型包括:gcePersistentDisk、AWSElasticBlockStore党涕、AzureFile烦感、AzureDisk、FC(Fibre Channel)膛堤、Flocker手趣、NFS、iSCSI肥荔、RBD(Rados Block Device)绿渣、CephFS、Cinder燕耿、GlusterFS中符、VsphereVolume、Quobyte Volumes誉帅、VMware Photon淀散、Portworx Volumes、ScaleIO Volumes和HostPath(僅供單機測試)蚜锨。
例子
下面給出了NFS類型的PV的一個YAML定義文件档插,聲明了需要5Gi的存儲空間:
比較重要的是PV的accessModes屬性,目前有以下類型亚再。
- ReadWriteOnce:讀寫權(quán)限郭膛,并且只能被單個Node掛載。
- ReadOnlyMany:只讀權(quán)限针余,允許被多個Node掛載饲鄙。
- ReadWriteMany:讀寫權(quán)限,允許被多個Node掛載圆雁。
如果某個Pod想申請某種類型的PV忍级,則首先需要定義一個PersistentVolumeClaim對象:
然后,在Pod的Volume定義中引用上述PVC即可:
PV的狀態(tài)
PV是有狀態(tài)的對象伪朽,它的狀態(tài)有以下幾種轴咱。
- Available:空閑狀態(tài)。
- Bound:已經(jīng)綁定到某個PVC上烈涮。
- Released:對應的PVC已經(jīng)被刪除朴肺,但資源還沒有被集群收回。
- Failed:PV自動回收失敗坚洽。
Namespace:多租戶的資源隔離
Namespace(命名空間)是Kubernetes系統(tǒng)中的另一個非常重要的概念戈稿,Namespace在很多情況下用于實現(xiàn)多租戶的資源隔離。Namespace通過將集群內(nèi)部的資源對象“分配”到不同的Namespace中讶舰,形成邏輯上分組的不同項目鞍盗、小組或用戶組需了,便于不同的分組在共享使用整個集群的資源的同時還能被分別管理。
Kubernetes集群在啟動后會創(chuàng)建一個名為default的Namespace般甲,通過kubectl可以查看:
接下來肋乍,如果不特別指明Namespace,則用戶創(chuàng)建的Pod敷存、RC墓造、Service都將被系統(tǒng)創(chuàng)建到這個默認的名為default的Namespace中。
Namespace的定義很簡單锚烦。如下所示的YAML定義了名為development的Namespace觅闽。
一旦創(chuàng)建了Namespace,我們在創(chuàng)建資源對象時就可以指定這個資源對象屬于哪個Namespace挽牢。比如在下面的例子中定義了一個名為busybox的Pod谱煤,并將其放入development這個Namespace里:
此時使用kubectl get命令查看摊求,將無法顯示:
這是因為如果不加參數(shù)禽拔,則kubectl get命令將僅顯示屬于default命名空間的資源對象。
可以在kubectl命令中加入--namespace參數(shù)來查看某個命名空間中的對象:
當給每個租戶創(chuàng)建一個Namespace來實現(xiàn)多租戶的資源隔離時室叉,還能結(jié)合Kubernetes的資源配額管理睹栖,限定不同租戶能占用的資源,例如CPU使用量茧痕、內(nèi)存使用量等野来。關(guān)于資源配額管理的問題,在后面中會詳細介紹踪旷。
Annotation:用戶任意定義的附加信息曼氛,以便于外部工具查找
Annotation(注解)與Label類似,也使用key/value鍵值對的形式進行定義令野。不同的是Label具有嚴格的命名規(guī)則舀患,它定義的是Kubernetes對象的元數(shù)據(jù)(Metadata),并且用于Label Selector气破。Annotation則是用戶任意定義的附加信息聊浅,以便于外部工具查找。在很多時候现使,Kubernetes的模塊自身會通過Annotation標記資源對象的一些特殊信息低匙。
通常來說,用Annotation來記錄的信息如下碳锈。
- build信息顽冶、release信息、Docker鏡像信息等售碳,例如時間戳强重、release id號佩迟、PR號、鏡像Hash值竿屹、Docker Registry地址等报强。
- 日志庫、監(jiān)控庫拱燃、分析庫等資源庫的地址信息秉溉。
- 程序調(diào)試工具信息,例如工具名稱碗誉、版本號等召嘶。
- 團隊的聯(lián)系信息,例如電話號碼哮缺、負責人名稱弄跌、網(wǎng)址等。
ConfigMap:動態(tài)修改pod配置
為了能夠準確和深刻理解Kubernetes ConfigMap的功能和價值尝苇,我們需要從Docker說起铛只。我們知道,Docker通過將程序、依賴庫、數(shù)據(jù)及配置文件“打包固化”到一個不變的鏡像文件中的做法陵珍,解決了應用的部署的難題,但這同時帶來了棘手的問題蜕着,即配置文件中的參數(shù)在運行期如何修改的問題。我們不可能在啟動Docker容器后再修改容器里的配置文件红柱,然后用新的配置文件重啟容器里的用戶主進程承匣。為了解決這個問題,Docker提供了兩種方式:
◎ 在運行時通過容器的環(huán)境變量來傳遞參數(shù)锤悄;
◎ 通過Docker Volume將容器外的配置文件映射到容器內(nèi)韧骗。
這兩種方式都有其優(yōu)勢和缺點,在大多數(shù)情況下铁蹈,后一種方式更合適我們的系統(tǒng)宽闲,因為大多數(shù)應用通常從一個或多個配置文件中讀取參數(shù)。但這種方式也有明顯的缺陷:我們必須在目標主機上先創(chuàng)建好對應的配置文件握牧,然后才能映射到容器里容诬。
上述缺陷在分布式情況下變得更為嚴重,因為無論采用哪種方式沿腰,寫入(修改)多臺服務器上的某個指定文件览徒,并確保這些文件保持一致,都是一個很難完成的目標颂龙。此外习蓬,在大多數(shù)情況下纽什,我們都希望能集中管理系統(tǒng)的配置參數(shù),而不是管理一堆配置文件躲叼。
Kubernetes給出動態(tài)修改容器配置參數(shù)的方法
針對上述問題芦缰,Kubernetes給出了一個很巧妙的設計實現(xiàn),如下所述枫慷。
- 首先让蕾,把所有的配置項都當作key-value字符串,當然value可以來自某個文本文件或听,比如配置項password=123456探孝、user=root、host=192.168.8.4用于表示連接FTP服務器的配置參數(shù)誉裆。這些配置項可以作為Map表中的一個項顿颅,整個Map的數(shù)據(jù)可以被持久化存儲在Kubernetes的Etcd數(shù)據(jù)庫中,然后提供API以方便Kubernetes相關(guān)組件或客戶應用CRUD操作這些數(shù)據(jù)足丢,上述專門用來保存配置參數(shù)的Map就是Kubernetes ConfigMap資源對象粱腻。
-
接下來,Kubernetes提供了一種內(nèi)建機制霎桅,將存儲在etcd中的ConfigMap通過Volume映射的方式變成目標Pod內(nèi)的配置文件栖疑,不管目標Pod被調(diào)度到哪臺服務器上,都會完成自動映射滔驶。進一步地,如果ConfigMap中的key-value數(shù)據(jù)被修改卿闹,則映射到Pod中的“配置文件”也會隨之自動更新揭糕。于是,Kubernetes ConfigMap就成了分布式系統(tǒng)中最為簡單(使用方法簡單锻霎,但背后實現(xiàn)比較復雜)且對應用無侵入的配置中心著角。ConfigMap配置集中化的一種簡單方案如圖所示
image.png