K8S原來如此簡單(七)儲存

語言: CN / TW / HK

emptyDir臨時卷

有些應用程式需要額外的儲存,但並不關心資料在重啟後仍然可用。

例如,快取服務經常受限於記憶體大小,將不常用的資料轉移到比記憶體慢、但對總體效能的影響很小的儲存中。

再例如,有些應用程式需要以檔案形式注入的只讀資料,比如配置資料或金鑰。

臨時卷就是為此類用例設計的。因為卷會遵從 Pod 的生命週期,與 Pod 一起建立和刪除, 所以停止和重新啟動 Pod 時,不會受持久卷在何處可用的限制。

下面我們就通過一個臨時卷,讓一個pod中的兩個容器實現檔案共享。

apiVersion: v1 
kind: Pod 
metadata: 
 name: emptydirpod 
 namespace: chesterns
spec: 
 containers: 
 - name: writeinfo 
   image: centos 
   command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"] 
   volumeMounts: 
   - name: data 
     mountPath: /data 
 - name: readinfo
   image: centos 
   command: ["bash","-c","tail -f /data/hello"] 
   volumeMounts: 
   - name: data 
     mountPath: /data 
 volumes: 
 - name: data 
   emptyDir: {} 

驗證

kubectl exec emptydirpod  -c readinfo -n chesterns -- cat /data/hello

hostPath卷

掛載Node檔案系統(Pod所在節點)上檔案或者目錄到Pod中的容器。通常用在Pod中容器需要訪問宿主機檔案的場景下。

下面通過一個yaml來實現hostPath卷

apiVersion: v1 
kind: Pod 
metadata: 
 name: hostpathpod 
 namespace: chesterns
spec: 
 containers: 
 - name: busybox 
   image: busybox 
   args: 
    - /bin/sh 
    - -c 
    - sleep 36000 
   volumeMounts: 
   - name: data 
     mountPath: /data 
 volumes: 
 - name: data 
   hostPath: 
    path: /tmp 
    type: Directory

驗證

kubectl  apply -f hostpath.yaml
kubectl exec hostpathpod -n chesterns -- ls /datals /tmp

網路卷NFS

NFS是一個主流的檔案共享伺服器。可以實現分散式系統中的檔案統一管理。

yum install nfs-utils -y #每個Node上都要安裝nfs-utils包

master上開啟nfs-server

#master
vi /etc/exports 
/tmp/chesternfs *(rw,fsid=0,no_root_squash) 

mkdir -p /tmp/chesternfs
systemctl start nfs 
systemctl enable nfs 

定義一個deployment,使用我們剛搭建的nfssever來掛載檔案

apiVersion: apps/v1 
kind: Deployment 
metadata: 
 name: nfsdeployment
 namespace: chesterns 
spec: 
 selector: 
  matchLabels: 
   app: nginx 
 replicas: 3 
 template: 
  metadata: 
   labels: 
    app: nginx 
  spec: 
   containers: 
   - name: nginx 
     image: nginx 
     volumeMounts: 
     - name: wwwroot 
       mountPath: /usr/share/nginx/html 
     ports: 
     - containerPort: 80 
   volumes: 
   - name: wwwroot 
     nfs: 
      server: 192.168.43.111 
      path: /tmp/chesternfs

通過新建一個a.html來驗證是不是掛載進了容器

vi /tmp/chesternfs/index.html/a.html
kubectl get pod -n chesterns
kubectl exec  nfsdeployment-f846bc9c4-s2598  -n chesterns -- ls /usr/share/nginx/html
curl 10.244.36.122/a.html

PV與PVC

我們可以將PV看作可用的儲存資源,PVC則是對儲存資源的需求,PV與PVC是為了方便我們對儲存資源進行系統的管理而誕生的,有了pv和pvc我們就可以對我們所有的儲存資源進行合理的分配。

pv的建立又分為靜態模式與動態模式。

靜態模式

叢集管理員手工建立許多PV,在定義PV時需要將後端儲存的特性進行設定。

定義PV,宣告需要5g空間

apiVersion: v1 
kind: PersistentVolume 
metadata: 
 name: chesterpv 
 namespace: chesterns
spec: 
 capacity: 
  storage: 5Gi 
 accessModes: 
 - ReadWriteMany 
 nfs: 
  path: /tmp/chesternfs 
  server: 192.168.43.111

AccessModes(訪問模式):

  • ReadWriteOnce(RWO):讀寫許可權,但是隻能被單個節點掛載

  • ReadOnlyMany(ROX):只讀許可權,可以被多個節點掛載

  • ReadWriteMany(RWX):讀寫許可權,可以被多個節點掛載

RECLAIM POLICY(回收策略):

通過pv的persistentVolumeReclaimPolicy欄位設定

  • Retain(保留):保留資料,需要管理員手工清理資料

  • Recycle(回收):清除 PV 中的資料,等同執行 rm -rf /tmp/chesternfs/*

  • Delete(刪除):與 PV 相連的後端儲存同時刪除

應用pv

kubectl apply -f pv.yaml
kubectl describe pv chesterpv -n chesterns

PVSTATUS(狀態):

  • Available(可用):表示可用狀態,還未被任何 PVC 繫結

  • Bound(已繫結):表示 PV 已經被 PVC 繫結

  • Released(已釋放):PVC 被刪除,但是資源還未被叢集重新宣告

  • Failed(失敗):表示該 PV 的自動回收失敗

下面我們定義pvc,設定一樣的儲存空間,繫結剛剛建好的pv

apiVersion: v1 
kind: PersistentVolumeClaim 
metadata: 
 name: chesterpvc
 namespace: chesterns
spec: 
 accessModes: 
 - ReadWriteMany 
 resources: 
  requests: 
   storage: 5Gi

應用pvc

kubectl apply -f pvc.yaml
kubectl describe pvc chesterpvc -n chesterns
kubectl describe pv chesterpv -n chesterns

使用PVC,我們定義一個pod,指定掛載用的pvc

apiVersion: v1 
kind: Pod 
metadata: 
 name: chesterpvcpod 
 namespace: chesterns
spec: 
 containers: 
 - name: nginx 
   image: nginx:latest 
   ports: 
   - containerPort: 80 
   volumeMounts: 
   - name: www 
     mountPath: /usr/share/nginx/html 
 volumes: 
 - name: www 
   persistentVolumeClaim: 
    claimName: chesterpvc

通過以下命令應用,並驗證

kubectl apply -f pvcpod.yaml
kubectl describe pod chesterpvcpod -n chesterns
kubectl describe pvc chesterpvc -n chesterns
kubectl describe pv chesterpv -n chesterns

curl 10.244.36.123/a.html

動態模式

動態模式可以解放叢集管理員,叢集管理員無須手工建立PV,而是通過StorageClass的設定對後端儲存進行描述,標記為某種型別。此時要求PVC對儲存的型別進行宣告,系統將自動完成PV的建立及與PVC的繫結。PVC可以宣告Class為"",說明該PVC禁止使用動態模式。

K8s需要安裝外掛支援NFS動態供給。

專案地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/tree/master/deploy

下載並安裝,需要修改其中的namespace為我們自己的chesterns

kubectl apply -f nfs-rbac.yaml # 授權訪問apiserver 
kubectl apply -f nfs-deployment.yaml # 部署外掛,需修改裡面NFS伺服器地址與共享目錄 
kubectl apply -f nfs-class.yaml # 建立儲存類 

下面我們定義pvc繫結我們剛建的storageclass,並且新建一個pod使用我們新建的這個pvc

apiVersion: v1 
kind: PersistentVolumeClaim 
metadata: 
 name: chesterscpvc
 namespace: chesterns
spec: 
 storageClassName: "nfs-client" 
 accessModes: 
 - ReadWriteMany 
 resources: 
  requests: 
   storage: 1Gi 
--- 
apiVersion: v1 
kind: Pod 
metadata: 
 name: chesterpvcscpod
 namespace: chesterns 
spec: 
 containers: 
 - name: chesterpvcscpod
   image: nginx 
   volumeMounts: 
   - name: nfs-pvc 
     mountPath: "/usr/share/nginx/html" 
 volumes: 
 - name: nfs-pvc 
   persistentVolumeClaim: 
    claimName: chesterscpvc

驗證

kubectl exec chesterpvcscpod  -n chesterns -- touch /usr/share/nginx/html/aa
ll /tmp/chesternfs/

ConfigMap

ConfigMap 是一種配置資源,用來將非機密性的資料儲存到etcd鍵值對中。使用時,Pods可以將其用作環境變數、命令列引數或者儲存卷中的配置檔案。

下面就來實現一個簡單的ConfigMap使用案例

定義ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
  namespace: chesterns
data:
  # 類屬性鍵;每一個鍵都對映到一個簡單的值
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # 類檔案鍵
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5    
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true 

通過kubectl apply應用後,開始在pod中使用

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo-pod
  namespace: chesterns
spec:
  containers:
    - name: demo
      image: alpine
      command: ["sleep", "3600"]
      env:
        # 定義環境變數
        - name: PLAYER_INITIAL_LIVES # 請注意這裡和 ConfigMap 中的鍵名是不一樣的
          valueFrom:
            configMapKeyRef:
              name: game-demo           # 這個值來自 ConfigMap
              key: player_initial_lives # 需要取值的鍵
        - name: UI_PROPERTIES_FILE_NAME
          valueFrom:
            configMapKeyRef:
              name: game-demo
              key: ui_properties_file_name
      volumeMounts:
      - name: config
        mountPath: "/config"
        readOnly: true
  volumes:
    # 你可以在 Pod 級別設定卷,然後將其掛載到 Pod 內的容器中
    - name: config
      configMap:
        # 提供你想要掛載的 ConfigMap 的名字
        name: game-demo
        # 來自 ConfigMap 的一組鍵,將被建立為檔案
        items:
        - key: "game.properties"
          path: "game.properties"
        - key: "user-interface.properties"
          path: "user-interface.properties"

驗證

kubectl apply -f configmap.yaml
kubectl apply -f configmappod.yaml

Secret

Secret 類似於ConfigMap但專門用於儲存機密資料。下面定義一個secret

apiVersion: v1
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm
kind: Secret
metadata:
  name: mysecret
  namespace: chesterns

應用secret

kubectl apply -f secret.yaml
kubectl get secret -n chesterns

在Pod中使用Secret

apiVersion: v1
kind: Pod
metadata:
  name: mypod
  namespace: chesterns
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret

驗證

kubectl apply -f secretpod.yaml
kubectl get pod -n chesternskubectl exec mypod  -n chesterns -- ls /etc/foo