1. 程式人生 > 實用技巧 >kubernetes-學習筆記_魂士1

kubernetes-學習筆記_魂士1

一、第一章(快速入門)

1.1 貴圈發展史

  • 2004-2007 Google大規模使用容器Cgroups技術
  • 2008.1 cgroups合併進入linux核心主幹
  • 2013.1 docker專案釋出,對創痛Paas產品"降維打擊"
  • 2014.6 kubernetes專案釋出,Google Borg/Omega系統思想借助開源社群”重生“,”容器設計模式“的思想正式成立
  • 2015.7 CNCF(雲原生基金會)成立,k8s成為第一個CNCF專案
  • 2015-2016 ,容器編排”三國爭霸“,Docker Swarm(偏生態),Mesos(偏技術),Kubernetes在容器編排領域角逐。解決你懂的
  • 2017 Kubernetes專案標準確立,docker公司選舉在核心產品內建kubernetes服務,Swarm專案逐漸停止維護
  • 2018 雲原生技術理念逐步萌芽,kubernetes和容器成為所有云廠商既定標準,以”雲“為核心的軟體思想逐步行程

1.2 landscape

landscape: https://landscape.cncf.io/ 雲原生全景圖

1.3、雲原生

1、雲原生定義:其實是一條使使用者能敏捷的、可複製、可擴充套件的最大化利用“雲”的能力、發揮“雲”的價值的最佳路徑,官方定義:

  Cloud native technologies empower organizations to build and run scalable applications in modern, dynamic environments such as public, private, and hybrid clouds. Containers, service meshes, microservices, immutable infrastructure, and declarative APIs exemplify this approach.
  These techniques enable loosely coupled systems that are resilient, manageable, and observable. Combined with robust automation, they allow engineers to make high-impact changes frequently and predictably with minimal toil.
  The Cloud Native Computing Foundation seeks to drive adoption of this paradigm by fostering and sustaining an ecosystem of open source, vendor-neutral projects. We democratize state-of-the-art patterns to make these innovations accessible for everyone.

2、雲原生的願景:軟體就生在雲上、長在雲上的,全新的軟體開發,釋出和運維模式、

3、雲原生的技術範疇

  • 雲應用定義與開發流程:應用定義與映象製作,CI/CD,訊息和Streaming等
  • 雲應用編排與管理:應用編排和排程、服務發現和治理、遠端呼叫、API閘道器、Service Mesh
  • 監控與可觀測性:監控、日誌、Tracing、混沌工程
  • 雲原生底層技術:容器執行時、雲原生儲存技術、雲原生網路技術
  • 雲原生工具集:流程自動化與配置管理、雲原生安全技術、雲端密碼管理
  • Serveless:Faas、Baas、Serveless計費 //Functions as a Service,Backend as a service

4、雲原生思想的兩個理論基礎:

  • 不可變基礎設施:

    • 目前實現:容器映象 //基礎設施不可變,是完全一個自包含,自描述可以隨時遷移的一個東西
  • 雲應用編排理論:

    • 目前實現:容器設計模式

5、基礎設施向雲演進的過程:

  • 傳統應用基礎設施:(可變)
    • 舉例:部署需要SSH到伺服器,逐個調整配置,以及將程式碼部署到現有伺服器上。基礎設施是獨一無二的寵物,要細心呵護
  • 對“雲”友好的應用基礎設施:(不可變)
    • 部署完成後,基礎設施不會修改或改變,如果要更新構建新的映象即可。基礎設施是可以替代的牲口,隨時替換

6、基礎設施向雲演進的意義:

  • 基礎設施一致性和可靠性:

    • 容器映象 //映象可以在任何地方開啟
    • 自包含 //映象包含執行所需要的所有依賴
    • 可飄逸 //可以飄逸到任何位置
  • 簡單可預測的部署與運維:

    • 自描述,自運維 //
    • 流程自動化 //
    • 容易水平擴充套件 //例項個數調整
    • 可快速複製的管控系統與支援元件 //

7、雲原生關鍵技術點

  • 自包含、可定製的應用映象
  • 應用快速部署與隔離能力
  • 應用基礎設施建立和銷燬的自動化管理
  • 可複製的管控系統與支撐元件

二、第二章(K8s核心概念與API原語)

2.1、什麼是Kubernetes

Kubernetes 源與希臘語,意為"舵手",或“飛行員”,k8s 是通過將8個字母“ubernete"替換為8而匯出的縮寫,container意為集裝箱,k8s寓意成為運送集裝箱的輪船。k8s為一個自動化的容器編排平臺:負責應用的部署、彈性、管理

2.2、核心功能

  • 服務發現與負載均衡
  • 自動釋出與回滾
  • 容器自動裝箱 //容器的自動排程,把一個容器放到叢集的某一個機器上
  • 儲存編排
  • 自動恢復 //檢測節點狀態,在節點異常後自動排程pod
  • 配置與密文管理
  • 批量執行
  • 水平伸縮 //修改副本值即可調整pod個數

2.3、架構

Kubernetes各個元件簡介

  • apiserver:處理api操作,K8s中所有的元件都會和apiserver進行連線,元件和元件之間不會進行連線,apiserver負責和etcd互動。叢集內的所有操作都會經過apiserver
  • controller-manager: 負責叢集內的資源物件(node,namespace,service,token等) 達到預期的工作狀態 //只有一個active,可以進行熱備
  • scheduler: 用與為提交的container 排程到合適的機器上 //只有一個active,可以進行熱備
  • etcd:元資料儲存
  • kubelet: 負責真正去執行這些元件,監聽apiserver的pod繫結事件,提交到container runtime中,在os上建立容器真正建立容器所需要執行的環境。
  • kub-proxy: 利用了iptables的能力,來進行本地ipvs 規則建立

pod建立過程:

pod 建立過程:

0、各元件啟動時向apiserver 發起watch請求進行訂閱,告訴apiserver自己需要訂閱哪些型別的變化的資料。watch是一個典型的釋出-訂閱模式可以有條件的(比如kubelet只關心自己節點上的Pod列表)。list是watch失敗後,資料過於陳舊後的彌補手段。k8s的watch功能是建立在etcd的watch之上的,etcd key-value發生變化,通知apiserver,apiserver對外提供watch api。

1、使用者通過cli或者ui進行pod建立,請求被apiserver接收

2、apiserver收到請求後,不會直接建立pod,而是生成一個包含建立資訊的yaml,並將yaml資訊儲存到etcd

3、scheduler檢視k8s api,判斷pod.spec.Node == null?決定是否需要建立,並根據一定的演算法找到最合適的pod,並將資訊儲存到etcd(通過apiserver儲存)

4、kubelet watch apiserver查詢自己是否有新增pod需要建立,如果有,Kubelet呼叫contianer runtime去建立容器執行環境

2.4、主要概念

  • pod : 是最小的排程以及資源單元、由一個或者多個容器組成、定義容器執行的方式(Command,環境變數等),提供給容器共享的執行環境(網路,程序空間等)

  • Volume:宣告在pod中的容器可訪問的檔案目錄,可以被掛載在Pod中一個或多個容器的指定路徑下,支援多種後端多種儲存的抽象(本地儲存、分散式儲存、雲端儲存)

  • Deployment: 定義一組Pod的副本數目、版本等,通過Controller-manager維持Pod的數目;通過控制器指定的策略控制版本(滾動升級、重新生成、回滾等)

  • Service:提供訪問一個或多個Pod例項的穩定訪問地址,支援多種訪問方式實現(ClusterIP,NodePort,LoadBalancer)

  • NameSpace:一個叢集內部的邏輯隔離機制(鑑權、資源額度),每個資源都屬於一個namespace,同一個Namespace中的資源命名唯一,不同Namespace中的資源可重新命名

  • API:HTTP+JSON/YAML型別的api,kubectl/UI/curl命令 等發起請求

  • Label:一組key:value,可以被selector所查詢,select color=red,資源集合的預設表達形式,例如Service 對應一組Pod

2.5、minikube

本地測試和實驗使用

https://kubernetes/io/docs/tasks/tools/install-minikube

三、第三章(容器基本概念)

3.1、容器與映象

傳統物理機上程序特點:APP可以相互“看見“,相互通訊,使用同樣的檔案系統,同樣的系統資源。意味著具有privileged許可權的程序可以攻擊其他程序。使用同一個檔案系統,導致APP可以對已有的檔案系統進行增刪改查,程序間資源依賴會出現衝突,以及系統資源搶佔問題。

為了解決上述問題,可以使用以下思路:

  • chroot: 檢視級別進行隔離,把一個子目錄程式設計根目錄

  • namespace:資源試圖隔離。程序在環境內使用獨立的環境,但是資源還是使用作業系統的

  • cgroup: 限制APP的資源使用率

什麼是容器:

  • 容器是一個檢視隔離、資源可限制、獨立檔案系統的程序集合。
    • 檢視隔離:如能看見部分程序,獨立主機名等;
    • 控制資源使用率:如2G記憶體大小;CPU使用個數等等。

什麼是映象:

  • 執行容器所需要的檔案集合-容器映象
  • DockerFile- 描述映象構建步驟
  • 構建步驟所產出檔案系統的變化 - changeset //映象分層和複用 的理念和作用
    • 類似:disk snapshot
    • 提高分發效率,減少磁碟壓力 #映象分層帶來的好處,各層級映象複用,基礎映象被上層映象所共用。#舉例,如果本地已經有nginx的基礎映象,針對下載不同版本,只需要下載所需的映象就可以
DockerFile最佳實踐: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

容器和映象:

  • 容器:和系統其他部分隔開的程序集合,包括網路,程序,檔案系統等等
  • 映象:容器所需要的所有檔案集合- Build once,Run anywhere

3.2、容器生命週期

容器是一種具有隔離特性的程序集合,在使用doker run的時候可以使用image來提供獨立的檔案系統,以及指定相應的程式。所指定的這個程式稱為init程序。容器的啟停和init程序同步:

單程序模型:

  • init程序生命週期 = 容器生命週期
  • 執行期間可執行exec執行運維操作

資料持久化:

  • 獨立於容器的生命週期
  • 資料卷 - docker volume vs bind

容器的生命週期和init程序是一致的

# bindg host dir into container
docker run -v /tmp:/tmp busybox:1.25 sh -c "date > /tmp/demo.log"

# check result
cat /tmp/demo.log

# let it handled by docker container engine
docker create volume demo

#demo is volume name 
docker run -v demo:/tmp busybox:1.25 sh -c "date > /tmp/demo.log"

#check result
docker run -v demo:/tmp busybox:1.25 sh -c "cat /tmp/demo.log"

3.3、容器專案的架構

moby和docker-ce以及docker-ee說明:

  • moby是繼承了原先的docker的專案,是社群維護的的開源專案
  • docker-ce是docker公司維護的開源專案,是一個基於moby專案的免費的容器產品
  • docker-ee是docker公司維護的閉源產品,是docker公司的商業產品

  • moby daemon:提供容器映象,網路,volume等的管理
  • containerd:容器執行時管理引擎,獨立於moby daemon
  • shim:類似於守護程序(單個容器的),shim負責管理容器的生命週期,容器可以有不同的執行時,現在有多種容器執行時的解決方案(runC,kata,gVisor等)。shim是用於針對不同的容器執行時所開發的。適用於多種容器執行時。並且可以被containerd動態接管

shim的另外一個好處:對moby或者containerd升級,因為有了shim,所以可以做到不影響業務

3.4、容器和vm的差異

  • VM
    • 隔離效果好,每個應用都是相互獨立的,看不到其他guest os的應用
    • 佔用更大的磁碟空間和更多的資源
  • container:
    • 啟動時間較快
    • 磁碟空間佔用較小
    • 隔離效果要比vm差很多,所以整體提供的隔離效果要差很多。kata container和gadvisor等強隔離的解決方案因此就火了起來

四、第四章(容器設計模式)

4.1、為什麼我們需要pod

4.1.1、容器的本質

  • 容器的本質是?

    • 一個檢視被隔離、資源受限的程序
      • 容器中PID = 1 的程序就是應用本身
        • 容器裡PID = 1的程序就是應用本身
          • 管理虛擬機器 = 管理基礎設施; 管理容器 = 直接管理應用本身
  • kubernetes 是什麼?

    • kubernetes就是雲時代的作業系統
      • 以此類推,容器映象其實就是:這個作業系統的軟體安裝包
    • 容器 = 程序(linux執行緒)
    • Pod = ?
      • 程序組(linux執行緒組)

以kubernetes為一個作業系統來說明:(來看一個真是作業系統中的例子)

linux實現 執行緒為 輕量級的程序

4.1.2、程序組概念提出

  • 舉例: hello world程式由4個程序組成,這些程序之間共享某些檔案
  • 問題:helloworld程式如何用容器跑起來呢?
    • 解法1: 在一個docker容器中,啟動這4個程序
      • 疑問:容器 PID =1的程序就是APP本身的main程序,那麼”誰“來負責管理剩餘的3個程序?
      • 容器是”單程序“模型
      • 除非:
        • 應用程序本身具備”程序管理“能力(這意味著:helloworld程式需要具備systemd的能力)
        • 或者,容器的PID=1程序改為systemd
          • 這會導致:管理容器 = 管理systemd != 直接管理應用本身

注意:除非程式具有systemd的功能,否則他是沒有管理多個程序的能力:

  • 如果在容器中啟動了多個程序,只有一個能成為pid為1的程序。如果pid為1的程序掛了,那麼其他的程序就成為了孤兒,沒人能夠回收容器內其他程序的資源。
  • 如果在程式中run systemd程式,那麼就會存在第二個問題:沒辦法直接管理應用,因為應用的生命週期被systemd接管,應用狀態的生命週期就不等於容器的生命週期。並且無法及時獲知應用程式狀態

4.1.3、pod是什麼

Pod為K8s提出的類似於一個程序組的概念:

四個程序共同組成的一個應用hello workld,實際上會被定義為擁有四個容器的pod。pod是一個邏輯概念,真實啟動的是4個容器。pod是k8s分配資源的一個單位。pod是k8s分配資源的一個單位

4.1.5、來自Google Borg的思考

Google的工程師麼們發現,在Borg專案部署的應用,往往都粗壯乃著類似於”程序和程序組“的關係,更具體的說,就是這些應用之間有著密切的協作關係,使得他們必須部署在同一臺機器上並且分享某些資訊。

思考:為什麼Pod必須是原子排程單位,為何不可以通過排程讓容器實現排程在同一臺機器上?

  • 舉例:兩個容器緊密協作
    • App:業務容器,寫日誌檔案
    • LogCollector: 轉發日誌檔案到ElasticSearch中
  • 記憶體要求:
    • App:1G
    • LogCollector:0.5G
  • 當前可用記憶體:
    • Node_A: 1.25G
    • Node_B: 2G
  • 如果APP 排程到了Node A上,會怎麼樣?
    • Task co-scheduling 問題
      • Mesos:資源推擠(resource hoarding):
        • 所有設定了Affinity約束的任務到達時,才開始統一進行排程 #兩個容器都提交了,才會進行排程
        • 問題:排程效率損失和死鎖
      • Google Omega: 樂觀排程處理衝突 #omega為borg的後代,目的是為了改善基於borg的軟體生態
        • 先不管這些衝突,而是通過精心設計的排程機制在出現了衝突之後解決問題,通過回滾機制解決問題
        • 較為複雜
      • kubernetes: pod

Pod解決了這兩個問題:1、怎麼去描述超親密關係;2、怎麼對超親密關係的容器或者業務進行排程

  • 親密關係 - 排程解決
    • 兩個應用需要執行在同一臺宿主機上
  • 超親密關係 - Pod解決
    • 會發生直接的檔案交換
    • 使用localhost或者socket進行本地通訊
    • 會發生非常頻繁的RPC呼叫
  • 會共享某些Linux namespace(比如一個容器要加入另外一個容器的netowrk namespace)

4.2、pod的實現機制

Pod要解決的問題如何讓一個pod中的多個容器之間最高效的共享某些資源和資料?容器之間原本是被Linux Namespace和cgroups隔離開的

解決方法分為兩個部分:共享網路和共享儲存

4.2.1、共享網路

  • 容器A和B

    • 通過infra container的方式共享同一個 Network NameSpace #pause還提供PID,network,IPC,UTS等名稱空間
      • 映象: k8s.gcr.io/pause;組合語言編寫的、永久處於”暫停“,puase:3.1 大小為743KB非常小
    • 直接使用localhost進行通訊
    • 看到的網路裝置跟infra容器看到 的完全一樣
    • 一個pod只有一個ip地址,也就是這個pod的network Namespace對應的IP地址
      • 所有網路資源,都是一個pod一份,並且被該pod中的所有容器共享
    • 整個Pod的生命週期和infra 容器一致,而與容器A和B無關
  • 通過infra container的方式共享network namespace;這個container永遠處於暫停狀態

  • 一個pod中的所有容器看到的網路試圖是一樣的,整個pod的生命週期一定是等於infra pod的生命週期,並且infra pod一定是第一個啟動的

4.2.2、pod如何去共享儲存

apiVersion: "apps/v1"
kind: "Pod"
metadata:
  name: "name01"
spec:
  restartPolicy: "Always"
  volumes:
  - name: shared-data
	hostPath: 
      path: /data
  containers:	  
    - name: nginx-controller
	  image: nginx 
	  volumeMounts:
	  - name: shared-data 
	    mountPath: /usr/share/nginx/html 
    - name: debian-container
	  image: debian 
	  volumeMounts:
	  - name: shared-data 
	    mountPath: /pod-data 
      command: ["/bin/sh"]		
	  args: ["-c","echo Hello from the debian container ! > /pod-data/index.html"]

shared-data 對應在宿主機上的目錄會被同時繫結掛載進了兩個容器當中

4.3、詳解容器設計模式

所有設計模式的本質都是: 解耦和重用

案例: WAR包 + Tomcat的容器化

  • 方法一: 把WAR包和Tomcat大包進一個映象
    • 無論是WAR包和Tomcat更新都需要重新制作映象
  • 方法二:映象裡只打包Tomcat。使用資料卷(hostPath)從宿主機上將WAR包掛載進tomcat容器
    • 需要維護一套分散式儲存系統
  • 有沒有其他更通用的方法?initContainer

InitContainer:

apiVersion: "apps/v1"
kind: "Pod"
metadata:
  name: "javaweb-2"
spec:
  initContainers: 
  - image: resouer/sample:v2
    name: war
	command: ["cp","/sample.war","/app"]
	volumeMounts:
	- mountPath: /app 
	  name: app-volume
  containers:	  
    - name: tomcat
	  image: tomcat7:latest
	  command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
	  volumeMounts:
	  - name: app-volume
	    mountPath: /root/apache-tomcat-7.0.42-v2/webapps
      ports:
      - containerPort: 8080
        hostPort: 8001	  
  volumes:
  - name: app-volume
    emptyDir: {}
  • init Container會比spec.Containers定義的使用者容器先啟動,並且嚴格按照定義的使用者容器先啟動;如果定義了多個initContainer,initContainer會嚴格按照定義順序依次執行
  • /app是一個Volume
  • Tomcat容器,同樣聲明瞭掛載該Volume到自己的webapp目錄下
  • 故當Tomcat容器啟動時,它的webapps目錄下就一定會存在sample.war
  • 在需要升級的時候,可以只更新sample映象或者只更新tomcat映象

這樣的一種設計方式, 就是k8s中一個比較經典的設計模式:稱為sidecar : 通過在pod內定義專門容器,來執行業務容器所需要的輔助工作

Sidecar的使用場景:

  • 應用與日誌收集,Fluentd等作為日誌收集
  • 代理容器:代理容器對業務容器遮蔽被大力的服務叢集,簡化業務程式碼的實現邏輯。{1、容器之間通過localhost通訊,代理容器的程式碼被全公司重用}
  • 介面卡容器:將業務容器暴漏出來的介面轉換為另一種格式(yaml轉為json,/metric轉為/healthz等)

代理容器場景:一個container 需要訪問外部系統或者服務,但是外部的服務或系統為叢集狀態,業務pod只需要訪問一個ip地址,一種方法,改業務程式碼記錄外部服務地址,還有一種方式就是解耦通過sidecar代理容器。單獨寫一個proxy專門用來對接外部的服務叢集,但是對外只要暴漏一個ip地址就可以了。通過proxy代為連線叢集。這裡面該pod和proxy之間通訊使用localhost無效能損耗。

五、第五章(應用編排與管理)

5.1、資源元資訊

kubernetes資源物件

  • Spec: 期望的狀態
  • Status:觀測到的狀態
  • Kind: 資源型別,Deployment,StatefulSet等
  • Metadata:
    • Labels:
    • Annotations:
    • OwnerReference: 描述多個資源之間的關係

5.1.1、Label

  • 標識性的Key: Value元資料
  • 作用:
    • 用於篩選資源
    • 唯一的組合資源的方法
  • 可以使用selector來查詢
    • 類似於:SQL ' select * from ..wher ...'
資源 標籤1 標籤2
R1 Tie:front Env:dev
R2 Tie:back Env:prod
R3 Tie:front Env:test
R4 Tie:back Env:gray

常見的selector:

  • 相等型Selector: Tie=front 篩選結果為R1和R3
  • 相等型的selector多個selector: Tie=front,Env=dev篩選結果為R1
  • 集合型selector:Env in (test,gray) 篩選結果為R3和R4
  • 其他集合selector:
    • Tie notin (front,back)
    • Tie notin release
    • Tie = !release

5.1.2、annotations

  • 作用:
    • 儲存資源的非標識性資訊
    • 擴充套件資源的spec/status
  • 特點:
    • 一般比label大
    • 格式為 key:value格式
    • 可以包含特殊字元
    • value可以結構化也可以非結構化
    • 可以用來儲存證書id等

5.1.3、ownerReferences

  • ”所有者“即集合類資源
    • Pod的集合:Replicaset,statefulset
  • 集合類資源的控制器建立了歸屬資源
    • Replicaset控制器建立Pod
  • 作用:
    • 方便反向查詢建立資源的物件
    • 方便進行級聯刪除

5.1.4、實踐

[root@master1 yaml]# kubectl run nginx1 --image=reg.mt.com:5000/nginx:latest -l env=dev,tie=front --dry-run=true -o yaml > pod1.yaml
[root@master1 yaml]# kubectl run nginx2 --image=reg.mt.com:5000/nginx:latest -l env=dev,tie=front --dry-run=true -o yaml > pod2.yaml
[root@master1 yaml]# cat pod1.yaml #pod2的只有pod的名稱和label不一樣
apiVersion: apps/v1	
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    env: dev
    tie: front
  name: nginx1
spec:
  replicas: 1
  selector:
    matchLabels:
      env: dev
      tie: front
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        env: dev
        tie: front
    spec:
      containers:
      - image: reg.mt.com:5000/nginx:latest
        name: nginx1
        resources: {}
status: {}
[root@master1 yaml]# kubectl apply -f pod1.yaml  -f pod2.yaml
deployment.apps/nginx1 created
deployment.apps/nginx2 created

#1、獲取pod的label
[root@master1 yaml]# kubectl get pods --show-labels
NAME                      READY   STATUS    RESTARTS   AGE     LABELS
nginx1-fb5497587-gdj9k    1/1     Running   0          3m15s   env=dev,pod-template-hash=fb5497587,tie=front
nginx2-6d5c4f84fb-qzr9q   1/1     Running   0          3m15s   env=dev,pod-template-hash=6d5c4f84fb,tie=front

#2、為pod打標籤/刪除標籤 
[root@master1 ~]# kubectl label pods nginx1-fb5497587-gdj9k  env=test  --overwrite
pod/nginx1-fb5497587-gdj9k labeled
[root@master1 ~]# kubectl get pods --show-labels #因為deployment,所以直接打pod會自動建立一個新的pod
NAME                      READY   STATUS    RESTARTS   AGE    LABELS
nginx1-fb5497587-54x29    1/1     Running   0          14s    env=dev,pod-template-hash=fb5497587,tie=front
nginx1-fb5497587-gdj9k    1/1     Running   0          3h9m   env=test,pod-template-hash=fb5497587,tie=front
nginx2-6d5c4f84fb-qzr9q   1/1     Running   0          3h9m   env=dev,pod-template-hash=6d5c4f84fb,tie=front
[root@master1 ~]# kubectl label pods nginx1-fb5497587-gdj9k  env-   #刪除標籤

#3、label查詢
[root@master1 ~]# kubectl get pods --show-labels -l 'env in (dev,prod)'
NAME                      READY   STATUS    RESTARTS   AGE     LABELS
nginx1-fb5497587-54x29    1/1     Running   0          36m     env=dev,pod-template-hash=fb5497587,tie=front
nginx2-6d5c4f84fb-qzr9q   1/1     Running   0          3h45m   env=dev,pod-template-hash=6d5c4f84fb,tie=front
[root@master1 ~]# kubectl get pods --show-labels -l 'env notin (dev,prod)'
NAME                     READY   STATUS    RESTARTS   AGE     LABELS
nginx1-fb5497587-gdj9k   1/1     Running   0          3h45m   pod-template-hash=fb5497587,tie=front

#4、anotate
[root@master1 ~]# kubectl annotate pods nginx1-fb5497587-dxl7k desc='author by MT'
pod/nginx1-fb5497587-dxl7k annotated
[root@master1 ~]# kubectl get pods nginx1-fb5497587-dxl7k -o yaml |grep annotations -A3
  annotations:
    desc: author by MT
  creationTimestamp: "2021-01-20T13:24:51Z"
  generateName: nginx1-fb5497587-
  
#5、ownerReference
[root@master1 ~]# kubectl get pods  nginx1-fb5497587-dxl7k   -o yaml |grep ownerReferences  -A5
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: ReplicaSet	#被ReplicaSet控制的pod
    name: nginx1-fb5497587  #這個ReplicaSet的名稱是 nginx1-fb5497587
[root@master1 ~]# kubectl get ReplicaSet nginx1-fb5497587  -o yaml |grep ownerReferences -A5
  ownerReferences:
  - apiVersion: apps/v1
    blockOwnerDeletion: true
    controller: true
    kind: Deployment  
    name: nginx1  

5.2、控制器模式

5.2.1、控制迴圈

控制器模式,最核心的就是控制迴圈

  • 元件包含:控制器、被控制的系統、能夠觀測系統的感測器Sensor #三個邏輯元件
  • 各元件獨立自主地執行
  • 不斷使系統向終態趨近 status-> spec

外界通過修改資源的spec控制資源,控制器比較被控制資源的spec和status,計算一個diff。diff用來決定對系統執行什麼樣的操作。控制操作會使得系統產生新的輸出。並被感測器以資源status的形式上報。控制器的各個元件都是獨立自主的執行。

1、感測器sensor:

控制迴圈中邏輯的感測器主要you Reflector,Informer,Indexer 三個元件構成。

  • Reflector: 通過list和watch apiserver來獲取資源的資料;
    • list用來在controller重啟以及連線中斷的情況下進行系統資源的全量分析
    • watch在多次list之間進行增量的資源更新
    • Reflector在獲取新的資源資料後,會在一個delta佇列中插入一個(包括資源本身資訊以及資源事件(event)型別)的記錄;delta佇列保證同一個物件在queue中只有一條記錄
  • Informer: 不斷從delta佇列中pop出記錄, 一方便把資源事件交給event回撥函式,一方面把資源物件交給Indexer
  • Indexer:把資源記錄到快取中。快取預設情況下是以資源的namespace進行索引,並且被多個controller-manager共享

2、控制器迴圈中的控制器元件

  • 主要由event handling 函式,以及worker組成
    • 事件處理函式:監聽informer中的新增、更新、刪除的事件。並根據控制器的邏輯決定是否需要處理。對於需要被處理的event,會把事件關聯資源的namespace以及name資訊放入到一個工作queue中。並且由worker池中的一個worker處理
    • 工作佇列:對資源物件進行去重,從而避免多個worker處理同一個資源。worker在處理資源時,一般需要worker的名字,來重新獲取最新的資源資料,用來建立或者更新資源物件,或者呼叫其他的外部服務。如果worker處理失敗,一般會把資源重新加入到工作佇列中,方便後續重試

5.2.2、控制器迴圈例子

舉例:ReplicaSet(name=rsA,namespace=nsA)資源的replicas(pod個數)使用kubectl edit由2改為3的場景

先更新replicaset.spec,後更新pod,最後更新replicaset.status

  • 1、Reflector會watch Replicaset和Pod兩種資源的變化,發現變化後在delta佇列中新增記錄

  • 2、Informer從delta queue中pop記錄,把新的replicaset更新到快取中(交給indexer)並以namespace和rsa作為索引,另一方面呼叫update的回撥函式

  • 3、Replicaset控制器發現replicaset發生變化後,會把nsA/rsA字串放入到工作佇列中

  • 4、工作佇列中的一個worker獲取 nsA/rsA 這個字串的key,並且從快取中獲取最新的replicaset資料

  • 5、worker通過比較replicaset中的status和spec中的replicas資料,發現需要對replicaset進行擴容。因此replicaset建立了一個pod,這個pod的ownereference取自 rsA

  • 6、Reflector watch到了新增事件,在delta中新增記錄

  • 7、informer從delta中獲取新的記錄,一方面通過indexer放入快取中,另一方面呼叫repliset的控制器的add回撥函式,add函式通過ownereference為rsA找到對應的replicaset,並把包括replicaset和namespace字串放到 工作佇列中

  • 8、replicaset的worker從工作佇列中獲取資料,從快取中獲取最新的replicaset記錄。並得到所有建立的pod

  • 9、因為replicaset狀態不是最新的,也就是所有建立的pod的數量已經不是最新的。因此更新rsA的status和spec一致。replicaset中的sepc和status達到了一致

5.3、控制器模式總結

API有兩種宣告方式:

  • 宣告式API:市場佔用率達到90%,副本個數為3個 //家長和孩子交流
  • 命令式API:吃飯,刪除一個pod //領導和員工交流

kubernetes控制器模式:

  • 由宣告式的API驅動 - k8s 資源物件
  • 由控制器非同步地控制系統向終態驅近
  • 使系統的自動化和無人值守成為可能
  • 便於擴充套件- 自定義資源和控制器(特別的,operator)