kubernetes的基本概念和術(shù)語

核心概念

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:


image.png

然后膳叨,通過kubectl describe node <node_name>查看某個Node的詳細信息:


image.png

image.png

上述命令展示了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è)務容器相速。


image.png

為什么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的資源定義文件:


image.png
  • 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)存:


image.png

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中:


image.png

管理對象RC和Service則通過Selector字段設置需要關(guān)聯(lián)Pod的Label:


image.png

其他管理對象如Deployment菩貌、ReplicaSet、DaemonSet和Job則可以在Selector中使用基于集合的篩選條件定義棚瘟,例如:
image.png

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卓起。


image.png

如果設置“release=beta”的Label Selector,則會選取到Node 2和Node 3上的Pod凹炸,如圖所示戏阅。


image.png

總之,使用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集群中始終只有一個副本:


image.png

作用

  • 在我們定義了一個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映穗。


image.png

上圖描述了在兩個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


image.png

此外辕录,在運行時,我們可以通過修改RC的副本數(shù)量梢卸,來實現(xiàn)Pod的動態(tài)縮放(Scaling)走诞,這可以通過執(zhí)行kubectl scale命令來一鍵完成:
image.png

Scaling的執(zhí)行結(jié)果如圖
image.png

使用的注意事項

  • 刪除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的定義很類似:


image.png

下面通過運行一些例子來直觀地感受Deployment的概念。創(chuàng)建一個名為tomcat-deployment.yaml的Deployment描述文件魔熏,內(nèi)容如下:


image.png

常用命令

1.創(chuàng)建

運行下述命令創(chuàng)建Deployment:


image.png

指定名字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)系:


image.png

4.查看創(chuàng)建的pod

image.png

我們發(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定義的一個具體例子:


image.png

根據(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對象:


image.png

后面會給出一個完整的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)系

image.png

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)也變得簡單和直觀許多弯院,如圖所示


image.png

客戶端如何訪問服務?

理論上的實現(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)在想想,這真是一個很棒的設計迈套。

例子

單端口

image.png

上述內(nèi)容定義了一個名為tomcat-service的Service捐祠,它的服務端口為8080,擁有“tier=frontend”這個Label的所有Pod實例都屬于它桑李,運行下面的命令進行創(chuàng)建:


image.png

我們之前在tomcat-deployment.yaml里定義的Tomcat的Pod剛好擁有這個標簽踱蛀,所以剛才創(chuàng)建的tomcat-service已經(jīng)對應一個Pod實例,運行下面的命令可以查看tomcatservice的Endpoint列表贵白,其中172.17.1.3是Pod的IP地址率拒,端口8080是Container暴露的端口:


image.png

你可能有疑問:“說好的Service的Cluster IP呢?怎么沒有看到禁荒?”運行下面的命令即可看到tomct-service被分配的Cluster IP及更多的信息:
image.png

在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定義樣例:


image.png

多端口為什么需要給每個端口都命名呢歇攻?這就涉及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)境變量條目:


image.png

在上述環(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的定義里做如下擴展即可(見代碼中的粗體部分):


image.png

其中,nodePort:31002這個屬性表明手動指定tomcat-service的NodePort為31002存哲,否則Kubernetes會自動分配一個可用的端口察滑。接下來在瀏覽器里訪問http://<nodePortIP>:31002/,就可以看到Tomcat的歡迎界面了饲化,如圖所示


image.png

NodePort的實現(xiàn)方式是在Kubernetes集群里的每個Node上都為需要外部訪問的Service開啟一個對應的TCP監(jiān)聽端口,外部系統(tǒng)只要用任意一個Node的IP地址+具體的NodePort端口號即可訪問此服務,在任意Node上運行netstat命令族奢,就可以看到有NodePort端口被監(jiān)聽:
image.png
NodePort還沒有完全解決外部訪問Service的所有問題

但NodePort還沒有完全解決外部訪問Service的所有問題卜高,比如負載均衡問題掺涛。假如在我們的集群中有10個Node,則此時最好有一個負載均衡器,外部的請求只需訪問此負載均衡器的IP地址减拭,由負載均衡器負責轉(zhuǎn)發(fā)流量到后面某個Node的NodePort上修陡,如圖所示


image.png

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的定義文件做如下修正即可(注意代碼中的粗體部分):


image.png

除了可以讓一個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的存儲空間:


image.png

比較重要的是PV的accessModes屬性,目前有以下類型亚再。

  • ReadWriteOnce:讀寫權(quán)限郭膛,并且只能被單個Node掛載。
  • ReadOnlyMany:只讀權(quán)限针余,允許被多個Node掛載饲鄙。
  • ReadWriteMany:讀寫權(quán)限,允許被多個Node掛載圆雁。

如果某個Pod想申請某種類型的PV忍级,則首先需要定義一個PersistentVolumeClaim對象:


image.png

然后,在Pod的Volume定義中引用上述PVC即可:


image.png

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可以查看:


image.png

接下來肋乍,如果不特別指明Namespace,則用戶創(chuàng)建的Pod敷存、RC墓造、Service都將被系統(tǒng)創(chuàng)建到這個默認的名為default的Namespace中。
Namespace的定義很簡單锚烦。如下所示的YAML定義了名為development的Namespace觅闽。


image.png

一旦創(chuàng)建了Namespace,我們在創(chuàng)建資源對象時就可以指定這個資源對象屬于哪個Namespace挽牢。比如在下面的例子中定義了一個名為busybox的Pod谱煤,并將其放入development這個Namespace里:
image.png

此時使用kubectl get命令查看摊求,將無法顯示:


image.png

這是因為如果不加參數(shù)禽拔,則kubectl get命令將僅顯示屬于default命名空間的資源對象。
可以在kubectl命令中加入--namespace參數(shù)來查看某個命名空間中的對象:
image.png

當給每個租戶創(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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市旋恼,隨后出現(xiàn)的幾起案子吏口,更是在濱河造成了極大的恐慌,老刑警劉巖冰更,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件产徊,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜀细,警方通過查閱死者的電腦和手機舟铜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奠衔,“玉大人谆刨,你說我怎么就攤上這事塘娶。” “怎么了痊夭?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵刁岸,是天一觀的道長。 經(jīng)常有香客問我她我,道長难捌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任鸦难,我火速辦了婚禮根吁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘合蔽。我一直安慰自己击敌,他們只是感情好,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布拴事。 她就那樣靜靜地躺著沃斤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刃宵。 梳的紋絲不亂的頭發(fā)上衡瓶,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天,我揣著相機與錄音牲证,去河邊找鬼哮针。 笑死,一個胖子當著我的面吹牛坦袍,可吹牛的內(nèi)容都是我干的十厢。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼捂齐,長吁一口氣:“原來是場噩夢啊……” “哼蛮放!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起奠宜,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤包颁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后压真,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娩嚼,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年榴都,在試婚紗的時候發(fā)現(xiàn)自己被綠了待锈。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡嘴高,死狀恐怖竿音,靈堂內(nèi)的尸體忽然破棺而出和屎,到底是詐尸還是另有隱情,我是刑警寧澤春瞬,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布柴信,位于F島的核電站,受9級特大地震影響宽气,放射性物質(zhì)發(fā)生泄漏随常。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一萄涯、第九天 我趴在偏房一處隱蔽的房頂上張望绪氛。 院中可真熱鬧,春花似錦涝影、人聲如沸枣察。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽序目。三九已至,卻和暖如春伯襟,著一層夾襖步出監(jiān)牢的瞬間猿涨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工姆怪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留叛赚,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓片效,卻偏偏與公主長得像红伦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子淀衣,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容