k8s基礎概念及術語


上一篇簡單介紹了一下k8s是什么以及如何使用kubeadm快捷安裝,今兒來聊一下k8s的幾個基礎概念及術語。k8s中的資源都可以使用yaml文件進行描述。(文章內容來源於《kubernetes權威指南 第四版》)

 

Master

集群控制節點,負責整個集群的管理和控制,負責命令的執行過程,運行着以下四個關鍵進程。

(1)Kubernetes API Service(Kube-apiservice):提供了Http Rest 接口的關鍵服務進程,是K8s里所有資源的CRUD的唯一操作入口,也是集群控制的入口進程。

(2)Kubernetes Controller Manager(Kube-controller-manager):K8s中所有資源對象的自動化控制中心,資源對象的大總管。controller用於監控容器健康狀態,controller manager監控controller的健康狀態。

(3)Kubernetes Scheduler(Kube-scheduler):先做預選,篩選有哪些Node符合,然后做優選最佳的節點。負責資源調度(Pod調度)的進程。

(4)etcd server:保存所有資源對象的數據。當數據發生變化時,etcd 會快速地通知 Kubernetes 相關組件。

Node

工作負載節點,每個Node都會被Master分配工作負載(Docker容器),當某個Node宕機時,其上的工作負載會被Master自動轉移到其他節點上。每個Node節點都運行着以下一組進程。

(1)kubelet:負責Pod對應的容器創建、啟停等任務,同時與Master密切協作,實現集群管理的基本功能。

(2)kube-proxy:實現K8s service的通信和負載均衡機制的重要組件。

(3)Docker Enginer:Docker引擎,負責本機的容器創建和管理工作。

Node節點可在運行時動態增加到集群中,默認情況下kubelet會向Master注冊自己。會定時匯報自身信息,比如Docker版本、CPU、內存、運行哪些Pod等。這樣Master可以熟知Node節點的信息,實現高效均衡的資源調度策略,在指定時間內沒上報,會被Master判斷為失聯,進行工作負載轉移。

~可通過如下命令查看集群中節點

kubectl get nodes

  

 

~可通過如下命令查看節點詳細信息

kubectl describe nodes/節點名稱

  

 

Pod

 

根容器Pause,作為業務無關並不易死亡的Pause容器,它的狀態代表了整個容器組的狀態,可以簡單有效判斷容器是否已死。

Pod里多個業務容器共享Pause容器的IP和Volume,簡化了業務容器之間的通信問題,也解決了文件共享問題。

k8s為每個Pod分配了一個唯一的IP地址,簡稱Pod IP,Pod里面的容器可以共享IP,采用虛擬二層網絡技術實現集群內任意兩個Pod之間可以直接進行TCP/IP通信。

 

Pod有兩種類型:普通Pod和靜態Pod,靜態Pod並不存放在etcd存儲里,而是存放在某個具體的Node里的一個具體文件中,並且只在此Node上運行。普通Pod創建之后就會被放在etcd中存儲,隨后被Master調度到某個Node上並進行綁定,被Node上kubelet進程實例化成一組相關的Docker容器並啟動。默認情況下,Pod某個容器停止 時,k8s會自動檢測並重啟此Pod,如果所在的Node宕機,則會將所有Pod重新調度到其他節點上。

每個Pod都可以對其能使用的服務器上的計算資源設置限額,當前可以設置限額的計算資源有cpu和memory兩種,其中cpu的資源單位以cpu的數量,是一個絕對值而非相對值。

在k8s中,通常以千分之一的CPU配額為最小單位,用m來表示,Memory配額也是一個絕對值,單位時內存字節數。

在K8s中,一個計算資源進行配額限定需要設定以下兩個參數:

Requests:最小申請量,必須滿足此要求。

Limits:最大允許使用量,不能被突破,當容器試圖突破時,會被kill掉然后重啟。

例如:在聲明某個Pod或Service時可以在spec中進行設置

spec:
  container:
  - name: db
    image: mysql
    imagePullPolixy: IfNotPresent
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

  

 

Event是一個事件的記錄,記錄了事件的最早發生時間、最后重現時間、重復次數、發起者、類型,以及導致此事件的原因等。

可使用如下命令在資源的詳細描述中看到

kubectl describe 資源類型 資源名稱 例如:
kubectl describe nodes cnode-1

  

 

 

Label

標簽信息,kv鍵值對,可附加到各種資源對象上,例如Node,Pod,Service,RC等,一個資源對象可以定義多個Label,一個Label可以被添加到多個資源上,通常在資源定義時確定,也可在在對象創建后動態添加或刪除。

可通過Label Selector查詢和篩選擁有某些Label的資源對象。當前有 兩種Label Selector的表達式,基於等式和基於集合。

例如:name=redis

env != dev

name in (a,b)

name not in (a,b)

當需要多個實現復雜選擇的時候,可以用逗號分隔,表示And的關系。

Label Selector使用場景:

(1)Kube-controller通過RC上定義的Label Selector來 篩選要監控的Pod副本數量,從而實現Pod副本的數量始終符合預期設定的全自動監控流程。

(2)kube-proxy通過Service的Label Selector來選擇對應的Pod,自動建立起每個Service到對象Pod的請求轉發路由表,從而實現Service的智能負載均衡機制。

(3)Kube-schedule通過Label,並且在Pod定義文件中使用NodeSelector這種標簽調度策略,實現Pod定向調度的特性。

Replication Controller

RC定義了一個期望的場景,聲明某個Pod的數量在任意時刻都符合某個預期值,RC的定義包括如下幾個部分:

(1)Pod期待的副本數

(2)用於篩選目標Pod的Label Selector

(3)當Pod的副本數量小於預期數量時,用創建新Pod的Pod模板創建足夠的Pod

例如:希望一個redis保持3個實例

apiVersion: v1
kind: ReplicationController
metadata:
  name: redis
  labels:
    name: redis
spec:
  replicas: 3
  selector:
    name: redis
  template:
    metadata: 
      name: redis
      labels:
        name: redis
    spec:
      containers:
      - name: redis
        image: redis
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 6379

  

Master會根據RC定期巡檢系統中存活的目標Pod,並確保目標Pod實例數量剛好等於RC的期望值。

可通過如下命令動態修改RC中的副本值,可使用此命令進行集群的擴容和縮容。

kubectl scale rc rc-name --replicas=4

  

特性和作用:

(1)通過定義RC實現Pod的創建過程及副本數量的自動控制。

(2)RC里包括完成的Pod定義模板

(3)RC通過Label Selector機制實現對Pod副本的自動控制。

(4)通過改變RC中的Pod副本數量,可以實現對Pod的擴容或縮容功能。

(5)通過改變RC中的鏡像版本,實現Pod的滾動升級功能。

Deployment

常見Pod控制器如下:

控制器名稱作用Deployment聲明式更新控制器,用於發布無狀態應用ReplicaSet副本集控制器,用於對Pod進行副本規模的擴大或者裁剪StatefulSet有狀態副本集,用於發布有狀態應用DaemonSet

在K8s集群每一個Node上運行一個副本,

用於發布監控和日志收集類等應用

Job運行一次性作業任務CronJob運行周期性作業任務

Deploymen內部使用Replica Set實現,Replica Set是下一代的RC,支持使用基於集合的Label Selector,這也是與Replication Controller唯一的區別。

使用場景:

(1)創建一個Deplayment來生成對應的Replica Set並完成副本的創建過程

(2)檢查Deplayment的狀態來看部署動作是否完成

(3)更新Deplayment來創建新的Pod

(4)如果當前Deplayment不穩定,則回滾到一個早前的版本。

(5)掛起或恢復一個Deplayment。

(6)擴展Deployment以應對高負載。

(7)清理不再需要的舊版本ReplicaSets。

Deployment的聲明的api是extensions/v1betal,其他的使用與RC並無區別

apiVersion: extensions/v1betas

StatefulSet

有很多服務是有狀態的,特別是一些中間件集群,例如MySQL集群、MongoDB集群、Akka集 群、ZooKeeper集群等,這些應用集群都有以下幾個共同點,

(1)每個節點都有固定的身份ID,通過這個ID,集群中的成員可 以相互發現並通信。

(2)集群的規模是比較固定的,集群規模不能隨意變動。

(3)集群中的每個節點都是有狀態的,通常會持久化數據到永久 存儲中。

(4)如果磁盤損壞,則集群里的某個節點無法正常運行,集群功 能受損

如果使用RC或Deployment的話,就會發現第一點無法滿足,因為其的Pod名稱都是隨機生成的,並且不固定,重啟之后又是另外一個名、IP等。

StatefulSet可以解決上述問題:

(1)StatefulSet里的每個Pod都有穩定、唯一的網絡標識,可以用來 發現集群內的其他成員。假設StatefulSet的名稱為kafka,那么第1個Pod 叫kafka-0,第2個叫kafka-1,以此類推。

(2) StatefulSet控制的Pod副本的啟停順序是受控的,操作第n個Pod 時,前n-1個Pod已經是運行且准備好的狀態。

(3) StatefulSet里的Pod采用穩定的持久化存儲卷,通過PV或PVC來 實現,刪除Pod時默認不會刪除與StatefulSet相關的存儲卷(為了保證數 據的安全)。


StatefulSet除了要與PV卷捆綁使用以存儲Pod的狀態數據,還要與 Headless Service配合使用,即在每個StatefulSet定義中都要聲明它屬於 哪個Headless Service。Headless Service與普通Service的關鍵區別在於, 它沒有Cluster IP,如果解析Headless Service的DNS域名,則返回的是該 Service對應的全部Pod的Endpoint列表。StatefulSet在Headless Service的 基礎上又為StatefulSet控制的每個Pod實例都創建了一個DNS域名,這個 域名的格式為:

${podname}.${handless service name}

比如一個3節點的Kafka的StatefulSet集群對應的Headless Service的名 稱為kafka,StatefulSet的名稱為kafka,則StatefulSet里的3個Pod的DNS 名稱分別為kafka-0.kafka、kafka-1.kafka、kafka-3.kafka。

Job

Job與其他Pod控制器不同的是,Job控制的容器僅運行一次,當所有Pod副本結束,Job也就運行結束了,Job生成的副本不能自動重啟,對應Pod的Restart Policy設置為Never。

同時,k8s提供了CronJob,解決某些任務需要定時反復執行的問題。

Horizontal Pod Autoscaler

Pod橫向自動擴容,通過追蹤分析RC控制的所有目標Pod的負載變化情況,來確定是否需要針對性的調整目標Pod的副本數。

HPA可以有兩種方式作為Pod負載的度量指標:

(1)CPUUtilizationPercentage

算術平均值,目標Pod所有副本自身的CPU利用率的一分鍾內的平均值,是當前cpu使用量除於Requests值,如果超過自定義比例,例如80%,則需要動態擴容

例如:聲明一個HPA對name為test的Deployment在cpu利用率達到90%進行擴容,最多為10個

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: test
  namespace: default
spec:
  maxReplicas: 10
  minReplicas: 1
  scaleTargetRef:
    kind: Deployment
    name: test
  targetCPUUtilizationPercentage: 90

  

也可以通過如下命令創建HPA

kubectl autoscale deployment app-name --cpu-percent=90 --min=1 --max=1

  

(2)應用程序自定義的度量指標,例如TPS或QPS(每秒內的請求數)

Service

K8s中的Service定義了一個服務的訪問入口地址,前端應用可以通過這個入口地址訪問其背后一組由Pod副本組成的集群實例,Service與其后端的Pod副本集群之間是通過Label Selector來實現連接的。

 

運行在每個Node節點上的kube-proxy進程其實就是一個智能的負載均衡器,負責把對Service的請求轉發到后端的Pod上,並在內部實現負載均衡和會話保持機制,每個Service都被分配了一個全局唯一的虛擬IP,成為Cluster-IP,在Service生命周期中,Cluster IP不會改變,但是Pod實例重啟之后ip就會變,所以Service的Cluster IP就可以解決此問題。

通過如下命令可以查看service的詳細信息

kubelet get svc service-name -o yaml

  

例如:

 

在spec.port中,targetPort表示容器所暴露的端口,port是Service提供的虛端口,如果未指定targetPort,則默認targetPort與port一致。

Service提供支持多個Endpoint,在此情況下,每個Endpoint需定義一個名字區分,例如:

apiVersion: v1
kind: Service
metadata:
  name: tomcat-test
spec:
  selector:
    name: tomcat-test
  ports:
  - port: 8080
    name: service-port1
  - port: 8081
    name: service-port2

  

(1)k8s的服務發現機制

K8S中的Service都有一個唯一的Cluster IP和唯一的名字,通過Add-On增值包的方式引入DNS系統,把服務名作為域名,程序就可以直接使用服務名來建立通信連接了。

(2)外部系統訪問Service

三種IP:

1、Node IP:Node節點的IP

節點物理網卡的IP地址,真實存在的物理網絡,K8s集群之外的節點訪問集群,必須通過Node IP進行通信。

2、Pod IP:Pod的IP

是Docker Engine根據docker0的網橋的IP地址段進行分配的,虛擬的二層網絡,

3、Cluster IP:Service的IP

僅僅作用於Service這個對象,由K8S管理和分配IP地址。無法被PING。只能結合Service Port組成一個具體的通信端口,單獨的Cluster IP不具備TCP/IP通信的基礎。

如果需要集群外的節點訪問集群,解決方案就是使用NodePort,例如:

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  type: NodePort
  selector:
    name: tomcat
  ports:
  - port: 8080
    nodePort: 30001

  

上例中將spec.type指定為NodePort,然后在ports中指定nodePort,也就是宿主機的端口號。

如果不指定NodePort,K8S會自動分配一個可用端口。

NodePort的實現方式是在K8S集群中的每個Node上為需要外部訪問的Service開啟一個對應的TCP監聽端口,外部系統只需要任意一個Node的IP地址+具體NodePort的端口即可訪問服務。

Volume

Volume是Pod中能夠被多個容器訪問的共享目錄,k8s的Volume定義在Pod上,然后被Pod的多個容器掛載到具體的文件目錄下;與Pod的生命周期相同,與容器的生命周期無關,當容器終止或重啟時,Volume中的數據也不會丟失,支持多種類型的Volume,例如G`lusterFS等文件系統。

使用:

先在Pod上聲明一個Volume,然后在容器中引用該Volume並Mount到容器中的某個目錄上,例如:增加一個名為datavol的Volume,並Mount到容器的/mydata-data目錄上。

spec:
  volumes:
  - name: datavol
    emptyDir: {}
  containers:
  - name: test-volume
    image: tomcat
    volumeMounts:
    - mountPath: /mydata-data
      name: datavol 

  

k8s提供了豐富的volume類型:

(1)emptyDir

在Pod分配到Node時創建的,初始內容為空,無需指定宿主機上對應的目錄文件,K8S自動分配,當Pod從Node上移除時,emptyDir中的數據也會被永久刪除。

用途:

1、臨時空間

2、長時間任務的中間過程CheckPoint的臨時保存目錄

3、一個容器需要從另一個容器中獲取數據的目錄(多容器共享目錄)

volumes:
- name: emptyDir
  emptyDir: {}

  

(2)hostPath

在Pod上掛載宿主機上的文件或目錄,可用於以下幾個方面:

1、容器生成的日志需要永久保存時

2、需要訪問宿主機上的Docker引擎內部數據結構的容器應用時,可以通過定義hostPath為宿主機/var/lib/docker目錄,使容器內部應用可以直接訪問Docker的文件系統。

需注意:

1、在不同的Node上具有相同配置的Pod可能會因為宿主機上的目錄和文件不同而導致對Volume上目錄和文件的訪問結果不一致。

2、如果使用了資源配額管理,則K8s無法將hostPath在宿主機上使用的資源納入管理。

volumes:
- name: hostpath
  hostpath:
    path: "/path"

  

(3)gcePersistentDisk

使用谷歌公有雲提供的永久磁盤(Persistent Disk,PD)存放Volume的數據,PD上的內容會永久保存,當Pod被刪除時,PD只是被卸載(Unmount),不會被刪除,需要先創建一個永久磁盤(PD),才能使用gcePersistentDisk。

限制條件:

Node需要GCE虛擬機

這些虛擬機需要與PD存在與相同的GCE項目和zone中。

通過gcloud命令可創建一個PD

gcloud compute disks create --size=500GB --zone=us-centrall-a my-data-disk
volumes:
- name: gcePersistentDiskTest
  gcePersistentDisk:
    pdName: my-data-disk
    fsType: ext4

  

(4)awsElasticBlockStore

使用亞馬遜公有雲提供的EBS Volume存儲數據,需要先創建一個EBS Volume才能使用

限制條件:

Node節點需要AWS EC2實例

AWS EC2實例需要與EBS Volume存在於相同的region和availability-zone中

EBS只支持單個EC2實例mount一個Volume

volumes:
- name: awsElasticBlockStoreTest
  awsElasticBlockStore:
    volumeId: aws://<availability-zone>/<volume-id>
    fsType: ext4

  

(5)NFS

使用NFS網絡文件系統提供的共享目錄存儲數據時,需在系統中部署一個NFS Server

volumes:
- name: nfs
  nfs:
    server: nfs服務器地址
    path: "/"

  

Persistent Volume

Persistent Volume(PV)和與之關聯的Persistent Volume Claim(PVC)是一塊網絡存儲,掛接到虛機上的‘網盤’。網絡存儲是相對獨立於計算資源而存在的一種實體資源。

PV是K8s集群中某個網絡存儲中對應的的一塊存儲,與Volume相似,但有以下區別:

(1)PV只能是網絡存儲,不屬於任何Node,但可以在任何Node上訪問。

(2)PV並不是定義在Pod上的,而是獨立於Pod之外定義的。

(3)PV目前只有幾種類型:GCE Persistent Disks、NFS、RBD、iSCSCI、AWS ElasticBlockStore、GlusterFS

例如:定義一個NFS類型的PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pvtest
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    server: nfs地址
    path: /path

  

重點是PV的accessModes屬性,目前有以下幾種類型:

(1)ReadWriteOnce:讀寫權限,並且只能被單個Node掛載

(2)ReadOnlyMany:只讀權限,允許被多個Node掛載

(3)ReadWriteMany:讀寫權限,允許被多個Node掛載


如果某個Pod想申請某種條件的PV,則首先需要定義一個Persistent Volume Claim(PVC)對象

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi

  

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

volumes:
- name: pvtest
  persistentVolumeClaim:
    claimName: myclaim

  

PV有以下幾種狀態:

(1)Available:空閑狀態

(2)Bound:已經綁定到某個PVC上

(3)Released:對應的PVC已經刪除,但資源還沒有被集群回收

(4)Failed:PV自動回收失敗。

Namespace

用於實現多租戶的資源隔離,通過將集群內部的資源對象“分配”到不同的Namespace中,形成邏輯上分組的不同項目、小組或用戶組,便於不同的分組在共享使用整個集群的資源的同時還能被分別管理。

K8S集群啟動之后,會創建一個名為default的Namespace,可以通過如下命令查看

kubectl get namespace
或
kubectl get ns

  

如果在資源定義的時候不指定Namespace,則用戶創建的Pod、Service、RC都將會創建到default的Namespace中。

 

Namespace的定義:

apiVersion: v1
kind: Namespace
metadata:
  name: my-ns

  

將Pod定義在這個Namespace中

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  namespace: my-ns
  labels:
    name: my-pod
spec:
 containers:
 - name: my-pod
   image: imageName
   imagePullPolicy: IfNotPresent
   ports:
   - containerPort: 8080

  

使用kubectl get pods是只能看到default命名空間的Pod,如果需要看到其他Namespace的資源,需要指定Namespace。

 kubectl get pods --namespace=my-ns
 或者
 kubectl get pods -n my-ns

  

當給不同租戶創建一個Namespace實現多租戶的資源隔離時,能結合k8s的資源配額管理,限定不同租戶能占用的資源,例如CPU使用量,內存使用量等。

Annotation

使用key/value鍵值對的形式進行定義,與Label類似,不同的是Label具有嚴格的命名規則,定義的是資源對象的元數據,並用於Label Selector,而Annotation則是任意定義的附加信息,以便於外部工具進行查找,K8s會通過此方式標記資源對象的一些特殊信息。

用Annotation來記錄的信息如下:

(1)build信息,release信息,Docker鏡像信息等,例如時間戳、release id號、鏡像hash值、docker registry地址等

(2)日志庫、監控庫、分析庫等資源庫的信息

(3)程序調試工具信息,例如工具名稱、版本號等

(4)團隊的聯系信息、例如電話號碼、負責人信息等。

ConfigMap

Docker容器提供了兩種方式在運行期間修改配置文件中的參數。

(1)在運行時通過容器的環境變量來傳遞參數;

(2)通過Docker Volume將容器外的配置文件映射到容器內。

大多數情況下使用的是第二種方式,但這種方式需要先在宿主機下創建配置文件進行映射,在分布式情況下,修改多台服務器的某個配置文件,都是比較麻煩的。

所以,ConfigMap就出現了,所有的配置項都是kv類型的,v也可以是某個文件的路徑,例如username=abc,這些配置項可以作為Map中的一個項,整個Map的數據可以被持久化存儲在 Kubernetes的Etcd數據庫中,然后提供API以方便Kubernetes相關組件或 客戶應用CRUD操作這些數據。

k8s提供了一種機制,將存儲在etcd中的 ConfigMap通過Volume映射的方式變成目標Pod內的配置文件,不管目標Pod被調度到哪台服務器上,都會完成自動映射。進一步地,如果 ConfigMap中的key-value數據被修改,則映射到Pod中的“配置文件”也會 隨之自動更新。

 


===============================

我是Liusy,一個喜歡健身的程序員。

歡迎關注微信公眾號【Liusy01】,一起交流Java技術及健身,獲取更多干貨,領取Java進階干貨,領取最新大廠面試資料,一起成為Java大神。

來都來了,關注一波再溜唄。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM