Kubernetes之存儲


存儲卷概述

容器磁盤上的文件的生命周期是短暫的,這就使得在容器中運行重要應用時會出現一些問題。首先,當容器崩潰時,kubelet 會重啟它,但是容器中的文件將丟失——容器以干凈的狀態(鏡像最初的狀態)重新啟動。其次,在 Pod 中同時運行多個容器時,這些容器之間通常需要共享文件。Kubernetes 中的 Volume 抽象就很好的解決了這些問題。在原docker環境中也有存儲卷的概念,但docker環境的存儲卷調度在宿主機上的目錄,當docker重新創建的時候存儲卷還會掛載統一宿主機上,但我們知道Kubernetes是分布式集群,當我們銷毀一個pod的時候,可能pod會在其他節點上啟動,但其他節點宿主機上並沒有這個目錄,這樣就不會掛載到原來的數據了。為此Kubernetes不同類型的持久卷。

我們可以通過kubectl explain pods.spec.volumes來查看支持的存儲卷:

  • hostPath  主機目錄
  • emptyDir  空目錄(pod銷毀也隨之銷毀)
  • rbd    分布式存儲之ceph塊存儲
  • local   卷表示掛載的本地存儲設備,如磁盤、分區或目錄
  • cephfs   分布式存儲之cephfs
  • awsElasticBlockStore  aws雲存儲
  • azureDisk   azure雲存儲
  • azureFile   azure雲存儲
  • glusterfs   分布式存儲之glusterfs
  • downwardAPI   卷用於使向下 API 數據(downward API data)對應用程序可用。它掛載一個目錄,並將請求的數據寫入純文本文件。
  • cinder   OpenStack 塊存儲
  • configMap   配置中心
  • fc  卷允許將現有的 fc 卷掛載到 pod 中。您可以使用卷配置中的 targetWWN 參數指定單個或多個目標全球通用名稱(World Wide Name)。如果指定了多個 WWN,則 targetWWN 期望這些 WWN 來自多路徑連接。
  • flexVolume 抽象的存儲服務,存儲服務的管理軟件
  • flocker  是一款開源的集群容器數據卷管理器。它提供了由各種存儲后端支持的數據卷的管理和編排。
  • gcePersistentDisk   谷歌雲上
  • gitRepo  卷是一個可以演示卷插件功能的示例。它會掛載一個空目錄並將 git 存儲庫克隆到您的容器中。
  • iscsi  iscsi 卷允許將現有的 iSCSI卷掛載到容器中。不像 emptyDir,刪除 Pod 時 iscsi 卷的內容將被保留,卷僅僅是被卸載。這意味着 iscsi 卷可以預先填充數據,並且這些數據可以在 pod 之間“切換”。
  • nfs   nfs Nas存儲
  • persistentVolumeClaim 卷用於將 PersistentVolume 掛載到容器中。PersistentVolumes 是在用戶不知道特定雲環境的細節的情況下“聲明”持久化存儲(例如 GCE PersistentDisk 或 iSCSI 卷)的一種方式。
  • photonPersistentDisk
  • portworxVolume  是一個與 Kubernetes 一起,以超融合模式運行的彈性塊存儲層
  • projected 卷將幾個現有的卷源映射到同一個目錄中
  • quobyte  卷允許將現有的 Quobyte 卷掛載到容器中。
  • scaleIO  ScaleIO 是一個基於軟件的存儲平台,可以使用現有的硬件來創建可擴展的共享塊網絡存儲集群
  • secret   加密文件
  • storageos  動態存儲
  • vsphereVolume 配置了 vSphere Cloud Provider 的 Kubernetes

 emptyDir

 kubectl explain pod.spec.volumes.emptyDir  指定emptyDir存儲卷

  • medium   指定媒介類型   disk  Memory 兩種
  • sizeLimit  現在資源使用情況

kubectl explain pod.spec.containers.volumeMounts  指定掛載哪些存儲卷

  • mountPath   掛載那個路徑
  • name 指定掛載的volumes名稱
  • readOnly   是否只讀掛載
  • subPath   是否掛載子路徑

下面實例為 一個pod中的兩個容器共享同一個存儲

apiVersion: v1
kind: Pod
metadata:
  name: my-demo
  namespace: default
  labels:
    name: myapp
    tier: appfront
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: appindex
      mountPath: /usr/share/nginx/html/
  - name: busybox
    image: busybox
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: appindex
      mountPath: /data/
    command:
    - "/bin/sh"
    - "-c"
    - "while true; do echo $(date) >> /data/index.html; sleep 2; done"
  volumes:
  - name: appindex
    emptyDir: {}

驗證

curl 10.244.3.14
Mon Sep 17 06:03:53 UTC 2018
Mon Sep 17 06:03:55 UTC 2018
Mon Sep 17 06:03:57 UTC 2018
Mon Sep 17 06:03:59 UTC 2018
Mon Sep 17 06:04:01 UTC 2018
Mon Sep 17 06:04:03 UTC 2018

 

hostPath

 kubectl explain pod.spec.volumes.hostPath

  • path  指定宿主機的路徑
  • type  DirectoryOrCreate  宿主機上不存在創建此目錄  Directory 必須存在掛載目錄  FileOrCreate 宿主機上不存在掛載文件就創建  File 必須存在文件  

 目錄自動創建

apiVersion: v1
kind: Pod
metadata:
  name: my-demo
  namespace: default
  labels:
    name: myapp
    tier: appfront
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: appindex
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: appindex
    hostPath:
      path: /data/pod/myapp
      type: DirectoryOrCreate

 NFS

kubectl explain pod.spec.volumes.nfs

  • path 源目錄
  • readOnly  是否只讀  默認false
  • server  NFS服務地址
apiVersion: v1
kind: Pod
metadata:
  name: my-demo-nfs
  namespace: default
  labels:
    name: myapp
    tier: appfront
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: appindex
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: appindex
    nfs:
      server: 172.16.132.241
      path: /data

手動在/data目錄下增加一個index.html

驗證

kubectl get pods -o wide 
NAME                          READY     STATUS    RESTARTS   AGE       IP            NODE
my-demo                       1/1       Running   0          3h        10.244.2.4    k8s-node02
my-demo-nfs                   1/1       Running   0          2m        10.244.3.15   k8s-node03

$ curl 10.244.3.15
nfs

PVC如何使用的

我們前面提到kubernetes提供那么多儲存接口,但是首先kubernetes的各個Node節點能管理這些存儲,但是各種存儲參數也需要專業的存儲工程師才能了解,由此我們的kubernetes管理變的更加復雜的。由此kubernetes提出了PV和PVC的概念,這樣開發人員和使用者就不需要關注后端存儲是什么,使用什么參數等問題。如下圖:

 

 當我們pod中定義volume的時候,我們只需要使用pvs存儲卷就可以,pvc必須與對應的pv建立關系,pvc會根據定義去pv申請,而pv是由存儲空間創建出來的。pv和pvc是kubernetes抽象出來的一種存儲資源。

PV介紹:

PersistentVolume 是由管理員設置的存儲,它是群集的一部分。就像節點是集群中的資源一樣,PV 也是集群中的資源。 PV 是 Volume 之類的卷插件,但具有獨立於使用 PV 的 Pod 的生命周期。此 API 對象包含存儲實現的細節,即 NFS、iSCSI 或特定於雲供應商的存儲系統。可根據上圖看清他們之間的關系

PV有兩種配置方式:動態和靜態

靜態:

集群管理員創建一些 PV。它們帶有可供群集用戶使用的實際存儲的細節。

動態:

當管理員創建的靜態 PV 都不匹配用戶的 PersistentVolumeClaim 時,集群可能會嘗試動態地為 PVC 創建卷。此配置基於 StorageClasses:PVC 必須請求存儲類,並且管理員必須創建並配置該類才能進行動態創建。聲明該類為 "" 可以有效地禁用其動態配置。

要啟用基於存儲級別的動態存儲配置,集群管理員需要啟用 API server 上的 DefaultStorageClass 准入控制器。例如,通過確保 DefaultStorageClass 位於 API server 組件的 --admission-control 標志,使用逗號分隔的有序值列表中,可以完成此操作。

 kubectl explain pv.spec

  • accessModes   訪問模式
  1. ReadWriteOnce(RWO)  單節點讀寫
  2. ReadOnlyMany(ROX)  多節點只讀
  3. ReadWriteMany(RWX)  多節點讀寫
  • capacity  定義pv使用多少資源

定義一個nfs格式的pv

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv01
  labels:
    name: pv01
spec:
  nfs:
    path: /data/pv/01
    server: 172.16.132.241
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv02
  labels:
    name: pv02
spec:
  nfs:
    path: /data/pv/02
    server: 172.16.132.241
  accessModes: ["ReadOnlyMany","ReadWriteOnce"]
  capacity:
    storage: 5Gi

查看詳細

kubectl get pv 
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
pv01      2Gi        RWO,RWX        Retain           Available                                      1m
pv02      5Gi        RWO,ROX        Retain           Available                                      1m

回收策略(RECLAIM POLICY

當pod結束 volume 后可以回收資源對象刪除PVC,而綁定關系就不存在了,當綁定關系不存在后這個PV需要怎么處理,而PersistentVolume 的回收策略告訴集群在存儲卷聲明釋放后應如何處理該卷。目前,volume 的處理策略有保留、回收或刪除。

保留:

此策略允許手動回收資源,當pvc被刪除后,pv依然存在,volume 被視為“已釋放”。但是由於前一個聲明人的數據仍然存在,所以還不能馬上進行其他聲明。管理員可以通過以下步驟手動回收卷。

  • 刪除 PV。在刪除 PV 后,外部基礎架構中的關聯存儲空間(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)仍然存在。
  • 手動清理相關存儲空間上的數據
  • 手動刪除關聯的存儲空間,或者如果要重新使用相同的存儲空間,請使用存儲空間定義創建新的 PersistentVolume

回收:

在 volume上執行情況數據(rm -rf /thevolume/*),可以再次被其他pvc調度

刪除:

對於支持刪除回收策略的卷插件,刪除操作將從 Kubernetes 中刪除 PV 對象,並刪除外部基礎架構(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中的關聯存儲空間。動態配置的卷繼承其 StorageClass 的回收策略,默認為 Delete。管理員應該根據用戶的期望來配置 StorageClass,否則就必須要在 PV 創建后進行編輯或修補。

PVC介紹:

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

雖然 PersistentVolumeClaims 允許用戶使用抽象存儲資源,但用戶需要具有不同性質(例如性能)的 PersistentVolume 來解決不同的問題。集群管理員需要能夠提供各種各樣的 PersistentVolume,這些PersistentVolume 的大小和訪問模式可以各有不同,但不需要向用戶公開實現這些卷的細節。對於這些需求,StorageClass 資源可以實現。可根據上圖看清他們之間的關系

kubectl  explain pvc.spec

  • accessModes 訪問模式  是遞延pv的accessModes的子集,例如:pv中accessModes 定義["ReadWriteMany","ReadWriteOnce"],pvc中的也只能定義["ReadWriteMany","ReadWriteOnce"] 或其中的一個。
  • resources  資源限制
  • selector  標簽選擇器
  • storageClassName  動態存儲名稱
  • volumeMode  后端存儲卷的模式
  • volumeName  指定卷(pv)的名稱

定義pvc資源對象

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: my-demo-pvc
  namespace: default
  labels:
    name: myapp
    tier: appfront
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: appindex
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: appindex
    persistentVolumeClaim:
      claimName: mypvc

查看

$ kubectl get pv 
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM           STORAGECLASS   REASON    AGE
pv02      5Gi        RWO,ROX        Retain           Bound     default/mypvc                            1h
$ kubectl describe pod my
-demo-pvc Name: my-demo-pvc Namespace: default Priority: 0 PriorityClassName: <none> Node: k8s-node02/172.16.138.42 Start Time: Thu, 20 Sep 2018 05:23:04 -0400 Labels: name=myapp tier=appfront Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"name":"myapp","tier":"appfront"},"name":"my-demo-pvc","namespace":"default"},"s... Status: Running IP: 10.244.2.6 Containers: myapp: Container ID: docker://6727e1b45fba703f98d7a11f16a60706b8f5c2925026707b412c13ef80f5ac52 Image: ikubernetes/myapp:v1 Image ID: docker-pullable://ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513 Port: 80/TCP Host Port: 0/TCP State: Running Started: Thu, 20 Sep 2018 05:23:06 -0400 Ready: True Restart Count: 0 Environment: <none> Mounts: /usr/share/nginx/html/ from appindex (rw) /var/run/secrets/kubernetes.io/serviceaccount from default-token-lplp6 (ro) ......

StorageClass介紹

當pvc申請的時候不一定有滿足pvc要求的pv,那怎么辦呢?kubernetes為 為管理員提供了描述存儲 "class(類)" 的方法(StorageClass)。例如存儲工程給划分一個1TB的存儲空間供kubernetes使用,當用戶需要一個10G的pvc的時候會立即通過restful的請求到存儲空間創建一個10G的images,之后在我們的集群中定義成10G的pv給當前pvc作為掛載使用。如下圖:

ConfigMap

configmap是讓配置文件從鏡像中解耦,讓鏡像的可移植性和可復制性。許多應用程序會從配置文件、命令行參數或環境變量中讀取配置信息。這些配置信息需要與docker image解耦,你總不能每修改一個配置就重做一個image吧?ConfigMap API給我們提供了向容器中注入配置信息的機制,ConfigMap可以被用來保存單個屬性,也可以用來保存整個配置文件或者JSON二進制大對象。

ConfigMap API資源用來保存key-value pair配置數據,這個數據可以在pods里使用,或者被用來為像controller一樣的系統組件存儲配置數據。雖然ConfigMap跟Secrets類似,但是ConfigMap更方便的處理不含敏感信息的字符串。

注意:ConfigMaps不是屬性配置文件的替代品。ConfigMaps只是作為多個properties文件的引用。你可以把它理解為Linux系統中的/etc目錄,專門用來存儲配置文件的目錄。下面舉個例子,使用ConfigMap配置來創建Kuberntes Volumes,ConfigMap中的每個data項都會成為一個新文件。

詳解

kubectl explain cm

  • data    傳遞數據
  • binaryData  使用二進制傳遞數據

如果臨時使用可以使用命令行創建  kubectl create cm --help

$ kubectl create cm nginx-conf  --from-literal=nginx_port=80 --from-literal=server_name=myapp.jaxzhai.com  
configmap/nginx-conf created
$ kubectl get cm
NAME         DATA      AGE
nginx-conf   2         31

通過配置文件創建

$ kubectl create cm nginx-jax --from-file=./jax.conf
configmap/nginx-jax created

引用configmap

kubectl explain pod.spec.containers.env.valueFrom.configMapKeyRef

  • key    引用那個confmap中的key
  • name  引用那個confmap
  • optional  如果沒有這個key就可以忽略

 

apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-1
  namespace: default
  labels:
    app: myapp
    tier: test
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    env:
    - name: NGINX_SERVER_PORT
      valueFrom:
        configMapKeyRef:
          name: nginx-conf
          key: nginx_port
    - name: NGINX_SERVER_NAME
      valueFrom:
        configMapKeyRef:
           name: nginx-conf
           key: server_name

查看

kubectl exec -it pod-cm-1 -- /bin/sh 
/ # printenv 
MYAPP_SVC_PORT_80_TCP_ADDR=10.98.57.156
KUBERNETES_SERVICE_PORT=443
MYAPP_SERVICE_PORT_HTTP=80
KUBERNETES_PORT=tcp://10.96.0.1:443
MYAPP_SVC_PORT_80_TCP_PORT=80
HOSTNAME=pod-cm-1
SHLVL=1
MYAPP_SVC_PORT_80_TCP_PROTO=tcp
HOME=/root
MYAPP_SERVICE_HOST=10.100.51.12
NGINX_SERVER_PORT=80
NGINX_SERVER_NAME=myapp.jaxzhai.com
.....

 存儲卷掛載的方式

apiVersion: v1
kind: Pod
metadata:
  name: pod-cm-2
  namespace: default
  labels:
    app: myapp
    tier: test
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: nginxconfig
      mountPath: /etc/nginx/config.d/
      readOnly: true
  volumes:
  - name: nginxconfig
    configMap: 
      name: nginx-conf

 

Secret

Secret解決了密碼、token、密鑰等敏感數據的配置問題,而不需要把這些敏感數據暴露到鏡像或者Pod Spec中。Secret可以以Volume或者環境變量的方式使用。

Secret有三種類型:

  • Service Account :用來訪問Kubernetes API,由Kubernetes自動創建,並且會自動掛載到Pod的/run/secrets/kubernetes.io/serviceaccount目錄中;
  • Opaque :base64編碼格式的Secret,用來存儲密碼、密鑰等;
  • kubernetes.io/dockerconfigjson用來存儲私有docker registry的認證信息

 創建密鑰有三種方式:

  • docker-registry:創建倉庫登錄密鑰
  • generic: 通用的創建方式
  • tls: 創建加密證書的方式

創建一個通用類型密鑰

用法:
kubectl create secret generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]
創建一個mysql的root密碼:
$ kubectl create secret generic mysql-root-password --from-literal=password=123456
secret/mysql-root-password created
查看
$ kubectl get secret
NAME                         TYPE                                  DATA     AGE
mysql-root-password   Opaque                                1         30s
$ kubectl describe secret mysql-root-password
Name:         mysql-root-password
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  6 bytes   #我們看到這里只顯示6個字節

怎樣解密
首先獲得解密信息
$ kubectl get secret mysql-root-password -o yaml                    
apiVersion: v1
data:
  password: MTIzNDU2
kind: Secret
metadata:
  creationTimestamp: 2018-10-29T09:07:02Z
  name: mysql-root-password
  namespace: default
  resourceVersion: "6391111"
  selfLink: /api/v1/namespaces/default/secrets/mysql-root-password
  uid: ffccb84d-db59-11e8-b8c9-005056930126
type: Opaque

通過base64解碼
$ echo MTIzNDU2 | base64 -d
123456

 


免責聲明!

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



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