国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

kubernetes中的local persistent volume

Zhuxy / 1695人閱讀

摘要:的詳細內容如下當然,也可以不使用,而是手動創建。前是將作為記錄到中,起將其獨立為一個字段接下來可以創建各種,記得要在的模板中聲明。注意到這里是,即我們一開始創建的實例的名字。為表示中申明的未的,在集群內的中找不到可以匹配的。

什么是Local Persistent Volumes

在kubernetes 1.14版本中, Local Persistent Volumes(以下簡稱LPV)已變為正式版本(GA),LPV的概念在1.7中被首次提出(alpha),并在1.10版本中升級到beat版本。現在用戶終于可以在生產環境中使用LPV的功能和API了。

首先:Local Persistent Volumes代表了直接綁定在計算節點上的一塊本地磁盤。

kubernetes提供了一套卷插件(volume plugin)標準,使得k8s集群的工作負載可以使用多種塊存儲和文件存儲。大部分磁盤插件都使用了遠程存儲,這是為了讓持久化的數據與計算節點彼此獨立,但遠程存儲通常無法提供本地存儲那么強的讀寫性能。有了LPV 插件,kubernetes負載現在可以用同樣的volume api,在容器中使用本地磁盤。

這跟hostPath有什么區別

hostPath是一種volume,可以讓pod掛載宿主機上的一個文件或目錄(如果掛載路徑不存在,則創建為目錄或文件并掛載)。

最大的不同在于調度器是否能理解磁盤和node的對應關系,一個使用hostPath的pod,當他被重新調度時,很有可能被調度到與原先不同的node上,這就導致pod內數據丟失了。而使用LPV的pod,總會被調度到同一個node上(否則就調度失敗)。

如何使用LPV

首先 需要創建StorageClass

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

注意到這里volumeBindingMode字段的值是WaitForFirstConsumer。這種bindingmode意味著:

kubernetes的pv控制器會將這類pv的binding延遲,直到有一個使用了對應pvc的pod被創建出來且該pod被調度完畢。這時候才會將pv和pvc進行binding,并且這時候pv的選擇會結合調度的node和pv的nodeaffinity。

接下來,提前準備好的provisioner會動態創建PV。

$ kubectl get pv
NAME                CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM  STORAGECLASS   REASON      AGE
local-pv-27c0f084   368Gi      RWO            Delete           Available          local-storage              8s
local-pv-3796b049   368Gi      RWO            Delete           Available          local-storage              7s
local-pv-3ddecaea   368Gi      RWO            Delete           Available          local-storage              7s

LPV的詳細內容如下:

$ kubectl describe pv local-pv-ce05be60 
Name:        local-pv-ce05be60
Labels:        
Annotations:    pv.kubernetes.io/provisioned-by=local-volume-provisioner-minikube-18f57fb2-a186-11e7-b543-080027d51893
StorageClass:    local-fast
Status:        Available
Claim:        
Reclaim Policy:    Delete
Access Modes:    RWO
Capacity:    1024220Ki
NodeAffinity:
  Required Terms:
      Term 0:  kubernetes.io/hostname in [my-node]
Message:    
Source:
    Type:    LocalVolume (a persistent volume backed by local storage on a node)
    Path:    /mnt/disks/vol1
Events:        

當然,也可以不使用provisioner,而是手動創建PV。但是必須要注意的是,LPV必須要填寫nodeAffinity。 (1.10前k8s是將nodeAffinity作為annotation記錄到PV中,1.10起將其獨立為一個字段)

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 100Gi
  # volumeMode field requires BlockVolume Alpha feature gate to be enabled.
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - example-node

接下來可以創建各種workload,記得要在workload的模板中聲明volumeClaimTemplates。

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: local-test
spec:
  serviceName: "local-service"
  replicas: 3
  selector:
    matchLabels:
      app: local-test
  template:
    metadata:
      labels:
        app: local-test
    spec:
      containers:
      - name: test-container
        image: k8s.gcr.io/busybox
        command:
        - "/bin/sh"
        args:
        - "-c"
        - "sleep 100000"
        volumeMounts:
        - name: local-vol
          mountPath: /usr/test-pod
  volumeClaimTemplates:
  - metadata:
      name: local-vol
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "local-storage"
      resources:
        requests:
          storage: 368Gi

注意到這里volumeClaimTemplates.spec.storageClassNamelocal-storage,即我們一開始創建的storageclass實例的名字。

使用LPV的pod的調度流程

上面這個statefulset創建后,控制器會為其創建對應的PVC,并且會為PVC查找符合條件的PV,但是由于我們在local-storage中配置了WaitForFirstConsumer,所以控制器不會處理pvc和pv的bind;

同時,調度器在調度該pod時,predicate算法中也會根據PVC的要求去找到可用的PV,并且會過濾掉“與LPV的affinity”不匹配的node。最終,調度器發現:

pv:example-pv滿足了pvc的要求;

node:example-node滿足了pv:example-pv的nodeAffinity要求。

于是乎調度器嘗試將pv和pvc bind起來,并且對pod進行重新調度。

重新調度pod時調度器發現pod的pvc資源得到了滿足(都bound了pv),且bound的pv的nodeAffinity與node:example-node匹配。于是將pod調度到node:example-node上。完成調度。

如何創建LPV

在機器上創建目錄: mkdir -p /mnt/disks/ssd1

在機器上執行命令,將某個卷掛載到該目錄:mount -t /dev/vdc /mnt/disks/ssd1

在集群中創建對應的storageClass. 參見上文。

手動創建本地卷的PV,或者通過provisioner去自動創建。手動創建的模板見上文。

如何刪除LPV

對于已經被bind并被pod使用的LPV,刪除一定要按照流程來 , 要不然會刪除失敗:

刪除使用這個pv的pod

從node上移除這個磁盤(按照一個pv一塊盤)

刪除pvc

刪除pv

LPV延遲綁定部分的代碼解讀

所有的關鍵在于volumeBinder這個結構,它繼承了SchedulerVolumeBinder接口,包括:

type SchedulerVolumeBinder interface {
    FindPodVolumes(pod *v1.Pod, node *v1.Node) 
    AssumePodVolumes(assumedPod *v1.Pod, nodeName string) 
    BindPodVolumes(assumedPod *v1.Pod) error
    GetBindingsCache() PodBindingCache
}
FindPodVolumes

了解調度器原理的應該知道,調度器的predicate算法,在調度pod時,會逐個node的去進行predicate,以確認這個node是否可以調度。我們稱之為預選階段。

VolumeBindingChecker 是一個檢查器,在調度器的算法工廠初始化的最后一步,會向工廠中注冊檢查算法,這樣調度器在進行predicate時,最后一步會執行對volumeBinding的檢查。我們看func (c *VolumeBindingChecker) predicate 方法就能看到,這里面執行了FindPodVolumes,并且判斷返回的幾個值是否為true,或err是否為空:

unboundSatisfied, boundSatisfied, err := c.binder.Binder.FindPodVolumes(pod, node)

boundSatisfied 為false表示pod綁定的pv 與當前計算的node親和性不過關。
unboundSatisfied 為false表示pod中申明的未bound的pvc,在集群內的pv中找不到可以匹配的。

就這樣,調度器會反復去重試調度,反復執行FindPodVolumes,直到我們(或者provisoner)創建出了PV,比如這時新建的PV,其nodeAffinity對應到了node A。這次調度,在對node A進行predicate計算時,發現pod中申明的、未bound的pvc,在集群中有合適的pv,且該pv的nodeAffinity就是node A,于是返回的unboundSatisfied為 true, 調度器最終找到了一個合適的node。

那么,調度器接下來要對pod執行assume,在對pod assume之前,調度器要先對pod中bind的volume進行assume。見func (sched *Scheduler) assumeAndBindVolumes(assumed *v1.Pod, host string) error 。這個函數里,我們調用了volumeBinderAssumePodVolumes方法。

AssumePodVolumes

assume是假設的意思,顧名思義,這個方法會先在調度器的緩存中,假定pod已經調度到node A上,對緩存中的pv、pvc、binding等資源進行更新,看是否能成功,它會返回一些訊息:

allBound, bindingRequired, err := sched.config.VolumeBinder.Binder.AssumePodVolumes(assumed, host)

allBound 為true表示所有的pv、pvc,在緩存中已經是bind。如果為false,會最終導致本次調度失敗。
bindingRequired 為true表示有一些pv需要和pvc bind起來。如果為true,調度器會向volumeBinderBindQueue中寫入一個用例。這個隊列會被一個worker輪詢,并進行對應的工作。

什么工作呢? BindPodVolumes

BindPodVolumes

調度器在Run起來的時候,會啟動一個協程,反復執行bindVolumesWorker。在這個worker中我們可以看到,他嘗試從volumeBinderBindQueue中取出任務,進行BindPodVolumes,成功則該任務Done,失敗則報錯重試。

閱讀BindPodVolumes這個方法,很簡單,從緩存中找到對應的pod、pv、pvc等內容,更新到APIserver中。

由于我們在AssumePodVolumes中已經更新了緩存,所以這里更新到apiserver的操作,會真正地將pv和pvc bind起來。

之后呢?

在worker中我們看到,如果BindPodVolumes成功,依然會構造一個pod調度失敗的事件,并更新pod的狀態為PodScheduled,這么做是為了將pod放回調度隊列,讓調度器再去調度一次。

我們假設pod中只申明了一個LPV,在剛剛描述的這次BindPodVolumes操作中已經在apiserver中對這個LPV,和pod中的pvc進行了bind。那么,下一次調度器調度pod時,在AssumePodVolumes時會發現已經allBound ,調度器會繼續后續的操作,最終pod被成功地調度(創建出Binding資源,apiserver將pod的nodeName更新)。

pv控制器不管嗎?

創建PVC后,pv控制器會有一個worker:syncUnboundClaim去管理未bind的pvc。這個worker中,對于spec.VolumeName不為空的pvc,會去進行bind操作,確保pv和pvc綁定起來;對于spec.VolumeName為空的pvc,會去檢查是否延遲綁定,并查找集群中適合該pvc的pv(這里沒有node的概念,所以在查找時更多地是根據selector和AccessModes去過濾)。可以在

func findMatchingVolume(
    claim *v1.PersistentVolumeClaim,
    volumes []*v1.PersistentVolume,
    node *v1.Node,
    excludedVolumes map[string]*v1.PersistentVolume,
    delayBinding bool) (*v1.PersistentVolume, error)

中找到過濾的邏輯。這里我們只要知道:對于延遲綁定的pvc,我們會過濾掉所有的pv,并最后發出一個WaitForFirstConsumer的event結束worker。

可見,pv控制器對于延遲調度的pvc放任自流了。我們在findMatchingVolume方法中也可以看到官方的一段注釋:

if node == nil && delayBinding {
    // PV controller does not bind this claim.
    // Scheduler will handle binding unbound volumes
    // Scheduler path will have node != nil
    continue
}
總結本地盤的使用流程

待補充: pv控制器、CSI的工作機制

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/33183.html

相關文章

  • 深入淺出聊聊Kubernetes存儲(二):搞定持久化存儲

    摘要:這與不同,因為將繼續存在于系統中,直到用戶刪除它。和持久卷聲明之間很容易弄混淆。該在直接和使用前必須已經存在。這對于需要持久化儲存但只有本地卷可用的工作負載,這非常有用。此外,由于缺少,會失去使用自動伸縮的能力。 showImg(https://segmentfault.com/img/remote/1460000017071596?w=1920&h=1080); 回 顧 在本系列...

    韓冰 評論0 收藏0
  • Kubernetes 1.14 正式發布,Windows節點生產級支持!

    摘要:此次新版的最重大更新無疑為對節點的生產級支持。持久化本地存儲的最主要用例是分布式文件系統和數據庫,主要是由于性能和成本的原因。在裸機上,除了性能之外,本地存儲通常也更便宜,并且使用它是配置分布式文件系統的必要條件。 Kubernetes 1.14現已正式發布,這是Kubernetes在2019年的首次更新! Kubernetes 1.14由31個增強功能組成:10個功能現進入Stabl...

    wean 評論0 收藏0
  • 通過一個例子學習Kubernetes里的PersistentVolumeClaim的用法

    摘要:的本身是無狀態的生命周期通常比較短,只要出現了異常,就會自動創建一個新的來代替它。為了實現內數據的存儲管理,引入了兩個資源持久卷,以下簡稱和持久卷申請,以下簡稱。跟里的卷類似,不過會有獨立于的生命周期。 Kubernetes的pod本身是無狀態的(stateless),生命周期通常比較短,只要出現了異常,Kubernetes就會自動創建一個新的Pod來代替它。 而容器產生的數據,會隨著...

    mindwind 評論0 收藏0
  • 通過一個例子學習Kubernetes里的PersistentVolumeClaim的用法

    摘要:的本身是無狀態的生命周期通常比較短,只要出現了異常,就會自動創建一個新的來代替它。為了實現內數據的存儲管理,引入了兩個資源持久卷,以下簡稱和持久卷申請,以下簡稱。跟里的卷類似,不過會有獨立于的生命周期。 Kubernetes的pod本身是無狀態的(stateless),生命周期通常比較短,只要出現了異常,Kubernetes就會自動創建一個新的Pod來代替它。 而容器產生的數據,會隨著...

    Rindia 評論0 收藏0
  • 通過一個例子學習Kubernetes里的PersistentVolumeClaim的用法

    摘要:的本身是無狀態的生命周期通常比較短,只要出現了異常,就會自動創建一個新的來代替它。為了實現內數據的存儲管理,引入了兩個資源持久卷,以下簡稱和持久卷申請,以下簡稱。跟里的卷類似,不過會有獨立于的生命周期。 Kubernetes的pod本身是無狀態的(stateless),生命周期通常比較短,只要出現了異常,Kubernetes就會自動創建一個新的Pod來代替它。 而容器產生的數據,會隨著...

    Bamboy 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<