Docker&k8s(三)

編排

? Pod 這個看似復雜的 API 對象,實際上就是對容器的進一步抽象和封裝而已。

? 如果在這個集群中段直,攜帶 app=nginx 標簽的 Pod 的個數大于 2 的時候,就會有舊的 Pod 被刪除;反之市怎,就會有新的 Pod 被創(chuàng)建。

? kube-controller-manager :一系列控制器的集合辛慰。這些控制器之所以被統(tǒng)一放在 pkg/controller 目錄下焰轻,就是因為它們都遵循 Kubernetes 項目中的一個通用編排模式,即:控制循環(huán)(control loop)昆雀。

  • 在具體實現中辱志,實際狀態(tài)往往來自于 Kubernetes 集群本身

  • 而期望狀態(tài)蝠筑,一般來自于用戶提交的 YAML 文件

  1. Deployment 控制器從 Etcd 中獲取到所有攜帶了“app: nginx”標簽的 Pod揩懒,然后統(tǒng)計它們的數量什乙,這就是實際狀態(tài);
  2. Deployment 對象的 Replicas 字段的值就是期望狀態(tài)已球;
  3. Deployment 控制器將兩個狀態(tài)做比較臣镣,然后根據比較結果,確定是創(chuàng)建 Pod智亮,還是刪除已有的 Pod

? 比如忆某,增加 Pod,刪除已有的 Pod阔蛉,或者更新 Pod 的某個字段弃舒。這也是 Kubernetes 項目“面向 API 對象編程”的一個直觀體現。

? 其中状原,這個控制器對象本身聋呢,負責定義被管理對象的期望狀態(tài)。比如颠区,Deployment 里的 replicas=2 這個字段削锰。而被控制對象的定義,則來自于一個“模板”毕莱。比如器贩,Deployment 里的 template 字段。

像 Deployment 定義的 template 字段朋截,在 Kubernetes 項目中有一個專有的名字磨澡,叫作 PodTemplate(Pod 模板)。

image-20200810220103084

? 類似 Deployment 這樣的一個控制器质和,實際上都是由上半部分的控制器定義(包括期望狀態(tài))稳摄,加上下半部分的被控制對象的模板組成的。

Deployment

它實現了 Kubernetes 項目中一個非常重要的功能:Pod 的“水平擴展 / 收縮”(horizontal scaling out/in)

舉個例子饲宿,如果你更新了 Deployment 的 Pod 模板(比如厦酬,修改了容器的鏡像),那么 Deployment 就需要遵循一種叫作“滾動更新”(rolling update)的方式瘫想,來升級現有的容器仗阅。

ReplicaSet

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx-set
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9

從這個 YAML 文件中,我們可以看到国夜,一個 ReplicaSet 對象减噪,其實就是由副本數目的定義和一個 Pod 模板組成的。不難發(fā)現,它的定義其實是 Deployment 的一個子集筹裕。

更重要的是醋闭,Deployment 控制器實際操縱的,正是這樣的 ReplicaSet 對象朝卒,而不是 Pod 對象证逻。

image-20200811180740517

? ReplicaSet 負責通過“控制器模式”,保證系統(tǒng)中 Pod 的個數永遠等于指定的個數抗斤。Deployment 同樣通過“控制器模式”囚企,來操作 ReplicaSet 的個數和屬性,進而實現“水平擴展 / 收縮”和“滾動更新”這兩個編排動作瑞眼。水平擴展 / 收縮”非常容易實現龙宏,Deployment Controller 只需要修改它所控制的 ReplicaSet 的 Pod 副本個數就可以了。

? 滾動更新:修改了Deployment的Pod模板后伤疙,自動觸發(fā)滾動更新银酗,比如直接使用kubectl edit指令編輯etcd里的api對象修改版本。就會逐個將老的RS中的pod副本減少掩浙,新的RS中的pod副本就會逐漸增加花吟。將一個集群中正在運行的多個 Pod 版本秸歧,交替地逐一升級的過程厨姚,就是“滾動更新”。其實就是灰度發(fā)布

kubectl edit 并不神秘键菱,它不過是把 API 對象的內容下載到了本地文件谬墙,讓你修改完成后再提交上去。

? 而為了進一步保證服務的連續(xù)性经备,Deployment Controller 還會確保拭抬,在任何時間窗口內,只有指定比例的 Pod 處于離線狀態(tài)侵蒙。同時造虎,它也會確保,在任何時間窗口內纷闺,只有指定比例的新 Pod 被創(chuàng)建出來算凿。這兩個比例的值都是可以配置的,默認都是 DESIRED 值的 25%犁功。就是cicd上的最大不可用實例數氓轰。

應用版本和 ReplicaSet 一一對應

Deployment 對應用進行版本控制的具體原理

  • 回滾:kubectl rollout undo 命令,就能把整個 Deployment 回滾到上一個版本浸卦。

  • 回滾到更早的版本:首先署鸡,需要使用 kubectl rollout history 命令,查看每次 Deployment 變更對應的版本然后靴庆,我們就可以在 kubectl rollout undo 命令行最后时捌,加上要回滾到的指定版本的版本號,就可以回滾到指定版本了撒穷。Deployment Controller 還會按照“滾動更新”的方式匣椰,完成對 Deployment 的降級操作。

kubectl rollout pause:讓這個 Deployment 進入了一個“暫投死瘢”狀態(tài)禽笑,可以隨意修改而不會立即出發(fā)滾動更新。kubectl rollout resume :可以把這個 Deployment“恢復”回來

StatefulSet(有狀態(tài)應用的編排功能)

  1. 拓撲狀態(tài)蛤奥。這種情況意味著佳镜,應用的多個實例之間不是完全對等的關系。這些應用實例凡桥,必須按照某些順序啟動蟀伸,比如應用的主節(jié)點 A 要先于從節(jié)點 B 啟動。而如果你把 A 和 B 兩個 Pod 刪除掉缅刽,它們再次被創(chuàng)建出來時也必須嚴格按照這個順序才行啊掏。并且,新創(chuàng)建出來的 Pod衰猛,必須和原來 Pod 的網絡標識一樣迟蜜,這樣原先的訪問者才能使用同樣的方法,訪問到這個新 Pod啡省。
  2. 存儲狀態(tài)娜睛。這種情況意味著,應用的多個實例分別綁定了不同的存儲數據卦睹。對于這些應用實例來說畦戒,Pod A 第一次讀取到的數據,和隔了十分鐘之后再次讀取到的數據结序,應該是同一份障斋,哪怕在此期間 Pod A 被重新創(chuàng)建過。這種情況最典型的例子徐鹤,就是一個數據庫應用的多個存儲實例垃环。

? 所以,StatefulSet 的核心功能凳干,就是通過某種方式記錄這些狀態(tài)晴裹,然后在 Pod 被重新創(chuàng)建時,能夠為新 Pod 恢復這些狀態(tài)救赐。

Headless Service

? 一個 Deployment 有 3 個 Pod涧团,那么我就可以定義一個 Service只磷。然后,用戶只要能訪問到這個 Service泌绣,它就能訪問到某個具體的 Pod钮追。訪問這個service的方法:

第一種方式,是以 Service 的 VIP(Virtual IP阿迈,即:虛擬 IP)方式元媚。比如:當我訪問 10.0.23.1 這個 Service 的 IP 地址時,10.0.23.1 其實就是一個 VIP苗沧,它會把請求轉發(fā)到該 Service 所代理的某一個 Pod 上刊棕。這里的具體原理,我會在后續(xù)的 Service 章節(jié)中進行詳細介紹待逞。

第二種方式甥角,就是以 Service 的 DNS 方式。比如:這時候识樱,只要我訪問“my-svc.my-namespace.svc.cluster.local”這條 DNS 記錄嗤无,就可以訪問到名叫 my-svc 的 Service 所代理的某一個 Pod。

第二種方式的處理方法:

  • Normal Service怜庸。這種情況下当犯,你訪問“my-svc.my-namespace.svc.cluster.local”解析到的,正是 my-svc 這個 Service 的 VIP割疾,后面的流程就跟 VIP 方式一致了嚎卫。
  • Headless Service。這種情況下杈曲,你訪問“my-svc.my-namespace.svc.cluster.local”解析到的驰凛,直接就是 my-svc 代理的某一個 Pod 的 IP 地址胸懈。可以看到担扑,這里的區(qū)別在于,Headless Service 不需要分配一個 VIP趣钱,而是可以直接以 DNS 記錄的方式解析出被代理 Pod 的 IP 地址涌献。

Headless Service 被創(chuàng)建后并不會被分配一個 VIP,而是會以 DNS 記錄的方式暴露出它所代理的 Pod首有。按照這樣的方式創(chuàng)建了一個 Headless Service 之后燕垃,它所代理的所有 Pod 的 IP 地址,都會被綁定一個這樣格式的 DNS 記錄:<pod-name>.<svc-name>.<namespace>.svc.cluster.local

StatefulSet 又是如何使用這個 DNS 記錄來維持 Pod 的拓撲狀態(tài)的呢井联?

  1. 這個 YAML 文件卜壕,和我們在前面文章中用到的 nginx-deployment 的唯一區(qū)別,就是多了一個 serviceName=nginx 字段烙常。就是告訴 StatefulSet 控制器轴捎,在執(zhí)行控制循環(huán)(Control Loop)的時候,請使用 nginx 這個 Headless Service 來保證 Pod 的“可解析身份”
  2. StatefulSet 給它所管理的所有 Pod 的名字,進行了編號侦副,編號規(guī)則是:-侦锯。而且這些編號都是從 0 開始累加,與 StatefulSet 的每個 Pod 實例一一對應秦驯,絕不重復尺碰。這兩個 Pod 的 hostname 與 Pod 名字是一致的,都被分配了對應的編號
  3. 當刪除這兩個pod后译隘,k8s會按照原先編號的順序亲桥,創(chuàng)建出兩個新的pod,且分配了原來相同的網絡身份固耘。通過這種嚴格的對應規(guī)則两曼,StatefulSet 就保證了 Pod 網絡標識的穩(wěn)定性

? 比如玻驻,如果 web-0 是一個需要先啟動的主節(jié)點悼凑,web-1 是一個后啟動的從節(jié)點,那么只要這個 StatefulSet 不被刪除璧瞬,你訪問 web-0.nginx 時始終都會落在主節(jié)點上户辫,訪問 web-1.nginx 時,則始終都會落在從節(jié)點上嗤锉,這個關系絕對不會發(fā)生任何變化渔欢。

? Kubernetes 就成功地將 Pod 的拓撲狀態(tài)(比如:哪個節(jié)點先啟動,哪個節(jié)點后啟動)瘟忱,按照 Pod 的“名字 + 編號”的方式固定了下來奥额。此外,Kubernetes 還為每一個 Pod 提供了一個固定并且唯一的訪問入口访诱,即:這個 Pod 對應的 DNS 記錄垫挨。

總結:

? StatefulSet 這個控制器的主要作用之一,就是使用 Pod 模板創(chuàng)建 Pod 的時候触菜,對它們進行編號九榔,并且按照編號順序逐一完成創(chuàng)建工作。而當 StatefulSet 的“控制循環(huán)”發(fā)現 Pod 的“實際狀態(tài)”與“期望狀態(tài)”不一致涡相,需要新建或者刪除 Pod 進行“調諧”的時候哲泊,它會嚴格按照這些 Pod 編號的順序,逐一完成這些操作催蝗。

存儲狀態(tài)的管理機制——Persistent Volume Claim

? Kubernetes 項目引入了一組叫作 Persistent Volume Claim(PVC)和 Persistent Volume(PV)的 API 對象切威,大大降低了用戶聲明和使用持久化 Volume 的門檻。

  1. 定義一個 PVC丙号,聲明想要的 Volume 的屬性先朦。
  2. 2.在應用的 Pod 中且预,聲明使用這個 PVC。

? 這時候烙无,只要我們創(chuàng)建這個 PVC 對象锋谐,Kubernetes 就會自動為它綁定一個符合條件的 Volume。這個PVC對象來自于由運維人員維護的 PV(Persistent Volume)對象截酷。所以涮拗,Kubernetes 中 PVC 和 PV 的設計,實際上類似于“接口”和“實現”的思想迂苛。開發(fā)者只要知道并會使用“接口”三热,即:PVC;而運維人員則負責給“接口”綁定具體的實現三幻,即:PV就漾。

? volumeClaimTemplates :從名字就可以看出來,它跟 Deployment 里 Pod 模板(PodTemplate)的作用類似念搬。也就是說抑堡,凡是被這個 StatefulSet 管理的 Pod,都會聲明一個對應的 PVC朗徊;而這個 PVC 的定義首妖,就來自于 volumeClaimTemplates 這個模板字段。更重要的是爷恳,這個 PVC 的名字有缆,會被分配一個與這個 Pod 完全一致的編號。PVC 其實就是一種特殊的 Volume温亲。只不過一個 PVC 具體是什么類型的 Volume棚壁,要在跟某個 PV 綁定之后才知道。

  1. 當你把一個 Pod栈虚,比如 web-0袖外,刪除之后,這個 Pod 對應的 PVC 和 PV节芥,并不會被刪除在刺,而這個 Volume 里已經寫入的數據逆害,也依然會保存在遠程存儲服務里(比如头镊,我們在這個例子里用到的 Ceph 服務器)。
  2. 此時魄幕,StatefulSet 控制器發(fā)現相艇,一個名叫 web-0 的 Pod 消失了。所以纯陨,控制器就會重新創(chuàng)建一個新的坛芽、名字還是叫作 web-0 的 Pod 來留储,“糾正”這個不一致的情況。
  3. 需要注意的是咙轩,在這個新的 Pod 對象的定義里获讳,它聲明使用的 PVC 的名字,還是叫作:www-web-0活喊。這個 PVC 的定義丐膝,還是來自于 PVC 模板(volumeClaimTemplates),這是 StatefulSet 創(chuàng)建 Pod 的標準流程钾菊。
  4. 所以帅矗,在這個新的 web-0 Pod 被創(chuàng)建出來之后,Kubernetes 為它查找名叫 www-web-0 的 PVC 時煞烫,就會直接找到舊 Pod 遺留下來的同名的 PVC浑此,進而找到跟這個 PVC 綁定在一起的 PV。
  5. 這樣滞详,新的 Pod 就可以掛載到舊 Pod 對應的那個 Volume凛俱,并且獲取到保存在 Volume 里的數據。

通過這種方式料饥,Kubernetes 的 StatefulSet 就實現了對應用存儲狀態(tài)的管理最冰。

  1. 首先,StatefulSet 的控制器直接管理的是 Pod稀火。這是因為暖哨,StatefulSet 里的不同 Pod 實例,不再像 ReplicaSet 中那樣都是完全一樣的凰狞,而是有了細微區(qū)別的篇裁。比如,每個 Pod 的 hostname赡若、名字等都是不同的达布、攜帶了編號的。而 StatefulSet 區(qū)分這些實例的方式逾冬,就是通過在 Pod 的名字里加上事先約定好的編號黍聂。
  2. 其次,Kubernetes 通過 Headless Service身腻,為這些有編號的 Pod产还,在 DNS 服務器中生成帶有同樣編號的 DNS 記錄。只要 StatefulSet 能夠保證這些 Pod 名字里的編號不變嘀趟,那么 Service 里類似于 web-0.nginx.default.svc.cluster.local 這樣的 DNS 記錄也就不會變脐区,而這條記錄解析出來的 Pod 的 IP 地址,則會隨著后端 Pod 的刪除和再創(chuàng)建而自動更新她按。這當然是 Service 機制本身的能力牛隅,不需要 StatefulSet 操心炕柔。
  3. 最后,StatefulSet 還為每一個 Pod 分配并創(chuàng)建一個同樣編號的 PVC媒佣。這樣匕累,Kubernetes 就可以通過 Persistent Volume 機制為這個 PVC 綁定上對應的 PV,從而保證了每一個 Pod 都擁有一個獨立的 Volume默伍。
  4. 在這種情況下哩罪,即使 Pod 被刪除,它所對應的 PVC 和 PV 依然會保留下來巡验。所以當這個 Pod 被重新創(chuàng)建出來之后际插,Kubernetes 會為它找到同樣編號的 PVC,掛載這個 PVC 對應的 Volume显设,從而獲取到以前保存在 Volume 里的數據框弛。

總結:StatefulSet 其實就是一種特殊的 Deployment,而其獨特之處在于捕捂,它的每個 Pod 都被編號了瑟枫。而且,這個編號會體現在 Pod 的名字和 hostname 等標識信息上指攒,這不僅代表了 Pod 的創(chuàng)建順序慷妙,也是 Pod 的重要網絡標識(即:在整個集群里唯一的、可被的訪問身份)允悦。

? 有了這個編號后膝擂,StatefulSet 就使用 Kubernetes 里的兩個標準功能:Headless Service 和 PV/PVC,實現了對 Pod 的拓撲狀態(tài)和存儲狀態(tài)的維護隙弛。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末架馋,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子全闷,更是在濱河造成了極大的恐慌叉寂,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件总珠,死亡現場離奇詭異屏鳍,居然都是意外死亡,警方通過查閱死者的電腦和手機局服,發(fā)現死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門钓瞭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腌逢,你說我怎么就攤上這事降淮。” “怎么了搏讶?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵佳鳖,是天一觀的道長。 經常有香客問我媒惕,道長系吩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任妒蔚,我火速辦了婚禮穿挨,結果婚禮上,老公的妹妹穿的比我還像新娘肴盏。我一直安慰自己科盛,他們只是感情好,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布菜皂。 她就那樣靜靜地躺著贞绵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恍飘。 梳的紋絲不亂的頭發(fā)上榨崩,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音章母,去河邊找鬼母蛛。 笑死,一個胖子當著我的面吹牛乳怎,可吹牛的內容都是我干的彩郊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蚪缀,長吁一口氣:“原來是場噩夢啊……” “哼焦辅!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤续担,失蹤者是張志新(化名)和其女友劉穎蝌数,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體前方,經...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年廉油,在試婚紗的時候發(fā)現自己被綠了惠险。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡抒线,死狀恐怖班巩,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情嘶炭,我是刑警寧澤抱慌,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布逊桦,位于F島的核電站,受9級特大地震影響抑进,放射性物質發(fā)生泄漏强经。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一寺渗、第九天 我趴在偏房一處隱蔽的房頂上張望匿情。 院中可真熱鬧,春花似錦信殊、人聲如沸炬称。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玲躯。三九已至,卻和暖如春鲸伴,著一層夾襖步出監(jiān)牢的瞬間府蔗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工汞窗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留姓赤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓仲吏,卻偏偏與公主長得像不铆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子裹唆,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355