k8s術語理解

Node,Pod,Replication Controller,Service等都是k8s中的一種“資源對象”,都可以通過工具kubectl執行增、刪、改的管理操作。其配置結果是保存在etcd中。k8s就像是一個自動化的資源控制系統,通過對etcd庫中保存的資源期望狀態和實際資源狀態進行差異對比,來發現、控制和進行“糾錯”。


1、k8s集羣管理角色——Master

每個k8s集羣裏需要一個Master節點來負責整個集羣的管理和控制,通常要佔據一個獨立的服務器,從高可用角度考慮則建議使用3臺服務器。

Master節點上運行着以下關鍵進程或服務:

k8s API Server,提供了HTTP Rest接口的關鍵服務進程,是集羣中所有資源增、刪、改操作的唯一入口,也是控制集羣的唯一入口。

k8s Controller Manager,是集羣中所有資源對象的運行指揮中心。

k8s Scheduler,是負責調度Pod資源的進程。

etcd服務,提供集羣中所有資源對象配置的持久化。

2、k8s集羣管理角色——Node

Node是k8s集羣中的工作負載節點,當某個Node當機時,其上的工作負載會被Master自動轉移到其他節點上去。

Node節點上運行着以下關鍵進程或服務:

Kublete,負責Pod對應的容器的創建、啓停管理,與Master節點協作,實現集羣管理的基本功能。

kube-proxy,是提供k8s的通信與負載均衡功能的重要組件。

Docker Engine,docker引擎。

Node節點可以動態地加入到k8s集羣中,在這個過程中kublete找到Master完成信息註冊。在加入集羣后,kublete進程就定時向Master節點發送操作系統、Docker版本、CPU、內存的統計信息,以及當前有哪些Pods在運行。當某個Node超時未發送以上信息時,會被Master判定爲“失聯”(Not Ready),隨即觸發工作負載轉移的流程。

查看集羣中有哪些Nodes:

[root@gqtest ~]# kubectl get nodes

NAME        STATUS    AGE

127.0.0.1   Ready     3d

查看某個Node的詳細信息:

[root@gqtest ~]# kubectl describe node "127.0.0.1"

Name:            127.0.0.1

Role:            

Labels:            beta.kubernetes.io/arch=amd64

            beta.kubernetes.io/os=linux

            kubernetes.io/hostname=127.0.0.1

Taints:            <none>

CreationTimestamp:    Sat, 17 Feb 2018 22:14:43 +0800

Phase:            

Conditions:

  Type            Status    LastHeartbeatTime            LastTransitionTime            Reason                Message

  ----            ------    -----------------            ------------------            ------                -------

  OutOfDisk         False     Wed, 21 Feb 2018 10:40:50 +0800     Sat, 17 Feb 2018 22:14:43 +0800     KubeletHasSufficientDisk     kubelet has sufficient disk space available

  MemoryPressure     False     Wed, 21 Feb 2018 10:40:50 +0800     Sat, 17 Feb 2018 22:14:43 +0800     KubeletHasSufficientMemory     kubelet has sufficient memory available

  DiskPressure         False     Wed, 21 Feb 2018 10:40:50 +0800     Sat, 17 Feb 2018 22:14:43 +0800     KubeletHasNoDiskPressure     kubelet has no disk pressure

  Ready         True     Wed, 21 Feb 2018 10:40:50 +0800     Wed, 21 Feb 2018 10:40:00 +0800     KubeletReady             kubelet is posting ready status

Addresses:        127.0.0.1,127.0.0.1,127.0.0.1

Capacity:

alpha.kubernetes.io/nvidia-gpu:    0

cpu:                    2

memory:                1532144Ki

pods:                    110

Allocatable:

alpha.kubernetes.io/nvidia-gpu:    0

cpu:                    2

memory:                1532144Ki

pods:                    110

System Info:

Machine ID:            3be0a8ad023f4dd0b530ddcaeecf83cd

System UUID:            E351A3F3-7D82-4C97-A174-297F8526DDBD

Boot ID:            d40f85db-90fe-4904-92cc-847b6f136058

Kernel Version:        3.10.0-693.17.1.el7.x86_64

OS Image:            CentOS Linux 7 (Core)

Operating System:        linux

Architecture:            amd64

Container Runtime Version:    docker://1.12.6

Kubelet Version:        v1.5.2

Kube-Proxy Version:        v1.5.2

ExternalID:            127.0.0.1

Non-terminated Pods:        (3 in total)

  Namespace            Name            CPU Requests    CPU Limits    Memory Requests    Memory Limits

  ---------            ----            ------------    ----------    ---------------    -------------

  default            mysql-mn49n        0 (0%)        0 (0%)        0 (0%)        0 (0%)

  default            myweb-k6fp0        0 (0%)        0 (0%)        0 (0%)        0 (0%)

  default            myweb-m9nv9        0 (0%)        0 (0%)        0 (0%)        0 (0%)

Allocated resources:

  (Total limits may be over 100 percent, i.e., overcommitted.

  CPU Requests    CPU Limits    Memory Requests    Memory Limits

  ------------    ----------    ---------------    -------------

  0 (0%)    0 (0%)        0 (0%)        0 (0%)

Events:

  FirstSeen    LastSeen    Count    From            SubObjectPath    Type        Reason            Message

  ---------    --------    -----    ----            -------------    --------    ------            -------

  1m        1m        1    {kubelet 127.0.0.1}            Normal        Starting        Starting kubelet.

  1m        1m        1    {kubelet 127.0.0.1}            Warning        ImageGCFailed        unable to find data for container /

  1m        1m        1    {kubelet 127.0.0.1}            Normal        NodeHasSufficientDisk    Node 127.0.0.1 status is now: NodeHasSufficientDisk

  1m        1m        1    {kubelet 127.0.0.1}            Normal        NodeHasSufficientMemory    Node 127.0.0.1 status is now: NodeHasSufficientMemory

  1m        1m        1    {kubelet 127.0.0.1}            Normal        NodeHasNoDiskPressure    Node 127.0.0.1 status is now: NodeHasNoDiskPressure

  1m        1m        1    {kubelet 127.0.0.1}            Warning        Rebooted        Node 127.0.0.1 has been rebooted, boot id: d40f85db-90fe-4904-92cc-847b6f136058

  1m        1m        1    {kubelet 127.0.0.1}            Normal        NodeNotReady        Node 127.0.0.1 status is now: NodeNotReady

  58s        58s        1    {kubelet 127.0.0.1}            Normal        NodeReady        Node 127.0.0.1 status is now: NodeReady

  1m        55s        2    {kubelet 127.0.0.1}            Warning        MissingClusterDNS    kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. pod: "myweb-k6fp0_default(3ac7a156-1414-11e8-9692-0800275f8277)". Falling back to DNSDefault policy.

  1m        53s        2    {kubelet 127.0.0.1}            Warning        MissingClusterDNS    kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. pod: "myweb-m9nv9_default(3ac7b4c7-1414-11e8-9692-0800275f8277)". Falling back to DNSDefault policy.

  1m        48s        2    {kubelet 127.0.0.1}            Warning        MissingClusterDNS    kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. pod: "mysql-mn49n_default(cee70dc4-140e-11e8-9692-0800275f8277)". Falling back to DNSDefault policy.


3、k8s集羣最小資源調度管理單位——Pod

一般情況下,Pod是Kubernetes創建或部署的最小/最簡單的基本單位,一個Pod代表集羣上正在運行的一個進程。

注:在單個Pod中共同管理多個容器是一個相對高級的用法,應該只有在容器緊密耦合的特殊實例中使用此模式。


Kubernetes中的Pod使用可分兩種主要方式:

Pod中運行一個容器。“one-container-per-Pod”模式是Kubernetes最常見的用法。在這種情況下,你可以將Pod視爲單個封裝的容器,但是Kubernetes是直接管理Pod而不是容器。

Pods中運行多個需要一起工作的容器。Pod可以封裝緊密耦合的應用,它們需要由多個容器組成,它們之間能夠共享資源,這些容器可以形成一個單一的內部service單位。

每個Pod都是運行應用的單個實例,如果需要水平擴展應用(例如,運行多個實例),則應該使用多個Pods,每個實例一個Pod。在Kubernetes中,這樣通常稱爲Replication。Replication的Pod通常由Controller創建和管理。


Pods提供兩種共享資源:網絡和存儲。

網絡,每個Pod被分配一個獨立的IP地址,Pod中的每個容器共享網絡命名空間,包括IP地址和網絡端口。Pod內的容器可以使用localhost相互通信。當Pod中的容器與Pod 外部通信時,他們必須協調如何使用共享網絡資源(如端口)。k8s要求底層網絡支持集羣內任意兩個Pod之間的TCP/IP直接通信,這一般是採用虛擬二層網絡技術來實現的,如Open vSwitch。

存儲,Pod可以指定一組共享存儲volumes。Pod中的所有容器都可以訪問共享volumes,允許這些容器共享數據。volumes 還用於Pod中的數據持久化,以防其中一個容器需要重新啓動而丟失數據。

Pod的幾個關鍵知識點:

很少會直接在kubernetes中創建單個Pod。因爲Pod的生命週期是短暫的,用後即焚的實體。當Pod被創建後(不論是由你直接創建還是被其他Controller),都會被Kuberentes調度到集羣的Node上。直到Pod的進程終止、被刪掉、因爲缺少資源而被驅逐、或者Node故障之前這個Pod都會一直保持在那個Node上。

Pod不會自愈。如果Pod運行的Node故障,或者是調度器本身故障,這個Pod就會被刪除。同樣的,如果Pod所在Node缺少資源或者Pod處於維護狀態,Pod也會被驅逐。Kubernetes使用更高級的稱爲Controller的抽象層,來管理Pod實例。雖然可以直接使用Pod,但是在Kubernetes中通常是使用Controller來管理Pod。

Controller可以創建和管理多個Pod,提供副本管理、滾動升級和集羣級別的自愈能力。例如,如果一個Node故障,Controller就能自動將該節點上的Pod調度到其他健康的Node上。通常,Controller會用你提供的Pod Template來創建相應的Pod。

Pod都會包含一個特殊的“根容器”,一個或多個業務容器。當根容器“死亡”了時,代表該Pod整個容器組的不可用。

Endpoint,Pod的IP加上Pod裏的容器端口(containerPort)稱爲一個Endpoint,代表着此Pod裏的一個服務進程的對外通信地址。

Pod Event事件,可以使用kubectl describe pod xxxx查看一個Pod的詳細信息,其中包括了該Pod所發生的每個事件的信息。Event事件信息對於故障排查很有幫助。

Pod的類型:

普通Pod

靜態Pod,不受etcd的配置信息管控,直接存放在某個Node上且只在該Node上運行。

Pod的資源限額:

CPU限額,資源限制的單位爲cpu Core的數量,該資源是以絕對值計算的。k8s將1/1000的CPU Core的資源定義爲可供分配的最小CPU資源單位,稱爲m。通常一個容器的CPU配額被定義爲100~300m,即佔用0.1~0.3個CPU Core。因爲該配額是一個資源的絕對值,所以無論是在一個只有2 CPU Cores的機器上,還是在一個有48CPU Cores的機器上,100m所代表的CPU使用量都是一樣的。

內存限額,內存的資源限制是以節節爲計量單位,內存的配額也是按資源的絕對值進行分配的。

k8s中配置資源限額的方法:

Requests設置,一個資源的最小申請量,是系統必須滿足的一個用量;

Limits設置,該資源的最大允許使用量,不能被突破,當容器試圖突破該參數限制時,可能會被k8s Kii並重啓。

一般是結合使用以上兩個參數去定義一個資源的配額,如下所示。

spec:

  containers:

  - name: db

    image: mysql

    resources:

      requests:

        memory: "64Mi"

        cpu: "250m"

      limits:

        memory: "128Mi"

        cpu: "500m"


4、Label和Label Selector

Label是一個key/value的鍵值對,可以附加到各種資源對象上。

一個資源對象可以定義任意數量的Label,同一個Label也可以被添加到任意數量的資源對象上去。

通常是在資源對象定義時確定Label,也支持在對象創建後動態添加或刪除。

Label和Lable Selector構成了k8s系統中最核心的一個應用模型,可以對被管理對象進行精細分組,以實現整個集羣的高可用。

通過給指定的資源對象捆綁一個或多個不同的Label來實現多維度的資源分組管理。一些示例標籤如下:

"release" : "stable", "release" : "canary"

"environment" : "dev","environment" : "qa","environment" : "production"

"tier" : "frontend","tier" : "backend","tier" : "cache"

"partition" : "customerA", "partition" : "customerB"

"track" : "daily", "track" : "weekly"

Label Selector可以查詢和篩選擁有某些Label的資源對象。

目前支持兩種選擇器:equality-based(基於平等)和set-based(基於集合)的。前者採用等式的表達式,後者採用集合操作的表達式匹配標籤。

標籤選擇器可以由逗號分隔的多個requirements 組成。在多重需求的情況下,必須滿足所有要求,因此逗號分隔符作爲AND邏輯運算符。

equality-based示例:

name = redis-slave

env != production

set-based示例:

name in (redis-master, redis-slave)

name not in (frontend)

Label Selector set-based篩選功能僅在以下新出現的管理對象中得到了支持:

Deployment

ReplicaSet

DaemonSet

Job

Label Selector的幾個重要使用場景:

kube-controller進程,通過資源對象RC上定義的Label Selector來篩選要監控和管理的Pod副本的數量。

kube-proxy進程,通過Service的Lable Selector來選擇對應的Pod,建立起每個Service到對應Pod的請求轉發路由表,進而實現Service的智能負載均衡機制。

kube-scheduler進程,通過爲某些Node定義特定的Label,然後在Pod定義文件中使用NodeSelector進行篩選,進而實現Pod的定向調度功能。

5、Replication Controller與Replica Set

ReplicationController(簡稱RC),定義了一個期望的場景,即聲明某種Pod的副本數量在任意時刻都符合某個預期值。通過RC,k8s實現了用戶應用集羣的高可用性,同時大減少了系統管理員在傳統IT環境中需要完成的許多手工運維工作(如主機監控、應用監控和故障恢復等)。

ReplicationController是早期k8s版本中主要使用的一項技術,在較新版本中,RC的功能已經逐漸被功能更強大的ReplicaSet和Deployment的組合所替代。

因爲ReplicationController、ReplicaSet和Deployment之間存在着巨大的相似性,所以仍然有了解和掌握RC知識和使用方法的必要。

RC會包含以下幾個部分:

Pod期待的副本數;

用於篩選目標Pod的Label Selector;

當Pod的副本數量小於預期時,用於創建新Pod的Pod模板。

修改RC的副本數量可以實現Pod的動態縮放:

$ kubectl scale rc redis-slave --replicas=3


關於刪除RC:

刪除RC並不會影響通過該RC已經創建好的Pod;

爲了刪除使用該RC創建的Pods,可以設置replicas爲0,然後更新該RC;

使用kubectl delete命令刪除RC及其所有pod。

關於ReplicaSet的知識:

由於Replication Controller與k8s代碼中的模塊Replication Controller同名,所以在k8s v1.2時就升級成了另外一個新的工具Replica Set。二者之間唯一的區別是,Replica Set支持了基於集合的Label Selector功能。

ReplicaSet是支持新的set-based選擇器要求的下一代ReplicationController 。它主要用作Deployment協調pod創建、刪除和更新。雖然ReplicaSets可以獨立使用,但它主要被 Deployments用作pod 機制的創建、刪除和更新,建議使用Deployment而不是直接使用ReplicaSets。

ReplicaSet的使用示例(部分):

apiVersion: extensions/v1beta1

kind: ReplicaSet

metadata:

  name: frontend

spec:

  replicas: 3

  selector:

    matchLabels:

      tier: frontend

    matchExpressions:

      - {key: tier, operator: In, values: [frontend]}

  template:

    metadata:

      labels:

        app: guestbook

        tier: frontend

    spec:


RC(Replica Set)的一些特性:

在大多數情況下,我們通過定義一個RC實現Pod的創建過程及副本數量的自動控制。

RC裏包括完整的Pod定義模板。

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

通過改變RC裏的Pod副本數量,可以實現Pod的擴容或縮容功能。

通過改變RC裏Pod模板中的鏡像版本,可以實現Pod的滾動升級功能。


6、Deployment

Deployment爲Pod和Replica Set(升級版的 Replication Controller)提供聲明式更新。

注意:您不該手動管理由 Deployment 創建的 Replica Set,否則您就篡越了 Deployment controller 的職責!


Deployment的典型的用例如下:

創建一個Deployment對象來生成對應的ReplicaSet,並完成Pod副本的創建過程。

檢查Deployment的狀態來查看部署動作是否完成,Pod副本的數量是否達到預期的值。

更新Deployment以創建新的Pod,通過修改Pod-Template-Spec字段來聲明Pod的新狀態。這會創建一個新的ReplicaSet,Deployment會按照控制的速率將pod從舊的ReplicaSet移動到新的ReplicaSet中。

如果當前狀態不穩定,則回滾到一個早先的Deployment版本。

暫停Deployment,以便於一次性修改多個PodTemplateSpec的配置項,然後再恢復Deployment,進行新的發佈。

擴容Deployment以滿足更高的負載。

查看Deployment 的狀態,以此作爲發佈是否成功的指標。

清除舊的不必要的 ReplicaSets。

(1)創建 Deployment

下面是一個 Deployment 示例,它創建了一個 ReplicaSet 來啓動3個 nginx pod。

下載示例文件nginx-deployment.yaml並執行命令:

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

  name: nginx-deployment

  labels:

    app: nginx

spec:

  replicas: 1

  selector:

    matchLabels:

      app: nginx

  template:

    metadata:

      labels:

        app: nginx

    spec:

      containers:

      - name: nginx

        image: nginx:1.7.9

        ports:

        - containerPort: 80

執行創建命令:

[root@gqtest ~]# kubectl create -f nginx-deployment.yaml --record

deployment "nginx-deployment" created

注:--record選項可以記錄當前命令執行記錄,便於以後查看一個deployment revision中執行了哪些命令。

[root@gqtest ~]# kubectl get deployments

NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

nginx-deployment   1         1         1            0           2m

看到available數量仍爲0,繼續查看一下該deployment的詳細情況:

[root@gqtest ~]# kubectl describe deployment nginx-deployment

Name:            nginx-deployment

Namespace:        default

CreationTimestamp:    Wed, 21 Feb 2018 17:02:45 +0800

Labels:            app=nginx

Selector:        app=nginx

Replicas:        1 updated | 1 total | 0 available | 1 unavailable

StrategyType:        RollingUpdate

MinReadySeconds:    0

RollingUpdateStrategy:    1 max unavailable, 1 max surge

Conditions:

  Type        Status    Reason

  ----        ------    ------

  Available     True    MinimumReplicasAvailable

OldReplicaSets:    <none>

NewReplicaSet:    nginx-deployment-4087004473 (1/1 replicas created)

Events:

  FirstSeen    LastSeen    Count    From                SubObjectPath    Type        Reason            Message

  ---------    --------    -----    ----                -------------    --------    ------            -------

  3m        3m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-4087004473 to 1

上面輸出信息沒有異常,再查看一次該deployment的狀態,如下所示,available的實例數量已經是1,說明經過一個創建過程(往往會因爲要在線下載docker image鏡像而需要等待一段時間),已經成功創建:

[root@gqtest ~]# kubectl get deployments

NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

nginx-deployment   1         1         1            1           4m

查看Replica Set信息,可以到到ReplicaSet名稱是在Deployment後添加一串數字:

[root@gqtest ~]# kubectl get rs

NAME                          DESIRED   CURRENT   READY     AGE

nginx-deployment-4087004473   1         1         1         4m

繼續查看pod的狀態,如下所示:

[root@gqtest ~]# kubectl get pods

NAME                                READY     STATUS    RESTARTS   AGE

mysql-mn49n                         1/1       Running   1          3d

myweb-k6fp0                         1/1       Running   1          3d

myweb-m9nv9                         1/1       Running   1          3d

nginx-deployment-4087004473-xdxhn   1/1       Running   0          7m


(2)更新Deployment

Deployment的更新(rollout)當且僅當Deployment的pod template中的label發生更新或者鏡像發生更改時,纔會被觸發。像Deployment擴容,不會觸發rollout事件。

假如我們現在想要讓 nginx pod 使用nginx:1.9.1的鏡像來代替原來的nginx:1.7.9的鏡像。

[root@gqtest ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1

deployment "nginx-deployment" image updated


或者可以使用edit命令來編輯 Deployment,修改 .spec.template.spec.containers[0].image ,將nginx:1.7.9 改寫成 nginx:1.9.1。

[root@gqtest ~]# kubectl edit deployment/nginx-deployment

查看更新結果:

[root@gqtest ~]# kubectl rollout status deployment/nginx-deployment

Waiting for rollout to finish: 0 of 1 updated replicas are available...

[root@gqtest ~]# kubectl get deployments

NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

nginx-deployment   1         1         1            0           18m

[root@gqtest ~]# kubectl get rs

NAME                          DESIRED   CURRENT   READY     AGE

nginx-deployment-3599678771   1         1         0         4m

nginx-deployment-4087004473   0         0         0         19m

從上面的輸出信息中看到,正在創建一個新的ReplicaSet的過程中,同時已經將舊的縮容到了0個replica。

查看pod狀態時,已經看不到舊的pod了:

[root@gqtest ~]# kubectl get pods

NAME                                READY     STATUS    RESTARTS   AGE

mysql-mn49n                         1/1       Running   1          3d

myweb-k6fp0                         1/1       Running   1          3d

myweb-m9nv9                         1/1       Running   1          3d

nginx-deployment-3599678771-chzwr   1/1       Running   0          6m

再次執行查看Deployment更新結果的命令,顯示已經成功完成:

[root@gqtest ~]# kubectl rollout status deployment/nginx-deployment

deployment "nginx-deployment" successfully rolled out

[root@gqtest ~]# kubectl get rs

NAME                          DESIRED   CURRENT   READY     AGE

nginx-deployment-3599678771   1         1         1         8m

nginx-deployment-4087004473   0         0         0         23m

最後查看一下該Deployment任務的詳細信息:

[root@gqtest ~]# kubectl describe deployment nginx-deployment

Name:            nginx-deployment

Namespace:        default

CreationTimestamp:    Wed, 21 Feb 2018 17:02:45 +0800

Labels:            app=nginx

Selector:        app=nginx

Replicas:        1 updated | 1 total | 1 available | 0 unavailable

StrategyType:        RollingUpdate

MinReadySeconds:    0

RollingUpdateStrategy:    1 max unavailable, 1 max surge

Conditions:

  Type        Status    Reason

  ----        ------    ------

  Available     True    MinimumReplicasAvailable

OldReplicaSets:    <none>

NewReplicaSet:    nginx-deployment-3599678771 (1/1 replicas created)

Events:

  FirstSeen    LastSeen    Count    From                SubObjectPath    Type        Reason            Message

  ---------    --------    -----    ----                -------------    --------    ------            -------

  25m        25m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-4087004473 to 1

  10m        10m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-3599678771 to 1

  10m        10m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled down replica set nginx-deployment-4087004473 to 0


Rollover(多個rollout並行)的說明:

假如您創建了一個有5個niginx:1.7.9 replica的 Deployment,但是當還只有3個nginx:1.7.9的 replica 創建出來的時候您就開始更新含有5個nginx:1.9.1 replica 的 Deployment。在這種情況下,Deployment 會立即殺掉已創建的3個nginx:1.7.9的 Pod,並開始創建nginx:1.9.1的 Pod。它不會等到所有的5個nginx:1.7.9的 Pod 都創建完成後纔開始改變航道。


Label selector 更新:

上面的演示是基於image文件發生了更改的條件下的一個Deployment更新的樣例。通常不鼓勵更新 label selector,雖然技術上可行,但關聯影響較多。


(3)回退Deployment

可以通過設置.spec.revisonHistoryLimit項來指定 deployment 最多保留多少 revision 歷史記錄。默認的會保留所有的 revision;如果將該項設置爲0,Deployment就不允許回退了。


只要 Deployment 的 rollout 被觸發就會創建一個 revision。也就是說當且僅當 Deployment 的 Pod template(如.spec.template)被更改,例如更新template 中的 label 和容器鏡像時,就會創建出一個新的 revision。


我們先故意執行一個有錯誤的Deployment任務:

[root@gqtest ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.99

deployment "nginx-deployment" image updated

我們故障寫了一個不存在的鏡像文件版本,Deployment rollout任務會補卡住,如下所示:

[root@gqtest ~]# kubectl rollout status deployments nginx-deployment

Waiting for rollout to finish: 0 of 1 updated replicas are available...

可以看到pod的狀態處於"ImagePullBackOff"的錯誤狀態:

[root@gqtest ~]# kubectl get rs

NAME                          DESIRED   CURRENT   READY     AGE

nginx-deployment-3599678771   0         0         0         23m

nginx-deployment-4087004473   0         0         0         38m

nginx-deployment-538426637    1         1         0         3m

[root@gqtest ~]# kubectl rollout status deployments nginx-deployment

Waiting for rollout to finish: 0 of 1 updated replicas are available...

^C[root@gqtest ~]# kubectl get pods

NAME                               READY     STATUS             RESTARTS   AGE

mysql-mn49n                        1/1       Running            1          3d

myweb-k6fp0                        1/1       Running            1          3d

myweb-m9nv9                        1/1       Running            1          3d

nginx-deployment-538426637-g55n4   0/1       ImagePullBackOff   0          3m

注:Deployment controller會自動停止壞的 rollout,並停止擴容新的 ReplicaSet。

[root@gqtest ~]# kubectl describe deployment nginx-deployment

Name:            nginx-deployment

Namespace:        default

CreationTimestamp:    Wed, 21 Feb 2018 17:02:45 +0800

Labels:            app=nginx

Selector:        app=nginx

Replicas:        1 updated | 1 total | 0 available | 1 unavailable

StrategyType:        RollingUpdate

MinReadySeconds:    0

RollingUpdateStrategy:    1 max unavailable, 1 max surge

Conditions:

  Type        Status    Reason

  ----        ------    ------

  Available     True    MinimumReplicasAvailable

OldReplicaSets:    <none>

NewReplicaSet:    nginx-deployment-538426637 (1/1 replicas created)

Events:

  FirstSeen    LastSeen    Count    From                SubObjectPath    Type        Reason            Message

  ---------    --------    -----    ----                -------------    --------    ------            -------

  40m        40m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-4087004473 to 1

  25m        25m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-3599678771 to 1

  25m        25m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled down replica set nginx-deployment-4087004473 to 0

  5m        5m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-538426637 to 1

  5m        5m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled down replica set nginx-deployment-3599678771 to 0

我們需要回退到穩定版本的Deployment revision。

先查看一下Deployment的revision記錄:

[root@gqtest ~]# kubectl rollout history deployment/nginx-deployment

deployments "nginx-deployment"

REVISION    CHANGE-CAUSE

1        kubectl create -f nginx-deployment.yaml --record

2        kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1

3        kubectl set image deployment/nginx-deployment nginx=nginx:1.99

注:因爲我們創建 Deployment 的時候使用了--recored參數可以記錄命令,我們可以很方便的查看每次 revision 的變化。

查看單個revision 的詳細信息:

[root@gqtest ~]# kubectl rollout history deployment/nginx-deployment --revision=2

deployments "nginx-deployment" with revision #2

  Labels:    app=nginx

    pod-template-hash=3599678771

  Annotations:    kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1

  Containers:

   nginx:

    Image:    nginx:1.9.1

    Port:    80/TCP

    Volume Mounts:    <none>

    Environment Variables:    <none>

  No volumes.

回退到歷史版本

回退到上一個版本:

[root@gqtest ~]# kubectl rollout undo deployment/nginx-deployment

deployment "nginx-deployment" rolled back

回退到一個指定的版本:

# kubectl rollout undo deployment/nginx-deployment --to-revision=2

deployment "nginx-deployment" rolled back


查看下回退結果:

[root@gqtest ~]# kubectl get deployment

NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

nginx-deployment   1         1         1            1           46m

查看下回退版本所產生的事件記錄:

[root@gqtest ~]# kubectl describe deployment nginx-deployment

Name:            nginx-deployment

Namespace:        default

CreationTimestamp:    Wed, 21 Feb 2018 17:02:45 +0800

Labels:            app=nginx

Selector:        app=nginx

Replicas:        1 updated | 1 total | 1 available | 0 unavailable

StrategyType:        RollingUpdate

MinReadySeconds:    0

RollingUpdateStrategy:    1 max unavailable, 1 max surge

Conditions:

  Type        Status    Reason

  ----        ------    ------

  Available     True    MinimumReplicasAvailable

OldReplicaSets:    <none>

NewReplicaSet:    nginx-deployment-3599678771 (1/1 replicas created)

Events:

  FirstSeen    LastSeen    Count    From                SubObjectPath    Type        Reason            Message

  ---------    --------    -----    ----                -------------    --------    ------            -------

  46m        46m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-4087004473 to 1

  32m        32m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled down replica set nginx-deployment-4087004473 to 0

  11m        11m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-538426637 to 1

  11m        11m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled down replica set nginx-deployment-3599678771 to 0

  32m        2m        2    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-3599678771 to 1

  2m        2m        1    {deployment-controller }            Normal        DeploymentRollback    Rolled back deployment "nginx-deployment" to revision 2

  2m        2m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled down replica set nginx-deployment-538426637 to 0


可以通過設置.spec.revisonHistoryLimit項來指定 deployment 最多保留多少 revision 歷史記錄。默認的會保留所有的 revision;如果將該項設置爲0,Deployment就不允許回退了。


(4)Deployment 擴容

使用以下命令將nginx-deployment擴容爲3副本:

[root@gqtest ~]# kubectl scale deployment nginx-deployment --replicas 3

deployment "nginx-deployment" scaled

[root@gqtest ~]# kubectl get deployment

NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE

nginx-deployment   3         3         3            3           51m

[root@gqtest ~]# kubectl get rs

NAME                          DESIRED   CURRENT   READY     AGE

nginx-deployment-3599678771   3         3         3         36m

nginx-deployment-4087004473   0         0         0         51m

nginx-deployment-538426637    0         0         0         16m

[root@gqtest ~]# kubectl get pods

NAME                                READY     STATUS    RESTARTS   AGE

mysql-mn49n                         1/1       Running   1          3d

myweb-k6fp0                         1/1       Running   1          3d

myweb-m9nv9                         1/1       Running   1          3d

nginx-deployment-3599678771-hz7l6   1/1       Running   0          7m

nginx-deployment-3599678771-j136m   1/1       Running   0          1m

nginx-deployment-3599678771-kqwpf   1/1       Running   0          1m

查看該Deployment的事件記錄:

[root@gqtest ~]# kubectl describe deployment nginx-deployment

Name:            nginx-deployment

Namespace:        default

CreationTimestamp:    Wed, 21 Feb 2018 17:02:45 +0800

Labels:            app=nginx

Selector:        app=nginx

Replicas:        3 updated | 3 total | 3 available | 0 unavailable

StrategyType:        RollingUpdate

MinReadySeconds:    0

RollingUpdateStrategy:    1 max unavailable, 1 max surge

Conditions:

  Type        Status    Reason

  ----        ------    ------

  Available     True    MinimumReplicasAvailable

OldReplicaSets:    <none>

NewReplicaSet:    nginx-deployment-3599678771 (3/3 replicas created)

Events:

  FirstSeen    LastSeen    Count    From                SubObjectPath    Type        Reason            Message

  ---------    --------    -----    ----                -------------    --------    ------            -------

  52m        52m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-4087004473 to 1

  37m        37m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled down replica set nginx-deployment-4087004473 to 0

  17m        17m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-538426637 to 1

  17m        17m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled down replica set nginx-deployment-3599678771 to 0

  37m        7m        2    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-3599678771 to 1

  7m        7m        1    {deployment-controller }            Normal        DeploymentRollback    Rolled back deployment "nginx-deployment" to revision 2

  7m        7m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled down replica set nginx-deployment-538426637 to 0

  1m        1m        1    {deployment-controller }            Normal        ScalingReplicaSet    Scaled up replica set nginx-deployment-3599678771 to 3


注:假如集羣中啓用了horizontal pod autoscaling,您可以給 Deployment 設置一個 autoscaler,基於當前 Pod的 CPU 利用率選擇最少和最多的 Pod 數。


關於Deployment的比例擴容:

RollingUpdate Deployment 支持同時運行一個應用的多個版本。或者 autoscaler 擴 容 RollingUpdate Deployment 的時候,正在中途的 rollout(進行中或者已經暫停的),爲了降低風險,Deployment controller 將會平衡已存在的活動中的 ReplicaSet(有 Pod 的 ReplicaSet)和新加入的 replica。這被稱爲比例擴容。


(5)暫停和恢復Deployment

可以在發出一次或多次更新前暫停一個 Deployment,然後再恢復它。這樣您就能多次暫停和恢復 Deployment,在此期間進行一些修復工作,而不會發出不必要的 rollout。

[root@gqtest ~]# kubectl rollout pause deployment/nginx-deployment

deployment "nginx-deployment" paused

[root@gqtest ~]# kubectl set image deploy/nginx-deployment nginx=nginx:1.9.2

deployment "nginx-deployment" image updated

即使執行了上面的鏡像更改命令,也沒有觸發任何Deployment rollout的事件。而且可以繼續做更多的修改,例如:

[root@gqtest ~]# kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=256Mi

deployment "nginx-deployment" resource requirements updated

注:-c選項的作用是指定容器唯一標識名

當各種變更都準備妥當後,我們恢復該deployment:

[root@gqtest ~]# kubectl rollout resume deploy nginx-deployment

deployment "nginx-deployment" resumed

查看一下deployment處理結果,使用-w選項(watch)跟蹤輸出如下所示:

[root@gqtest ~]# kubectl get rs -w

NAME                          DESIRED   CURRENT   READY     AGE

nginx-deployment-27997383     2         2         0         2m

nginx-deployment-3599678771   2         2         2         1h

nginx-deployment-4087004473   0         0         0         1h

nginx-deployment-538426637    0         0         0         59m

NAME                        DESIRED   CURRENT   READY     AGE

nginx-deployment-27997383   2         2         1         4m

nginx-deployment-3599678771   1         2         2         1h

nginx-deployment-3599678771   1         2         2         1h

nginx-deployment-27997383   3         2         1         4m

nginx-deployment-3599678771   1         1         1         1h

nginx-deployment-27997383   3         2         1         4m

nginx-deployment-27997383   3         3         1         4m

nginx-deployment-27997383   3         3         2         5m

nginx-deployment-3599678771   0         1         1         1h

nginx-deployment-3599678771   0         1         1         1h

nginx-deployment-3599678771   0         0         0         1h

可以看到已經成功完成了合併了多次更新內容後的deployment任務:

[root@gqtest ~]# kubectl get rs

NAME                          DESIRED   CURRENT   READY     AGE

nginx-deployment-27997383     3         3         3         13m

nginx-deployment-3599678771   0         0         0         1h

nginx-deployment-4087004473   0         0         0         1h

nginx-deployment-538426637    0         0         0         1h


(6)Deployment 狀態

Deployment 在生命週期中有多種狀態。在創建一個新的 ReplicaSet 的時候它可以是 progressing 狀態, complete 狀態,或者 fail to progress 狀態。

進行中的 Deployment

Kubernetes 將執行過下列任務之一的 Deployment 標記爲 progressing 狀態:

Deployment 正在創建新的ReplicaSet過程中。

Deployment 正在擴容一個已有的 ReplicaSet。

Deployment 正在縮容一個已有的 ReplicaSet。

有新的可用的 pod 出現。

可以使用kubectl rollout status命令監控 Deployment 的進度。


完成的 Deployment

Kubernetes 將包括以下特性的 Deployment 標記爲 complete 狀態:

Deployment 最小可用。最小可用意味着 Deployment 的可用 replica 個數等於或者超過 Deployment 策略中的期望個數。

所有與該 Deployment 相關的replica都被更新到了指定版本,也就說更新完成。

該 Deployment 中沒有舊的 Pod 存在。

可以用kubectl rollout status命令查看 Deployment 是否完成。如果 rollout 成功完成,kubectl rollout status將返回一個0值的 Exit Code。

[root@gqtest ~]# kubectl rollout status deploy/nginx-deployment

deployment "nginx-deployment" successfully rolled out

[root@gqtest ~]# echo $?

0


版本記錄的清理策略

可以設置 Deployment 中的 .spec.revisionHistoryLimit 項來指定保留多少舊的 ReplicaSet。 餘下的將在後臺被當作垃圾收集。默認的,所有的 revision 歷史就都會被保留。在未來的版本中,將會更改爲2。

注意: 將該值設置爲0,將導致所有的 Deployment 歷史記錄都會被清除,該 Deployment 就無法再回退了。


(7)金絲雀 Deployment

如果想要使用 Deployment 對部分用戶或服務器發佈 release,可以創建多個 Deployment,每個 Deployment 對應一個 release。


(8)編寫 Deployment Spec

在所有的 Kubernetes 配置中,Deployment 也需要apiVersion,kind和metadata這些配置項。

Deployment也需要 .spec section.

Pod Template

.spec.template 是 .spec中唯一要求的字段。

.spec.template 是 pod template. 它跟 Pod有一模一樣的schema,除了它是嵌套的並且不需要apiVersion 和 kind字段。

爲了劃分Pod的範圍,Deployment中的pod template必須指定適當的label(不要跟其他controller重複了)和適當的重啓策略。

.spec.template.spec.restartPolicy 可以設置爲 Always , 如果不指定的話這就是默認配置。

Replicas

.spec.replicas 是可以選字段,指定期望的pod數量,默認是1。

Selector

.spec.selector是可選字段,用來指定 label selector ,圈定Deployment管理的pod範圍。

如果被指定, .spec.selector 必須匹配 .spec.template.metadata.labels,否則它將被API拒絕。如果 .spec.selector 沒有被指定, .spec.selector.matchLabels 默認是 .spec.template.metadata.labels。

在Pod的template跟.spec.template不同或者數量超過了.spec.replicas規定的數量的情況下,Deployment會殺掉label跟selector不同的Pod。

注意: 不應該再創建其他label跟這個selector匹配的pod,或者通過其他Deployment,或者通過其他Controller,例如ReplicaSet和ReplicationController。否則該Deployment會被把它們當成都是自己創建的。Kubernetes不會阻止這麼做。如果有多個controller使用了重複的selector,controller們就會互相打架並導致不正確的行爲。

策略

.spec.strategy 指定新的Pod替換舊的Pod的策略。 .spec.strategy.type 可以是"Recreate"或者是 "RollingUpdate"(按比例更新)。"RollingUpdate"是默認值。

Recreate Deployment,.spec.strategy.type==Recreate時,在創建出新的Pod之前會先殺掉所有已存在的Pod。

Rolling Update Deployment,.spec.strategy.type==RollingUpdate時,Deployment使用rolling update 的方式更新Pod 。可以指定maxUnavailable 和 maxSurge 來控制 rolling update 進程。

Max Unavailable,.spec.strategy.rollingUpdate.maxUnavailable 是可選配置項,用來指定在升級過程中不可用Pod的最大數量。該值可以是一個絕對值(例如5),也可以是期望Pod數量的百分比(例如10%)。通過計算百分比的絕對值向下取整。例如,該值設置成30%,啓動rolling update後舊的ReplicatSet將會立即縮容到期望的Pod數量的70%。新的Pod ready後,隨着新的ReplicaSet的擴容,舊的ReplicaSet會進一步縮容,確保在升級的所有時刻可以用的Pod數量至少是期望Pod數量的70%。

Max Surge,.spec.strategy.rollingUpdate.maxSurge 是可選配置項,用來指定可以超過期望的Pod數量的最大個數。該值可以是一個絕對值(例如5)或者是期望的Pod數量的百分比(例如10%)。當MaxUnavailable爲0時該值不可以爲0。通過百分比計算的絕對值向上取整。默認值是1。例如,該值設置成30%,啓動rolling update後新的ReplicatSet將會立即擴容,新老Pod的總數不能超過期望的Pod數量的130%。舊的Pod被殺掉後,新的ReplicaSet將繼續擴容,舊的ReplicaSet會進一步縮容,確保在升級的所有時刻所有的Pod數量和不會超過期望Pod數量的130%。

Progress Deadline Seconds

.spec.progressDeadlineSeconds 是可選配置項,用來指定在系統報告Deployment的failed progressing——表現爲resource的狀態中type=Progressing、Status=False、 Reason=ProgressDeadlineExceeded前可以等待的Deployment進行的秒數。Deployment controller會繼續重試該Deployment。未來,在實現了自動回滾後, deployment controller在觀察到這種狀態時就會自動回滾。

如果設置該參數,該值必須大於 .spec.minReadySeconds。

Min Ready Seconds

.spec.minReadySeconds是一個可選配置項,用來指定沒有任何容器crash的Pod並被認爲是可用狀態的最小秒數。默認是0(Pod在ready後就會被認爲是可用狀態)。

Rollback To

.spec.rollbackTo 是一個可以選配置項,用來配置Deployment回退的配置。設置該參數將觸發回退操作,每次回退完成後,該值就會被清除。

Revision

.spec.rollbackTo.revision是一個可選配置項,用來指定回退到的revision。默認是0,意味着回退到歷史中最老的revision。

Revision History Limit

Deployment revision history存儲在它控制的ReplicaSets中。

.spec.revisionHistoryLimit 是一個可選配置項,用來指定可以保留的舊的ReplicaSet數量。該理想值取決於心Deployment的頻率和穩定性。如果該值沒有設置的話,默認所有舊的Replicaset或會被保留,將資源存儲在etcd中,是用kubectl get rs查看輸出。每個Deployment的該配置都保存在ReplicaSet中,然而,一旦刪除了舊的RepelicaSet,該Deployment就無法再回退到那個revison了。

如果將該值設置爲0,所有具有0個replica的ReplicaSet都會被刪除。在這種情況下,新的Deployment rollout無法撤銷,因爲revision history都被清理掉了。

Paused

.spec.paused是可以可選配置項,boolean值。用來指定暫停和恢復Deployment。Paused和沒有paused的Deployment之間的唯一區別就是,所有對paused deployment中的PodTemplateSpec的修改都不會觸發新的rollout。

Deployment被創建之後默認是非paused。

7、Horizontal Pod Autoscaler

橫向自動擴容功能,簡稱HPA,也是k8s系統中的一種資源對象。在v1.1版本中首次發佈,在v1.2版本中升級爲穩定版。在v1.6版本之前,僅支持使用CPU負載作爲是否擴容的判定條件;自v1.6版本開始提供了根據應用自定義指標進行自動擴容和縮容的功能,不過目前仍爲實驗性質。


可以通過yaml文件定義一個HPA對象,或者直接使用命令創建一個HPA對象。

yaml文件定義的樣例:

apiVersion: autoscaling/v1

kind: HorizontalPodAutoscaler

metadata:

  name: php-apache

  namespace: default

spec:

  maxReplicas: 10

  minReplicas: 1

  scaleTargetRef:

    kink: Deployment

    name: php-apache

  targetCPUUtilizationPercentage: 90

注:當名爲php-apache的deployment的Pods副本的CPU使用率超過90%時,會觸發自動擴容行爲。但擴容或縮容都必須滿足的約束條件是Pod的副本數量要在1~10之間。

以上爲命令行方式創建一個HPA:

[root@gqtest ~]# kubectl autoscale deployment nginx-deployment --min=1 --max=5 --cpu-percent=80

deployment "nginx-deployment" autoscaled


8、StatefulSet

StatefulSet(有狀態系統服務設計)在k8s v1.5中引入,在Kubernetes 1.7中還是beta特性。

現實中很多服務是有狀態的,如MySQL集羣、kafka集羣、ZooKeeper集羣等,這些應用集羣有以下特點:

每個節點都有固定的身份ID,通過這個ID,集羣中的成員可以相互發現和通信;

集羣的規模是相對固定的,且不能隨意變動;

集羣裏每個節點都是有狀態的,通常會持久化數據到永久存儲中;

如果磁盤損壞導致集羣裏某個節點無法正常運行,則集羣功能會部分受損;

StatefulSet是Deployment/RC的一個特殊變種,有如下特性:

StatefulSet裏每個Pod都有穩定、唯一的網絡標識,可以用來發現集羣內其他成員。假設StatefulSet名字叫kafka,那麼第1個Pod會命名爲kafka-0,第2個Pod叫kafka-1,以此類推。

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

StatefulSet裏的Pod採用穩定的持久化存儲卷,通過PV/PVC實現,刪除Pod時默認不會刪除與StatefulSet相關的存儲卷。

StatefulSet需要與Headless Service配合使用,需要在每個StatefulSet的定義中聲明它屬於哪個Headless Service。

Headless Service沒有Cluster IP,當解析Headless Service的DNS域名時,得到的是該Service對應的全部Pod的Endpoint列表。StatefulSet在Headless Service的基礎上,又爲受Headless Service控制的每個Pod實例創建了一個DNS域名,格式爲:$(podname).$(headless service name)。

樣例:一個3節點的kafka的StatefulSet集羣

該應用集羣的headless service名稱定義爲kafka

該應用集羣的StatefulSet名字爲kafka,則StatefulSet裏的3個Pod的名稱分別爲:kafka-0,kafka-1,kafka-2

該應用集羣的StatefulSet中3個Pod的DNS名稱應該是:kafka-0.kafka,kafka-1.kafka,kafka-2.kafka

可以在該應用集羣的配置文件中直接使用上述DNS名稱來代表相應的Pod。


9、Service

(1)Service的概念

k8s的Service定義了一個服務的訪問入口地址,前端的應用通過這個入口地址訪問其背後的一組由Pod副本組成的集羣實例。Service與其後端Pod副本集羣之間則是通過Label Selector來實現對接的。RC的作用相當於是保證Service的服務能力和服務質量始終處於預期的標準。一個 Service 在 Kubernetes 中是一個 REST 對象。


 Service 定義可以基於 POST 方式,請求 apiserver 創建新的實例。 例如,假定有一組 Pod,它們對外暴露了 9376 端口,同時還被打上 "app=MyApp" 標籤。

kind: Service

apiVersion: v1

metadata:

  name: my-service

spec:

  selector:

    app: MyApp

  ports:

    - protocol: TCP

      port: 80

      targetPort: 9376

上述配置將創建一個名稱爲 “my-service” 的 Service 對象,它會將請求代理到使用 TCP 端口 9376,並且具有標籤 "app=MyApp" 的 Pod 上。 這個 Service 將被指派一個 IP 地址(通常稱爲 “Cluster IP”)。 Service 能夠將一個接收端口映射到任意的 targetPort。 默認情況下,targetPort 將被設置爲與 port 字段相同的值。Kubernetes Service 能夠支持 TCP 和 UDP 協議,默認 TCP 協議。


使用以下命令查看Service的yaml定義文件:

# kubectl get svc my-service -o yaml


(2)沒有 selector 的 Service

Servcie 抽象了該如何訪問 Kubernetes Pod,但也能夠抽象其它類型的 backend,例如:

希望在生產環境中使用外部的數據庫集羣。

希望服務指向另一個 Namespace 中或其它集羣中的服務。

正在將工作負載同時轉移到 Kubernetes 集羣和運行在 Kubernetes 集羣之外的 backend。


定義沒有 selector 的 Service :

kind: Service

apiVersion: v1

metadata:

  name: my-service

spec:

  ports:

    - protocol: TCP

      port: 80

      targetPort: 9376

由於這個 Service 沒有 selector,就不會創建相關的 Endpoints 對象。可以手動將 Service 映射到指定的 Endpoints:

kind: Endpoints

apiVersion: v1

metadata:

  name: my-service

subsets:

  - addresses:

      - ip: 1.2.3.4

    ports:

      - port: 9376

注意:Endpoint IP 地址不能是 loopback(127.0.0.0/8)、 link-local(169.254.0.0/16)、或者 link-local 多播(224.0.0.0/24)。

訪問沒有 selector 的 Service,與有 selector 的 Service 的原理相同。請求將被路由到用戶定義的 Endpoint(該示例中爲 1.2.3.4:9376)。


ExternalName Service 是 Service 的特例,它沒有 selector,也沒有定義任何的端口和 Endpoint。 相反地,對於運行在集羣外部的服務,它通過返回該外部服務的別名這種方式來提供服務。

kind: Service

apiVersion: v1

metadata:

  name: my-service

  namespace: prod

spec:

  type: ExternalName

  externalName: my.database.example.com

當查詢主機 my-service.prod.svc.CLUSTER時,集羣的 DNS 服務將返回一個值爲 my.database.example.com 的 CNAME 記錄。 訪問這個服務的工作方式與其它的相同,唯一不同的是重定向發生在 DNS 層,而且不會進行代理或轉發。 如果後續決定要將數據庫遷移到 Kubernetes 集羣中,可以啓動對應的 Pod,增加合適的 Selector 或 Endpoint,修改 Service 的 type。


(3)VIP 和 Service 代理

運行在每個Node上的kube-proxy進程其實就是一個智能的軟件負載均衡器,它會負責把對Service的請求轉發到後端的某個Pod實例上並在內部實現服務的負載均衡與會話保持機制。Service不是共用一個負載均衡器的IP,而是被分配了一個全局唯一的虛擬IP地址,稱爲Cluster IP。在Service的整個生命週期內,它的Cluster IP不會改變。 kube-proxy 負責爲 Service 實現了一種 VIP(虛擬 IP)的形式,而不是 ExternalName 的形式。在k8s v1.2版本之前默認使用userspace提供vip代理服務,從 Kubernetes v1.2 起,默認是使用 iptables 代理。


iptables 代理模式

這種模式,kube-proxy 會監視 Kubernetes master 對 Service 對象和 Endpoints 對象的添加和移除。 對每個 Service,它會創建相關 iptables 規則,從而捕獲到達該 Service 的 clusterIP(虛擬 IP)和端口的請求,進而將請求重定向到 Service 的一組 backend 中的某個上面。 對於每個 Endpoints 對象,它也會創建 iptables 規則,這個規則會選擇一個 backend Pod。默認的策略是,隨機選擇一個 backend。 實現基於客戶端 IP 的會話親和性,可以將 service.spec.sessionAffinity 的值設置爲 "ClientIP" (默認值爲 "None")。

和 userspace 代理類似,網絡返回的結果是,任何到達 Service 的 IP:Port 的請求,都會被代理到一個合適的 backend,不需要客戶端知道關於 Kubernetes、Service、或 Pod 的任何信息。 這應該比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始選擇的 Pod 沒有響應,iptables 代理能夠自動地重試另一個 Pod,所以它需要依賴 readiness probes。


(4)多端口 Service

很多 Service 需要暴露多個端口。對於這種情況,Kubernetes 支持在 Service 對象中定義多個端口。 當使用多個端口時,必須給出所有的端口的名稱,這樣 Endpoint 就不會產生歧義,例如:

kind: Service

apiVersion: v1

metadata:

  name: my-service

spec:

    selector:

      app: MyApp

    ports:

      - name: http

        protocol: TCP

        port: 80

        targetPort: 9376

      - name: https

        protocol: TCP

        port: 443

        targetPort: 9377


(5)選擇自己的 IP 地址

在 Service 創建的請求中,可以通過設置 spec.clusterIP 字段來指定自己的集羣 IP 地址。 比如,希望替換一個已經已存在的 DNS 條目,或者遺留系統已經配置了一個固定的 IP 且很難重新配置。 用戶選擇的 IP 地址必須合法,並且這個 IP 地址在 service-cluster-ip-range CIDR 範圍內,這對 API Server 來說是通過一個標識來指定的。 如果 IP 地址不合法,API Server 會返回 HTTP 狀態碼 422,表示值不合法。


(6)服務發現

Kubernetes 支持2種基本的服務發現模式 —— 環境變量和 DNS。

環境變量

當 Pod 運行在 Node 上,kubelet 會爲每個活躍的 Service 添加一組環境變量。 它同時支持 Docker links兼容 變量、簡單的 {SVCNAME}_SERVICE_HOST 和 {SVCNAME}_SERVICE_PORT 變量,這裏 Service 的名稱需大寫,橫線被轉換成下劃線。

舉個例子,一個名稱爲 "redis-master" 的 Service 暴露了 TCP 端口 6379,同時給它分配了 Cluster IP 地址 10.0.0.11,這個 Service 生成了如下環境變量:

REDIS_MASTER_SERVICE_HOST=10.0.0.11

REDIS_MASTER_SERVICE_PORT=6379

REDIS_MASTER_PORT=tcp://10.0.0.11:6379

REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379

REDIS_MASTER_PORT_6379_TCP_PROTO=tcp

REDIS_MASTER_PORT_6379_TCP_PORT=6379

REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11

這意味着需要有順序的要求 —— Pod 想要訪問的任何 Service 必須在 Pod 自己之前被創建,否則這些環境變量就不會被賦值。DNS 並沒有這個限制。

DNS

一個強烈推薦的集羣插件 是 DNS 服務器。 DNS 服務器監視着創建新 Service 的 Kubernetes API,從而爲每一個 Service 創建一組 DNS 記錄。 如果整個集羣的 DNS 一直被啓用,那麼所有的 Pod 應該能夠自動對 Service 進行名稱解析。

例如,有一個名稱爲 "my-service" 的 Service,它在 Kubernetes 集羣中名爲 "my-ns" 的 Namespace 中,爲 "my-service.my-ns" 創建了一條 DNS 記錄。 在名稱爲 "my-ns" 的 Namespace 中的 Pod 應該能夠簡單地通過名稱查詢找到 "my-service"。 在另一個 Namespace 中的 Pod 必須限定名稱爲 "my-service.my-ns"。 這些名稱查詢的結果是 Cluster IP。

Kubernetes 也支持對端口名稱的 DNS SRV(Service)記錄。 如果名稱爲 "my-service.my-ns" 的 Service 有一個名爲 "http" 的 TCP 端口,可以對 "_http._tcp.my-service.my-ns" 執行 DNS SRV 查詢,得到 "http" 的端口號。

Kubernetes DNS 服務器是唯一的一種能夠訪問 ExternalName 類型的 Service 的方式。 更多信息可以查看DNS Pod 和 Service。

Kubernetes 從 1.3 版本起, DNS 是內置的服務,通過插件管理器 集羣插件 自動被啓動。Kubernetes DNS 在集羣中調度 DNS Pod 和 Service ,配置 kubelet 以通知個別容器使用 DNS Service 的 IP 解析 DNS 名字。


(7)Headless Service

有時不需要或不想要負載均衡,以及單獨的 Service IP。 遇到這種情況,可以通過指定 Cluster IP(spec.clusterIP)的值爲 "None" 來創建 Headless Service。

這個選項允許開發人員自由尋找他們自己的方式,從而降低與 Kubernetes 系統的耦合性。 應用仍然可以使用一種自注冊的模式和適配器,對其它需要發現機制的系統能夠很容易地基於這個 API 來構建。

對這類 Service 並不會分配 Cluster IP,kube-proxy 不會處理它們,而且平臺也不會爲它們進行負載均衡和路由。 DNS 如何實現自動配置,依賴於 Service 是否定義了 selector。


配置 Selector

對定義了 selector 的 Headless Service,Endpoint 控制器在 API 中創建了 Endpoints 記錄,並且修改 DNS 配置返回 A 記錄(地址),通過這個地址直接到達 Service 的後端 Pod上。

不配置 Selector

對沒有定義 selector 的 Headless Service,Endpoint 控制器不會創建 Endpoints 記錄。 


(8)發佈服務 —— type類型

對一些應用希望通過外部(Kubernetes 集羣外部)IP 地址暴露 Service。

Kubernetes ServiceTypes 允許指定一個需要的類型的 Service,默認是 ClusterIP 類型。

Type 的取值以及行爲如下:

ClusterIP:通過集羣的內部 IP 暴露服務,選擇該值,服務只能夠在集羣內部可以訪問,這也是默認的 ServiceType。

NodePort:通過每個 Node 上的 IP 和靜態端口(NodePort)暴露服務。NodePort 服務會路由到 ClusterIP 服務,這個 ClusterIP 服務會自動創建。通過請求 <NodeIP>:<NodePort>,可以從集羣的外部訪問一個 NodePort 服務。

LoadBalancer:使用雲提供商的負載局衡器,可以向外部暴露服務。外部的負載均衡器可以路由到 NodePort 服務和 ClusterIP 服務。

ExternalName:通過返回 CNAME 和它的值,可以將服務映射到 externalName 字段的內容(例如, foo.bar.example.com)。 沒有任何類型代理被創建,這隻有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。


k8s中有3種IP地址:

Node IP: Node節點的IP地址,這是集羣中每個節點的物理網卡的IP地址;

Pod IP: Pod的IP地址,這是Docker Engine根據docker0網橋的IP地址段進行分配的,通常是一個虛擬的二層網絡;

Cluster IP:Service 的IP地址,這也是一個虛擬的IP,但它更像是一個“僞造”的IP地址,因爲它沒有一個實體網絡對象,所以無法響應ping命令。它只能結合Service Port組成一個具體的通信服務端口,單獨的Cluster IP不具備TCP/IP通信的基礎。在k8s集羣之內,Node IP網、Pod IP網與Cluster IP網之間的通信採用的是k8s自己設計的一種編程實現的特殊的路由規則,不同於常見的IP路由實現。

10、Volume

(1)Volume概要知識

默認情況下容器中的磁盤文件是非持久化的,對於運行在容器中的應用來說面臨兩個問題,第一:當容器掛掉kubelet將重啓啓動它時,文件將會丟失;第二:當Pod中同時運行多個容器,容器之間需要共享文件時。Kubernetes的Volume解決了這兩個問題。

Kubernetes Volume具有明確的生命週期,與pod相同。因此,Volume的生命週期比Pod中運行的任何容器要持久,在容器重新啓動時能可以保留數據,當然,當Pod被刪除不存在時,Volume也將消失。

Kubernetes支持許多類型的Volume,Pod可以同時使用任意類型/數量的Volume。

要使用Volume,pod需要指定Volume的類型和內容(spec.volumes字段),和映射到容器的位置(spec.containers.volumeMounts字段)。

Volume的配置樣例:

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      


更多的Volume類型配置樣例可以參見:https://github.com/kubernetes/kubernetes/tree/master/examples/volumes


(2)Volume 類型

Kubernetes支持Volume類型有:

emptyDir

hostPath

gcePersistentDisk

awsElasticBlockStore

nfs

iscsi

fc (fibre channel)

flocker

glusterfs

rbd

cephfs

gitRepo

secret

persistentVolumeClaim

downwardAPI

projected

azureFileVolume

azureDisk

vsphereVolume

Quobyte

PortworxVolume

ScaleIO

StorageOS

local

(3)emptyDir

使用emptyDir時,當Pod分配到Node上時,將會創建一個emptyDir Volume,它的內容爲空,並且只要Node上的Pod一直運行,Volume就會一直存在。當Pod(不管任何原因)從Node上被刪除時,emptyDir也同時會刪除,存儲的數據也將永久刪除。emptyDir Volume的存儲介質(Disk,SSD等)取決於kubelet根目錄(如/var/lib/kubelet)所處文件系統的存儲介質。不限制emptyDir或hostPath Volume使用的空間大小,不對容器或Pod的資源隔離。

注:刪除容器不影響emptyDir。

emptyDir的一些用途:

臨時空間

一個容器需要從另一個容器中獲取數據的目錄

示例:

apiVersion: v1

kind: Pod

metadata:

  name: test-pd

spec:

  containers:

  - image: gcr.io/google_containers/test-webserver

    name: test-container

    volumeMounts:

    - mountPath: /cache

      name: cache-volume

  volumes:

  - name: cache-volume

    emptyDir: {}


(4)hostPath

hostPath允許掛載Node上的文件系統到Pod裏面去。如果Pod需要使用Node上的文件,可以使用hostPath。

通常有以下兩種使用場景:

容器應用程序生成的日誌文件需要永久保存時,可以使用宿主機的文件系統進行存儲。

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

使用hostPath的注意事項:

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

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

hostPath使用示例:

apiVersion: v1

kind: Pod

metadata:

  name: test-pd

spec:

  containers:

  - image: gcr.io/google_containers/test-webserver

    name: test-container

    volumeMounts:

    - mountPath: /test-pd

      name: test-volume

  volumes:

  - name: test-volume

    hostPath:

      # directory location on host

      path: /data

(5)NFS

Kubernetes中通過簡單地配置就可以掛載NFS到Pod中,而NFS中的數據是可以永久保存的,同時NFS支持同時寫操作。Pod被刪除時,Volume被卸載,內容被保留。這就意味着NFS能夠允許我們提前對數據進行處理,而且這些數據可以在Pod之間相互傳遞。

NFS使用示例(PV):nfs-pv.yaml

apiVersion: v1

kind: PersistentVolume

metadata:

  name: nfs

spec:

  capacity:

    storage: 1Mi

  accessModes:

    - ReadWriteMany

  nfs:

    # FIXME: use the right IP

    server: 10.244.1.4

    path: "/exports"


11、Persistent Volume(PV)

PersistentVolume子系統爲用戶和管理員提供了一個API,它抽象瞭如何提供存儲以及如何使用它的細節。 爲此,我們引入兩個新的API資源:PersistentVolume和PersistentVolumeClaim。

PersistentVolume(PV)是管理員設置的羣集中的一部分存儲。 它就像集羣中的一個資源,就像一個節點是集羣資源一樣。 PV是類似Volumes的插件,但具有獨立於Pod的生命週期。 此API對象捕獲存儲實現的細節,即NFS,iSCSI或特定於雲提供程序的存儲系統。

PersistentVolumeClaim(PVC)是用戶存儲的請求。 它與Pod相似。 Pod消耗節點資源,PVC消耗PV資源。 Pod可以請求特定級別的資源(CPU和內存)。 PVC聲明可以請求特定的存儲空間大小和訪問模式(例如,可以一次讀/寫或多次只讀)。

PV可以理解成是k8s集羣中的某個網絡存儲中對應的一塊存儲資源,它與Volume很類似,但有以下區別:

PV只能是網絡存儲,不屬於任何Node,但可以在每個Node上訪問;

PV不是定義是Pod上的,而是獨立定義的;

PV目前支持的存儲類型包括:gcePersistentDisk、AWSElasticBlockStore、AzureFile、AzureDisk、FC、Flocker、NFS、iSCSI、RBD、CephFS、Cinder、GlusterFS、Vsphere Volume、Quobyte Volumes、VMware Photon、Portworx Volumes、ScaleIO Volumes和HostPath(僅支持單機測試使用)。

比較重要的PV的accessModes屬性:

ReadWriteOnce: 讀寫權限,只能被單個Node掛載;

ReadOnlyMany: 只讀權限,允許被多個Node掛載;

ReadWriteMany: 讀寫權限,允許被多個Node掛載;

PV的幾種狀態:

Available

Bound

Released: 對應的PVC已經刪除,但資源還沒有被集羣回收。

Failed:PV自動回收失敗。

PV/PVC使用示例:nfs-pvc.yaml

kind: PersistentVolumeClaim

apiVersion: v1

metadata:

  name: my-nfs

spec:

  accessModes:

    - ReadWriteMany

  resources:

    requests:

      storage: 1Mi

注:PV的示例參見上一段落的NFS使用示例。


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

      volumes:

        - name: mypvc

          persistentVolumeClaim:

            claimName: my-nfs


12、Namespace

Kubernetes可以使用Namespaces(命名空間)創建多個虛擬集羣。當團隊或項目中具有許多用戶時,可以考慮使用Namespace來實現多租戶的資源隔離。

Namespace爲名稱提供了一個範圍。資源的Names在Namespace中具有唯一性。

Namespace是一種將集羣資源劃分爲多個用途(通過 resource quota)的方法。

在未來的Kubernetes版本中,默認情況下,相同Namespace中的對象將具有相同的訪問控制策略。

k8s集羣啓動後,會創建一個名爲"default"的Namespace,如果不特別指明一個資源對象的Namespace屬性,則用戶創建的資源對象都會使用默認的"default"。

大多數Kubernetes資源(例如pod、services、replication controllers或其他)都在某些Namespace中,但Namespace資源本身並不在Namespace中。而低級別資源(如Node和persistentVolumes)不在任何Namespace中。Events是一個例外:它們可能有也可能沒有Namespace,具體取決於Events的對象。


創建Namespace

(1) 命令行直接創建

$ kubectl create namespace new-namespace


(2) 通過文件創建

$ cat my-namespace.yaml

apiVersion: v1

kind: Namespace

metadata:

  name: new-namespace


$ kubectl create -f ./my-namespace.yaml

注意:命名空間名稱滿足正則表達式[a-z0-9]([-a-z0-9]*[a-z0-9])?,最大長度爲63位


刪除Namespace


$ kubectl delete namespaces new-namespace

注意:

刪除一個namespace會自動刪除所有屬於該namespace的資源。

default和kube-system命名空間不可刪除。

PersistentVolumes是不屬於任何namespace的,但PersistentVolumeClaim是屬於某個特定namespace的。

Events是否屬於namespace取決於產生events的對象。

查看 Namespace

使用以下命令列出羣集中的當前的Namespace:

$ kubectl get namespaces

NAME STATUS AGE

default Active 1d

kube-system Active 1d


Kubernetes從兩個初始的Namespace開始:

default

kube-system 由Kubernetes系統創建的對象的Namespace

將一個資源對象放入名爲"development"的命名空間裏:

apiVersion: v1

kind: Pod

metadata:

  name: busybox

  namespace: development

spec:

  containers:

  - image: busybox

    command:

    - sleep

    - "3600"

    name: busybox


設置請求的名稱空間

要臨時設置Request的Namespace,請使用--namespace 標誌。

例如:

$ kubectl --namespace=<insert-namespace-name-here> run nginx --image=nginx

$ kubectl --namespace=<insert-namespace-name-here> get pods

注:如果不加--namespace參數,kubectl get將僅顯示屬於"default"命名空間的資源對象。


可以使用kubectl命令將創建的Namespace可以永久保存在context中。

$ kubectl config set-context $(kubectl config current-context) --namespace=<insert-namespace-name-here>

# Validate it

$ kubectl config view | grep namespace:


13、Annotation(註解)

Annotation與Label類似,也使用key/value鍵值對的形式定義。可以使用Kubernetes Annotations將任何非標識metadata附加到對象。客戶端(如工具和庫)可以檢索此metadata。

可以使用Labels或Annotations將元數據附加到Kubernetes對象。標籤可用於選擇對象並查找滿足某些條件的對象集合。相比之下,Annotations不用於標識和選擇對象。Annotations中的元數據可以是small 或large,structured 或unstructured,並且可以包括標籤不允許使用的字符。


Annotations就如標籤一樣,也是由key/value組成:

"annotations": {

  "key1" : "value1",

  "key2" : "value2"

}


以下是在Annotations中記錄信息的一些例子:

構建、發佈的鏡像信息,如時間戳,發行ID,git分支,PR編號,鏡像hashes和注Registry地址。

一些日誌記錄、監視、分析或audit repositories。

一些工具信息:例如,名稱、版本和構建信息。

用戶或工具/系統來源信息,例如來自其他生態系統組件對象的URL。

負責人電話/座機,或一些信息目錄。

注意:Annotations不會被Kubernetes直接使用,其主要目的是方便用戶閱讀查找。

參考1:《Kubernetes權威指南——從Docker到Kubernetes實踐全接觸》第1章。


參考2:Kubernetes中文社區 | 中文文檔



轉自:https://blog.csdn.net/watermelonbig/article/details/79346524?utm_source=copy 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章