溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

初識Kubernetes(K8s):各種資源對象的理解和定義

發(fā)布時間:2020-06-13 21:00:30 來源:網(wǎng)絡(luò) 閱讀:5376 作者:xuad88 欄目:云計(jì)算

一、Pod

Kubernetes為每個Pod都分配了唯一的IP地址,稱之為Pod IP,一個Pod里的多個容器共享Pod IP地址。Kubernetes要求底層網(wǎng)絡(luò)支持集群內(nèi)任意兩個Pod之間的TCP/IP直接通信,這通常采用虛擬二層網(wǎng)絡(luò)技術(shù)來實(shí)現(xiàn),例如Flannel、Open vSwitch等。因此,在Kubernetes里,一個Pod里的容器與另外主機(jī)上的Pod容器能夠直接通信。
Pod有兩種類型:普通的Pod和靜態(tài)Pod(Static Pod),靜態(tài)Pod不存放在etcd存儲里,而是存放在某個具體的Node上的一個具體文件中,并且只在此Node上啟動運(yùn)行。普通的Pod一旦被創(chuàng)建,就會被存儲到etcd中,隨后會被Kubernetes Master調(diào)度到某個具體的Node上并進(jìn)行綁定(Binding),該Node上的kubelet進(jìn)程會將其實(shí)例化成一組相關(guān)的Docker容器并啟動起來。當(dāng)Pod里的某個容器停止時,Kubernetes會自動檢測到這個問題并且重新啟動這個Pod(重啟Pod里的所有容器);如果Pod所在的Node宕機(jī),則會將這個Node上的所有Pod重新調(diào)度到其他節(jié)點(diǎn)上運(yùn)行。
Pod、容器與Node的關(guān)系如下圖:
初識Kubernetes(K8s):各種資源對象的理解和定義
Kubernetes里的所有資源對象都可以采用yaml或者JSON格式的文件來定義或描述,下面是一個簡單的Pod資源定義文件:

apiVersion: v1
kind: Pod
metadata:
  name: myweb
  labels:
    name: myweb
spec:
  containers:
  - name: myweb
    image: kubeguide/tomcat-app: v1
    ports:
    - containerPort: 8080
    env:
    - name: MYSQL_SERVICE_HOST
      value: 'mysql'
    - name: MYSQL_SERVICE_PORT
      value: '3306'

kind為pod表明這是一個Pod的定義,metadata里的name屬性為Pod的名字,metadata里還能定義資源對象的標(biāo)簽(Label),這里聲明myweb擁有一個name=myweb的標(biāo)簽(Label)。Pod里包含的容器組的定義則在spec一節(jié)中聲明,這里定義了一個名字為myweb,對應(yīng)鏡像為kubeguide/tomcat-app: v1的容器,該容器注入了名為MYSQL_SERVICE_HOST='mysql'和MYSQL_SERVICE_PORT='3306'的環(huán)境變量(env關(guān)鍵字),并且在8080端口(containerPort)上啟動容器進(jìn)程。Pod的IP加上這里的容器端口,就組成了一個新的概念——Endpoint,它代表著此Pod里的一個服務(wù)進(jìn)程的對外通信地址。一個Pod也存在著具有多個Endpoint的情況,比如我們把Tomcat定義為一個Pod時,可以對外暴露管理端口與服務(wù)端口這兩個Endpoint。
Docker里的Volume在Kubernetes里也有對應(yīng)的概念——Pod Volume,Pod Volume有一些擴(kuò)展,比如可以用分布式文件系統(tǒng)GlusterFS等實(shí)現(xiàn)后端存儲功能;Pod Volume是定義在Pod之上,然后被各個容器掛載到自己的文件系統(tǒng)中的。對于Pod Volume的定義我們后面會講到。
這里順便提一下Event概念,Event是一個事件的記錄,記錄了事件的最早產(chǎn)生時間、最后重現(xiàn)時間、重復(fù)次數(shù)、發(fā)起者、類型,以及導(dǎo)致此事件的原因等眾多信息。Event通常會關(guān)聯(lián)到某個具體的資源對象上,是排查故障的重要參考信息,當(dāng)我們發(fā)現(xiàn)某個Pod遲遲無法創(chuàng)建時,可以用kubectl describe pod xxx來查看它的描述信息,用來定位問題的原因。
每個Pod都可以對其能使用的服務(wù)器上的計(jì)算資源設(shè)置限額,當(dāng)前可以設(shè)置限額的計(jì)算資源有CPU和Memory兩種,其中CPU的資源單位為CPU(Core)的數(shù)量,是一個絕對值。
對于容器來說一個CPU的配額已經(jīng)是相當(dāng)大的資源配額了,所以在Kubernetes里,通常以千分之一的CPU配額為最小單位,用m來表示。通常一個容器的CPU配額被定義為100-300m,即占用0.1-0.3個CPU。與CPU配額類似,Memory配額也是一個絕對值,它的單位是內(nèi)存字節(jié)數(shù)。
對計(jì)算資源進(jìn)行配額限定需要設(shè)定以下兩個參數(shù):

  • Requests:該資源的最小申請量,系統(tǒng)必須滿足要求。
  • Limits:該資源最大允許使用的量,不能超過這個使用限制,當(dāng)容器試圖使用超過這個量的資源時,可能會被Kubernetes Kill并重啟。

通常我們應(yīng)該把Requests設(shè)置為一個比較小的數(shù)值,滿足容器平時的工作負(fù)載情況下的資源需求,而把Limits設(shè)置為峰值負(fù)載情況下資源占用的最大量。下面是一個資源配額的簡單定義:

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

最小0.25個CPU及64MB內(nèi)存,最大0.5個CPU及128MB內(nèi)存。

二、Label(標(biāo)簽)

Label相當(dāng)于我們熟悉的“標(biāo)簽”,給某個資源對象定義一個Label,就相當(dāng)于給它打了一個標(biāo)簽,隨后可以通過Label Selector(標(biāo)簽選擇器)查詢和篩選擁有某些Label的資源對象,Kubernetes通過這種方式實(shí)現(xiàn)了類似SQL的簡單又通用的對象查詢機(jī)制。
Label Selector相當(dāng)于SQL語句中的where查詢條件,例如,name=redis-slave這個Label Selector作用于Pod時,相當(dāng)于select * from pod where pod’s name = ‘redis-slave’這樣的語句。Label Selector的表達(dá)式有兩種:基于等式的(Equality-based)和基于集合的(Set-based)。下面是基于等式的匹配例子。
name=redis-slave:匹配所有標(biāo)簽為name=redis-slave的資源對象。
env != production:匹配所有標(biāo)簽env不等于production的資源對象。
下面是基于集合的匹配例子

  • name in (redis-master, redis-slave):匹配所有標(biāo)簽為name=redis-master或者name=redis-slave的資源對象。
  • name not in (php-frontend):匹配所有標(biāo)簽name不等于php-frontend的資源對象。

還可以通過多個Label Selector表達(dá)式的組合實(shí)現(xiàn)復(fù)雜的條件選擇,多個表達(dá)式之間用“,”進(jìn)行分隔即可,幾個條件之間是“AND”的關(guān)系,即同時滿足多個條件,例如:

name=redis-slave, env!=production
name not in (php-frontend), env!=production

以Pod為例,Label定義在metadata中:

apiVersion: v1
kind: Pod
metadata:
  name: myweb
  labels:
    app: myweb

RC和Service在spec中定義Selector與Pod進(jìn)行關(guān)聯(lián):

apiVersion: v1
kind: ReplicationController
metadata:
  name: myweb
spec:
  replicas: 1
  selector:
    app: myweb
  template:
  …………

Deployment、ReplicaSet、DaemonSet和Job則可以在Selector中使用基于集合的篩選條件:

selector:
  matchLabels:
    app: myweb
  matchExpressions:
    - {key: tier, operator: In, values: [frontend]}
    - {key: environment, operator: NotIn, values: [dev]}

matchLabels用于定義一組Label,與直接寫在Selector中作用相同;matchExpressions用于定義一組基于集合的篩選條件,可用的條件運(yùn)算符包括:In、NotIn、Exists和DoesNotExist。
如果同時設(shè)置了matchLabels和matchExpressions,則兩組條件為“AND”關(guān)系,即所有條件需要同時滿足才能完成Selector的篩選。
Label Selector在Kubernetes中的重要使用場景如下:

  • Kube-controller進(jìn)程通過資源對象RC上定義的Label Selector來篩選要監(jiān)控的Pod副本的數(shù)量,從而實(shí)現(xiàn)Pod副本的數(shù)量始終符合預(yù)期設(shè)定的全自動控制流程。
  • Kube-proxy進(jìn)程通過Service的Label Selector來選擇對應(yīng)的Pod,自動建立起每個Service到對應(yīng)Pod的請求轉(zhuǎn)發(fā)路由表,從而實(shí)現(xiàn)Service的智能負(fù)載均衡機(jī)制。
  • 通過對某些Node定義特定的Label,并且在Pod定義文件中使用NodeSelector這種標(biāo)簽調(diào)度策略,kube-scheduler進(jìn)程可以實(shí)現(xiàn)Pod“定向調(diào)度”的特性。

下面舉個復(fù)雜點(diǎn)的例子,假設(shè)我們?yōu)镻od定義了3個Label:release、env和role,不同的Pod定義了不同的Label。如下圖所示,如果我們設(shè)置了“role=frontend”的Label Selector,則會選取到Node 1和Node 2上的Pod。
初識Kubernetes(K8s):各種資源對象的理解和定義
如果我們設(shè)置“release=beta”的Label Selector,則會選取到Node 2和Node 3上的Pod,如下圖所示。
初識Kubernetes(K8s):各種資源對象的理解和定義
總結(jié):使用Label可以給對象創(chuàng)建多組標(biāo)簽,Label和Label Selector共同構(gòu)成了Kubernetes系統(tǒng)中最核心的應(yīng)用模型,使得被管理對象能夠被精細(xì)地分組管理,同時實(shí)現(xiàn)了整個集群的高可用性。

三、Replication Controller

RC的作用是聲明Pod的副本數(shù)量在任意時刻都符合某個預(yù)期值,所以RC的定義包括如下幾個部分。

  • Pod期待的副本數(shù)量(replicas)。
  • 用于篩選目標(biāo)Pod的Label Selector。
  • 當(dāng)Pod的副本數(shù)量小于預(yù)期數(shù)量時,用于創(chuàng)建新Pod的Pod模板(template)。

下面是一個完整的RC定義的例子,即確保擁有tier=frontend標(biāo)簽的這個Pod(運(yùn)行Tomcat容器)在整個Kubernetes集群中始終有三個副本:

apiVersion: v1
kind: ReplicationController
metadata:
  name: frontend
spec:
  replicas: 3
  selector:
    tier: frontend
  template:
    metadata:
      labels:
        app: app-demo
        tier: frontend
    spec:
      containers:
      - name: tomcat-demo
        image: tomcat
        imagePullPolicy: IfNotPresent
        env:
        - name: GET_HOSTS_FROM
          value: dns
        ports:
        - containerPort: 80

當(dāng)我們定義了一個RC并提交到Kubernetes集群中后,Master節(jié)點(diǎn)上的Controller Manager組件就得到通知,定期巡檢系統(tǒng)中當(dāng)前存活的目標(biāo)Pod,并確保目標(biāo)Pod實(shí)例的數(shù)量剛好等于此RC的期望值。如果有過多的Pod副本在運(yùn)行,系統(tǒng)就會停掉多余的Pod;如果運(yùn)行的Pod副本少于期望值,即如果某個Pod掛掉,系統(tǒng)就會自動創(chuàng)建新的Pod以保證數(shù)量等于期望值。
通過RC,Kubernetes實(shí)現(xiàn)了用戶應(yīng)用集群的高可用性,并且大大減少了運(yùn)維人員在傳統(tǒng)IT環(huán)境中需要完成的許多手工運(yùn)維工作(如主機(jī)監(jiān)控腳本、應(yīng)用監(jiān)控腳本、故障恢復(fù)腳本等)。
下面我們來看下Kubernetes如何通過RC來實(shí)現(xiàn)Pod副本數(shù)量自動控制的機(jī)制,假如我們有3個Node節(jié)點(diǎn),在RC里定義了redis-slave這個Pod需要保持兩個副本,系統(tǒng)將會在其中的兩個Node上創(chuàng)建副本,如下圖所示。
初識Kubernetes(K8s):各種資源對象的理解和定義
假如Node2上的Pod2意外終止,根據(jù)RC定義的replicas數(shù)量2,Kubernetes將會自動創(chuàng)建并啟動一個新的Pod,以保證整個集群中始終有兩個redis-slave Pod在運(yùn)行。
系統(tǒng)可能選擇Node1或者Node3來創(chuàng)建一個新的Pod,如下圖。
初識Kubernetes(K8s):各種資源對象的理解和定義
通過修改RC的副本數(shù)量,可以實(shí)現(xiàn)Pod的動態(tài)縮放(Scaling)功能。
kubectl scale rc redis-slave --replicas=3
此時Kubernetes會在3個Node中選取一個Node創(chuàng)建并運(yùn)行一個新的Pod3,使redis-slave Pod副本數(shù)量始終保持3個。

四、Replica Set

由于Replication Controller與Kubernetes代碼中的模塊Replication Controller同名,同時這個詞也無法準(zhǔn)確表達(dá)它的意思,所以從Kubernetes v1.2開始,它就升級成了另外一個新的對象——Replica Set,官方解釋為“下一代的RC”。它與RC當(dāng)前存在的唯一區(qū)別是:Replica Set支持基于集合的Label selector(Set-based selector),而RC只支持基于等式的Label selector(equality-based selector),所以Replica Set的功能更強(qiáng)大。下面是Replica Set的定義例子(省去了Pod模板部分的內(nèi)容):

apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
  name: frontend
spec:
  selector:
    matchLabels:
      tier: frontend
    matchExpressions:
      - {key: tier, operator: In, values: [frontend]}
  template:
  …………

Replica Set很少單獨(dú)使用,它主要被Deployment這個更高層的資源對象所使用,從而形成一整套Pod創(chuàng)建、刪除、更新的編排機(jī)制。
RC和RS的特性與作用如下:

  • 在大多情況下,我們通過定義一個RC實(shí)現(xiàn)Pod的創(chuàng)建過程及副本數(shù)量的自動控制。
  • RC里包括完整的Pod定義模板。
  • RC通過Label Selector機(jī)制實(shí)現(xiàn)對Pod副本的自動控制。
  • 通過改變RC里的Pod副本數(shù)量,可以實(shí)現(xiàn)Pod的擴(kuò)容或縮容功能。
  • 通過改變RC里Pod模板中的鏡像版本,可以實(shí)現(xiàn)Pod的滾動升級功能。

五、Deployment

Deployment相對于RC的最大區(qū)別是我們可以隨時知道當(dāng)前Pod“部署”的進(jìn)度。一個Pod的創(chuàng)建、調(diào)度、綁定節(jié)點(diǎn)及在目標(biāo)Node上啟動對應(yīng)的容器這一完整過程需要一定的時間,所以我們期待系統(tǒng)啟動N個Pod副本的目標(biāo)狀態(tài),實(shí)際上是一個連續(xù)變化的“部署過程”導(dǎo)致的最終狀態(tài)。
Deployment的典型使用場景有以下幾個:

  • 創(chuàng)建一個Deployment對象來生成對應(yīng)的Replica Set并完成Pod副本的創(chuàng)建過程。
  • 檢查Deployment的狀態(tài)來看部署動作是否完成(Pod副本的數(shù)量是否達(dá)到預(yù)期的值)。
  • 更新Deployment以創(chuàng)建新的Pod(比如鏡像升級)。
  • 如果當(dāng)前Deployment不穩(wěn)定,則回滾到一個早先的Deployment版本。
  • 暫停Deployment以便于一次性修改多個Pod Template Spec的配置項(xiàng),之后再恢復(fù)Deployment,進(jìn)行新的發(fā)布。
  • 擴(kuò)展Deployment以應(yīng)對高負(fù)載。
  • 查看Deployment的狀態(tài),以此作為發(fā)布是否成功的指標(biāo)。
  • 清理不再需要的舊版本ReplicaSet。

Deployment的定義與Replica Set的定義類似,只是API聲明與Kind類型不同。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
apiVersion: v1
kind: ReplicaSet
metadata:
  name: nginx-repset

下面是Deployment定義的一個完整例子:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      tier: frontend
    matchExpressions:
      - {key: tier, operator: In, values: [frontend]}
  template:
    metadata:
      labels:
        app: app-demo
        tier: frontend
    spec:
      containers:
      - name: tomcat-demo
        image: tomcat
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080

可以通過命令kubectl get deployment來查看Deployment的信息,其中的幾個參數(shù)解釋如下:

  • DESIRED::Pod副本數(shù)量的期望值,即Deployment里定義的Replica。
  • CURRENT:當(dāng)前Replica的值,如果小于DESIRED的期望值,會創(chuàng)建新的Pod,直到達(dá)成DESIRED為止。
  • UP-TO-DATE:最新版本的Pod的副本數(shù)量,用于指示在滾動升級的過程中,有多少個Pod副本已經(jīng)成功升級。
  • AVAILABLE:當(dāng)前集群中可用的Pod副本數(shù)量,即集群中當(dāng)前存活的Pod數(shù)量。

Pod的管理對象,除了RC、ReplicaSet、Deployment,還有DaemonSet、StatefulSet、Job等,分別用于不同的應(yīng)用場景。

六、Horizontal Pod Autoscaler

HPA與RC、Deployment一樣,也屬于Kubernetes資源對象。通過追蹤分析RC或RS控制的所有目標(biāo)Pod的負(fù)載變化情況,來確定是否需要針對性地調(diào)整目標(biāo)Pod的副本數(shù)。
HPA有以下兩種方式作為Pod負(fù)載的度量指標(biāo):

  • CPUUtilizationPercentage
  • 應(yīng)用程序自定義的度量指標(biāo),比如服務(wù)在每秒內(nèi)的相應(yīng)的請求數(shù)(TPS或QPS)。

CPUUtilizationPercentage是一個算術(shù)平均值,即目標(biāo)Pod所有副本自帶的CPU利用率的平均值。一個Pod自身的CPU利用率是該P(yáng)od當(dāng)前CPU的使用量除以它的Pod Request的值,比如我們定義一個Pod的Pod Request為0.4,而當(dāng)前Pod的CPU使用量為0.2,則它的CPU使用率為50%,這樣我們就可以算出來一個RC或RS控制的所有Pod副本的CPU利用率的算術(shù)平均值了。如果某一時刻CPUUtilizationPercentage的值超過80%,則意味著當(dāng)前的Pod副本數(shù)很可能不足以支撐接下來更多的請求,需要進(jìn)行動態(tài)擴(kuò)容,而當(dāng)請求高峰時段過去后,Pod的CPU利用率又會降下來,此時對應(yīng)的Pod副本數(shù)應(yīng)該自動減少到一個合理的水平。
下面是HPA定義的一個具體的例子:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  maxReplicas: 10
  minReplicas: 2
  scaleTargetRef:
    kind: Deployment
    name: php-apache
  targetCPUUtilizationPercentage: 90

通過HPA控制php-apache的Pod副本,當(dāng)Pod副本的CPUUtilizationPercentage的值超過90%時,會進(jìn)行自動擴(kuò)容增加Pod副本的數(shù)量,擴(kuò)容或縮容時Pod的副本數(shù)量要介于2-10之間。
除了通過yaml文件來定義HPA對象之外,還可以通過命令的方式創(chuàng)建:
kubectl autoscale deployment php-apache --cpu-percent=90 --min=1 --max=10

七、StatefulSet

Pod的管理對象RC、Deployment、DaemonSet和Job都是面向無狀態(tài)的服務(wù),但實(shí)際中有很多服務(wù)是有狀態(tài)的,比如Mysql集群、MongoDB集群、ZooKeeper集群等,可以使用StatefulSet來管理有狀態(tài)的服務(wù)。
StatefulSet有如下一些特性:

  • StatefulSet里的每個Pod都有穩(wěn)定、唯一的網(wǎng)絡(luò)標(biāo)識,可以用來發(fā)現(xiàn)集群內(nèi)的其他成員。假設(shè)StatefulSet的名字叫kafka,那么第1個Pod叫kafka-0,第2個叫kafka-1,以此類推。
  • StatefulSet控制的Pod副本的啟停順序是受控的,操作第n個Pod時,前n-1個Pod已經(jīng)是運(yùn)行且準(zhǔn)備好的狀態(tài)。
  • StatefulSet里的Pod采用穩(wěn)定的持久化存儲卷,通過PV/PVC來實(shí)現(xiàn),刪除Pod時默認(rèn)不會刪除與StatefulSet相關(guān)的存儲卷(為了保證數(shù)據(jù)的安全)。

StatefulSet除了要與PV卷捆綁使用以存儲Pod的狀態(tài)數(shù)據(jù),還要與Headless Service配合使用,即在每個StatefulSet的定義中要聲明它屬于哪個Headless Service。Headless Service與普通Service的區(qū)別在于,它沒有Cluster IP,如果解析Headless Service的DNS域名,則返回的是該Service對應(yīng)的全部Pod的Endpoint列表。StatefulSet在Headless Service的基礎(chǔ)上又為StatefulSet控制的每個Pod實(shí)例創(chuàng)建了一個DNS域名,這個域名的格式為:

$(podname).$(headless service name)

比如一個3節(jié)點(diǎn)的kafka的StatefulSet集群,對應(yīng)的Headless Service的名字為kafka,StatefulSet的名字為kafka,則StatefulSet里面的3個Pod的DNS名稱分別為kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,這些DNS名稱可以直接在集群的配置文件中固定下來。

八、Service(服務(wù))

1.概述
Service其實(shí)就是我們經(jīng)常提起的微服務(wù)架構(gòu)中的一個“微服務(wù)”,Pod、RC等資源對象其實(shí)都是為它作“嫁衣”的。Pod、RC或RS與Service的邏輯關(guān)系如下圖所示。
初識Kubernetes(K8s):各種資源對象的理解和定義
通過上圖我們看到,Kubernetes的Service定義了一個服務(wù)的訪問入口地址,前端的應(yīng)用(Pod)通過這個入口地址訪問其背后的一組由Pod副本組成的集群實(shí)例,Service與其后端Pod副本集群之間則是通過Label Selector來實(shí)現(xiàn)“無縫對接”的。而RC的作用實(shí)際上是保證Service的服務(wù)能力和服務(wù)質(zhì)量始終處于預(yù)期的標(biāo)準(zhǔn)。
通過分析、識別并建模系統(tǒng)中的所有服務(wù)為微服務(wù)——Kubernetes Service,最終我們的系統(tǒng)由多個提供不同業(yè)務(wù)能力而又彼此獨(dú)立的微服務(wù)單元所組成,服務(wù)之間通過TCP/IP進(jìn)行通信,從而形成了強(qiáng)大而又靈活的彈性集群,擁有了強(qiáng)大的分布式能力、彈性擴(kuò)展能力、容錯能力。因此,我們的系統(tǒng)架構(gòu)也變得簡單和直觀許多。
既然每個Pod都會被分配一個單獨(dú)的IP地址,而且每個Pod都提供了一個獨(dú)立的Endpoint(Pod IP+ContainerPort)以被客戶端訪問,多個Pod副本組成了一個集群來提供服務(wù),那么客戶端如何來訪問它們呢?一般的做法是部署一個負(fù)載均衡器(軟件或硬件),但這樣無疑增加了運(yùn)維的工作量。在Kubernetes集群里使用了Service(服務(wù)),它提供了一個虛擬的IP地址(Cluster IP)和端口號,Kubernetes集群里的任何服務(wù)都可以通過Cluster IP+端口的方式來訪問此服務(wù),至于訪問請求最后會被轉(zhuǎn)發(fā)到哪個Pod,則由運(yùn)行在每個Node上的kube-proxy負(fù)責(zé)。kube-proxy進(jìn)程其實(shí)就是一個智能的軟件負(fù)載均衡器,它負(fù)責(zé)把對Service的請求轉(zhuǎn)發(fā)到后端的某個Pod實(shí)例上,并在內(nèi)部實(shí)現(xiàn)服務(wù)的負(fù)載均衡與會話保持機(jī)制。
下面是一個Service的簡單定義:

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  ports:
  - port: 8080
  selector:
    tier: frontend

上述內(nèi)容定義了一個名為“tomcat-service”的Service,它的服務(wù)端口為8080,擁有“tier=frontend”這個Label的所有Pod實(shí)例。
很多服務(wù)都存在多個端口的問題,通常一個端口提供業(yè)務(wù)服務(wù),另外一個端口提供管理服務(wù),比如Mycat、Codis等常見中間件。Kubernetes Service支持多個Endpoint,要求每個Endpoint定義一個名字來區(qū)分,下面是tomcat多端口的Service定義樣例。

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
spec:
  ports:
  - port: 8080
    name: service-port
  - port: 8005
    name: shutdown-port
  selector:
    tier: frontend

多端口為什么需要給每個端口命名呢?這就涉及Kubernetes的服務(wù)發(fā)現(xiàn)機(jī)制了。
2.Kubernetes的服務(wù)發(fā)現(xiàn)機(jī)制
每個Kubernetes中的Service都有一個唯一的Cluster IP及唯一的名字,而名字是由我們自己定義的,那我們是否可以通過Service的名字來訪問呢?
最早時Kubernetes采用了Linux環(huán)境變量的方式來實(shí)現(xiàn),即每個Service生成一些對應(yīng)的Linux環(huán)境變量(ENV),并在每個Pod的容器啟動時,自動注入這些環(huán)境變量,以實(shí)現(xiàn)通過Service的名字來建立連接的目的。
考慮到通過環(huán)境變量獲取Service的IP與端口的方式仍然不方便、不直觀,后來Kubernetes通過Add-On增值包的方式引入了DNS系統(tǒng),把服務(wù)名作為DNS域名,這樣程序就可以直接使用服務(wù)名來建立連接了。
關(guān)于DNS的部署,后續(xù)博文我會單獨(dú)講解,有興趣的朋友可以關(guān)注我的博客。
3.外部系統(tǒng)訪問Service的問題
Kubernetes集群里有三種IP地址,分別如下:

  • Node IP:Node節(jié)點(diǎn)的IP地址,即物理網(wǎng)卡的IP地址。
  • Pod IP:Pod的IP地址,即docker容器的IP地址,此為虛擬IP地址。
  • Cluster IP:Service的IP地址,此為虛擬IP地址。

外部訪問Kubernetes集群里的某個節(jié)點(diǎn)或者服務(wù)時,必須要通過Node IP進(jìn)行通信。
Pod IP是Docker Engine根據(jù)docker0網(wǎng)橋的IP地址段進(jìn)行分配的一個虛擬二層網(wǎng)絡(luò)IP地址,Pod與Pod之間的訪問就是通過這個虛擬二層網(wǎng)絡(luò)進(jìn)行通信的,而真實(shí)的TCP/IP流量則是通過Node IP所在的物理網(wǎng)卡流出的。
Service的Cluster IP具有以下特點(diǎn):

  • Cluster IP僅僅作用于Service這個對象,并由Kubernetes管理和分配IP地址。
  • Cluster IP是一個虛擬地址,無法被ping。
  • Cluster IP只能結(jié)合Service Port組成一個具體的通信端口,供Kubernetes集群內(nèi)部訪問,單獨(dú)的Cluster IP不具備TCP/IP通信的基礎(chǔ),并且外部如果要訪問這個通信端口,需要做一些額外的工作。
  • Node IP、Pod IP和Cluster IP之間的通信,采用的是Kubernetes自己設(shè)計(jì)的一種特殊的路由規(guī)則,與我們熟悉的IP路由有很大的區(qū)別。

我們的應(yīng)用如果想讓外部訪問,最常用的作法是使用NodePort方式。

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

NodePort的實(shí)現(xiàn)方式是在Kubernetes集群里的每個Node上為需要外部訪問的Service開啟一個對應(yīng)的TCP監(jiān)聽端口,外部系統(tǒng)只要用任意一個Node的IP地址+具體的NodePort端口號即可訪問此服務(wù)。
NodePort還沒有完全解決外部訪問Service的所有問題,比如負(fù)載均衡問題,常用的做法是在Kubernetes集群之外部署一個負(fù)載均衡器。
初識Kubernetes(K8s):各種資源對象的理解和定義
Load balancer組件獨(dú)立于Kubernetes集群之外,可以是一個硬件負(fù)載均衡器,也可以是軟件方式實(shí)現(xiàn),例如HAProxy或者Nginx。這種方式,無疑是增加了運(yùn)維的工作量及出錯的概率。
于是Kubernetes提供了自動化的解決方案,如果我們使用谷歌的GCE公有云,那么只需要將type: NodePort改成type: LoadBalancer,此時Kubernetes會自動創(chuàng)建一個對應(yīng)的Load balancer實(shí)例并返回它的IP地址供外部客戶端使用。其他公有云提供商只要實(shí)現(xiàn)了支持此特性的驅(qū)動,則也可以達(dá)到上述目的。

九、Volume(存儲卷)

Volume是Pod中能夠被多個容器訪問的共享目錄。Volume定義在Pod上,被一個Pod里的多個容器掛載到具體的文件目錄下,當(dāng)容器終止或者重啟時,Volume中的數(shù)據(jù)也不會丟失。Kubernetes支持多種類型的Volume,例如GlusterFS、Ceph等分布式文件系統(tǒng)。
除了可以讓一個Pod里的多個容器共享文件、讓容器的數(shù)據(jù)寫到宿主機(jī)的磁盤上或者寫文件到網(wǎng)絡(luò)存儲中,Kubernetes還提供了容器配置文件集中化定義與管理,通過ConfigMap對象來實(shí)現(xiàn)。
Kubernetes支持多種Volume類型,下面我們一一進(jìn)行介紹。
1.emptyDir
emptyDir是在Pod分配到Node時創(chuàng)建的,它的初始內(nèi)容為空,并且無須指定宿主機(jī)上對應(yīng)的目錄文件,它是Kubernetes自動分配的一個目錄,當(dāng)Pod從Node上移除時,emptyDir中的數(shù)據(jù)也會被永久刪除。
emptyDir的用途如下:

  • 臨時空間,例如用于某些應(yīng)用程序運(yùn)行時所需的臨時目錄,且無須永久保存。
  • 長時間任務(wù)的中間過程CheckPoint的臨時保存目錄。
  • 一個容器需要從另一個容器中獲取數(shù)據(jù)的目錄(多容器共享目錄)。

emptyDir的定義如下:

template:
  metadata:
    labels:
      app: app-demo
      tier: frontend
  spec:
    volumes:
      - name: datavol
        emptyDir: {}
    containers:
    - name: tomcat-demo
      image: tomcat
      volumeMounts:
        - mountPath: /mydata-data
          name: datavol
      imagePullPolicy: IfNotPresent

2.hostPath
使用hostPath掛載宿主機(jī)上的文件或目錄,主要用于以下幾個方面:

  • 容器應(yīng)用程序生成的日志文件需要永久保存時,可以使用宿主機(jī)的文件系統(tǒng)存儲。
  • 需要訪問宿主機(jī)上Docker引擎內(nèi)部數(shù)據(jù)時,可以定義hostPath的宿主機(jī)目錄為docker的數(shù)據(jù)存儲目錄,使容器內(nèi)部應(yīng)用可以直接訪問docker的數(shù)據(jù)文件。

使用hostPath時,需要注意以下幾點(diǎn):

  • 在不同的Node上的Pod掛載的是本地宿主機(jī)的目錄,如果要想讓不同的Node掛載相同的目錄,則可以使用網(wǎng)絡(luò)存儲或分布式文件存儲。
  • 如果使用了資源配額管理,則Kubernetes無法將其在宿主機(jī)上使用的資源納入管理。

hostPath的定義如下:

volumes:
- name: "persistent-storage"
  hostPath:
    path: "/data"

3.gcePersistentDisk
使用這種類型的Volume表示使用谷歌公有云提供的永久磁盤(Persistent Disk,PD)存放數(shù)據(jù),使用gcePersistentDisk有以下一些限制條件:

  • Node需要是谷歌GCE云主機(jī)。
  • 這些云主機(jī)需要與PD存在于相同的GCE項(xiàng)目和Zone中。

通過gcloud命令創(chuàng)建一個PD:
gcloud compute disks create --size=500GB --zone=us-centrall-a my-data-disk
定義gcePersistentDisk類型的Volume的示例如下:

volumes:
- name: test-volume
  gcPersistentDisk:
    pdName: my-data-disk
    fsType: ext4

4.awsElasticBlockStore
與GCE類似,該類型的Volume使用亞馬遜公有云提供的EBS Volume存儲數(shù)據(jù),需要先創(chuàng)建一個EBS Volume才能使用awsElasticBlockStore。
使用awsElasticBlockStore的一些限制條件如下:

  • Node需要是AWS EC2實(shí)例。
  • 這些AWS EC2實(shí)例需要與EBS volume存在于相同的region和availability-zone中。
  • EBS只支持單個EC2實(shí)例mount一個volume。

通過aws ec2 create-volume命令創(chuàng)建一個EBS volume:
aws ec2 create-volume --availability-zone eu-west-la --size 10 --volume-type gp2
定義awsElasticBlockStore類型的Volume的示例如下:

volumes:
- name: test-volume
  awsElasticBlockStore:
    volumeID: aws://<availability-zone>/<volume-id>
    fsType: ext4

5.NFS
使用NFS網(wǎng)絡(luò)文件系統(tǒng)提供的共享目錄存儲數(shù)據(jù)時,我們需要在系統(tǒng)中部署一個NFS Server。
定義NFS類型的Volume的示例如下:

volumes:
- name: nfs-volume
  nfs:
    server: nfs-server.localhost
    path: "/"

6.其他類型的Volume

  • iscsi:使用iSCSI存儲設(shè)備上的目錄掛載到Pod中。
  • flocker:使用Flocker來管理存儲卷。
  • glusterfs:使用GlusterFS網(wǎng)絡(luò)文件系統(tǒng)的目錄掛載到Pod中。
  • rbd:使用Ceph塊設(shè)備共享存儲(Rados Block Device)掛載到Pod中。
  • gitRepo:通過掛載一個空目錄,并從GIT庫clone一個git repository以供Pod使用。
  • secret:一個secret volume用于為Pod提供加密的信息,可以將定義在Kubernetes中的secret直接掛載為文件讓Pod訪問。Secret volume是通過tmfs(內(nèi)存文件系統(tǒng))實(shí)現(xiàn)的,所以這種類型的volume不會持久化。

十、Persistent Volume

上面提到的Volume是定義在Pod上的,屬于“計(jì)算資源”的一部分,而實(shí)際上,“網(wǎng)絡(luò)存儲”是相對獨(dú)立于“計(jì)算資源”而存在的一種實(shí)體資源。比如在使用云主機(jī)的情況下,我們通常會先創(chuàng)建一個網(wǎng)絡(luò)存儲,然后從中劃出一個“網(wǎng)盤”并掛載到云主機(jī)上。Persistent Volume(簡稱PV)和與之相關(guān)聯(lián)的Persistent Volume Claim(簡稱PVC)實(shí)現(xiàn)了類似的功能。
PV與Volume的區(qū)別如下:

  • PV只能是網(wǎng)絡(luò)存儲,不屬于任何Node,但可以在每個Node上訪問。
  • PV并不是定義在Pod上的,而是獨(dú)立于Pod之外定義。

下面是NFS類型PV的yaml定義內(nèi)容,聲明了需要5G的存儲空間:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /somepath
    server: 172.17.0.2

PV的accessModes屬性有以下類型:

  • ReadWriteOnce:讀寫權(quán)限、并且只能被單個Node掛載。
  • ReadOnlyMany:只讀權(quán)限、允許被多個Node掛載。
  • ReadWriteMany:讀寫權(quán)限、允許被多個Node掛載。

如果Pod想申請使用PV資源,則首先需要定義一個PersistentVolumeClaim(PVC)對象:

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

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

volumes:
  - name: mypd
    persistentVolumeClaim:
      claimName: myclaim

PV是有狀態(tài)的對象,它有以下幾種狀態(tài):

  • Available:空閑狀態(tài)。
  • Bound:已經(jīng)綁定到某個PVC上。
  • Released:對應(yīng)的PVC已經(jīng)刪除,但資源還沒有被集群收回。
  • Failed:PV自動回收失敗。

十一、Namespace(命名空間)

通過將Kubernetes集群內(nèi)部的資源對象“分配”到不同的Namespace中,形成邏輯上分組的不同項(xiàng)目、小組或用戶組,便于不同的分組在共享使用整個集群的資源的同時還能被分別管理。
Kubernetes集群在啟動后,會創(chuàng)建一個名為“default”的Namespace,通過kubectl可以查看到:
kubectl get namespaces
如果不特別指明Namespace,則用戶創(chuàng)建的Pod、RC、RS、Service都獎被系統(tǒng)創(chuàng)建到這個默認(rèn)的名為default的Namespace中。
下面是Namespace的定義示例:

apiVersion: v1
kind: Namespace
metadata:
  name: development

定義一個Pod,并指定它屬于哪個Namespace:

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: development
spec:
  containers:
  - image: busybox
    command:
      - sleep
      - "3600"
    name: busybox

使用kubectl get命令查看Pod狀態(tài)信息時,需要加上--namespace參數(shù),指定查看哪個namespace下的資源對象,不加這個參數(shù)則默認(rèn)查看 default下的資源對象。
kubectl get pods --namespace=development
當(dāng)我們給每個租戶創(chuàng)建一個Namespace來實(shí)現(xiàn)多租戶的資源隔離時,還能結(jié)合Kubernetes的資源配額管理,限定不同租戶能占用的資源,例如CPU使用量、內(nèi)存使用量等。

十二、Annotation(注解)

Annotation與Label類似,也使用key/value鍵值對的形式進(jìn)行定義。不同的是Label具有嚴(yán)格的命名規(guī)則,它定義的是Kubernetes對象的元數(shù)據(jù)(Metadata),并且用于Label Selector。而Annotation則是用戶任意定義的“附加”信息,以便于外部工具進(jìn)行查找。通常Kubernetes的模塊會通過Annotation的方式標(biāo)記資源對象的一些特殊信息。
使用Annotation來記錄的信息如下:

  • build信息、release信息、Docker鏡像信息等,例如時間戳、release id號、PR號、鏡像bash值、docker registry地址等。
  • 日志庫、監(jiān)控庫、分析庫等資源庫的地址信息。
  • 程序調(diào)試工具信息,例如工具名稱、版本號等。
  • 團(tuán)隊(duì)的聯(lián)系信息,例如電話號碼、負(fù)責(zé)人名稱、網(wǎng)址等。

注:本文內(nèi)容摘自《Kubernetes權(quán)威指南:從Docker到Kubernetes實(shí)踐全接觸(紀(jì)念版》,并精減了部分內(nèi)部,而且對部分內(nèi)容做了相應(yīng)的調(diào)整,可以幫助大家加深對Kubernetes的各種資源對象的理解和定義方法,關(guān)注我的博客,跟我一起開啟k8s的學(xué)習(xí)之旅吧。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI