CKA認證 | Day7 K8s存儲

第七章 Kubernetes存儲

1、數據卷與數據持久卷

為什么需要數據卷?

容器中的文件在磁盤上是臨時存放的,這給容器中運行比較重要的應用程序帶來一些問題。

  1. 問題1:當容器升級或者崩潰時,kubelet會重建容器,容器內文件會丟失;

  2. 問題2:一個Pod中運行多個容器并需要共享文件;

Kubernetes 卷(Volume) 這一抽象概念能夠解決這兩個問題。

1.?數據持久化
  • 容器的無狀態性:Kubernetes 中的容器是無狀態的,這意味著它們在重啟或重新調度時,容器內的數據會丟失。
  • 持久化數據:通過使用數據卷,可以將數據持久化到外部存儲系統中,確保數據在容器生命周期外仍然存在。
2.?數據共享
  • 多容器共享數據:在某些情況下,同一個 Pod 中的多個容器需要共享數據。數據卷允許這些容器共享同一個存儲卷。
  • 跨容器協作:例如,一個容器生成日志文件,另一個容器需要讀取這些日志文件。
3.?數據隔離
  • 獨立存儲:不同的 Pod 可以使用不同的數據卷,確保數據隔離,避免數據沖突。
  • 安全性:通過將敏感數據存儲在獨立的數據卷中,可以提高安全性。
4.?簡化配置
  • 統一管理:使用數據卷可以簡化應用程序的配置,因為存儲配置可以在 Kubernetes 中集中管理。
  • 靈活性:可以根據需要選擇不同的存儲后端(如本地存儲、云存儲、網絡文件系統等),而不需要修改應用程序代碼。
5.?生命周期管理
  • 數據生命周期:數據卷可以獨立于 Pod 的生命周期管理,確保數據在 Pod 重啟或刪除后仍然可用。
  • 自動掛載:Kubernetes 可以自動掛載和卸載數據卷,簡化操作。

常用的數據卷:

官網:Volumes | Kubernetes

  • 節點本地存儲(hostPath,emptyDir)
  • 網絡存儲(NFS,Ceph,GlusterFS)
  • 公有云存儲(AWS EBS)
  • K8S資源存儲(configmap,secret)

1.1 臨時數據卷:emptyDir

emptyDir卷是一個臨時存儲卷,與Pod生命周期綁定一起,如果 Pod刪除了卷也會被刪除

應用場景:Pod中容器之間數據共享

選項:

  • sizeLimit:500Mi? ? ? ?//限制共享空間大小(比較少用)


示例:Pod內容器之間共享數據
apiVersion: v1
kind: Pod
metadata: name: emptydir-test
spec:containers:- name: write-container    //程序講數據寫入到文件image: centoscommand: ["bash","-c","for i in {1..100};do echo $i >> 
/data/hello;sleep 1;done"]volumeMounts:- name: data-volume    //通過volume卷名稱引用mountPath: /data- name: read-container     //程序從文件中讀取數據image: centoscommand: ["bash","-c","tail -f /data/hello"]volumeMounts:- name: data-volumemountPath: /datavolumes:      //定義卷的來源- name: data-volumeemptyDir: {}    //{}中為空值

驗證1:驗證容器之間是否能夠共享數據

[root@k8s-master-1-71 ~]# kubectl apply -f emptydir-test.yaml
[root@k8s-master-1-71 ~]# kubectl get pods
NAME            READY   STATUS    RESTARTS      AGE
emptydir-test   2/2     Running   1 (21s ago)   3m14s
# 進入write-container查看
[root@k8s-master-1-71 ~]# kubectl exec -it emptydir-test -- bash[root@emptydir-test /]# tail -f /data/hello
...
99
100
command terminated with exit code 137
[root@emptydir-test /]# touch /data/aaa ; ls /data/     //往容器中寫入臨時文件
aaa  hello## 注:腳本循環結束后退出容器,按照默認的策略Always進行容器重啟。
# 進入read-container查看
[root@k8s-master-1-71 ~]# kubectl exec -it emptydir-test -c read-container -- bash
[root@emptydir-test /]# ls /data/
aaa  hello

驗證2:實際存儲位置(基于節點的存儲)

補充:Kubelet的工作目錄為/var/lib/kubelet/,負載維護Pod數據的

[root@k8s-master-1-71 ~]# kubectl get pods -o wide
NAME            READY   STATUS    RESTARTS      AGE    IP              NODE             NOMINATED NODE   READINESS GATES
emptydir-test   2/2     Running   2 (45s ago)   5m3s   10.244.114.48   k8s-node2-1-73   <none>           <none># 根據查看到的Pod所在節點,找到相應的容器ID
[root@k8s-node2-1-73 ~]# docker ps | grep emptydir-test(例如:7c26307b-b290-4bac-9a3b-6f18ffc26776)
6deb6dc27ab2   centos                                              "bash -c 'for i in {…"   44 seconds ago   Up 43 seconds             k8s_write-container_emptydir-test_default_7c26307b-b290-4bac-9a3b-6f18ffc26776_3
7bb46657087b   centos                                              "bash -c 'tail -f /d…"   7 minutes ago    Up 7 minutes              k8s_read-container_emptydir-test_default_7c26307b-b290-4bac-9a3b-6f18ffc26776_0
fd4c6c671807   registry.aliyuncs.com/google_containers/pause:3.7   "/pause"                  7 minutes ago    Up 7 minutes              k8s_POD_emptydir-test_default_7c26307b-b290-4bac-9a3b-6f18ffc26776_0# 找到相關Pod關聯的empty-dir目錄,即可看到掛載的empty-dir目錄內容
[root@k8s-node2-1-73 kubernetes.io~empty-dir]# pwd
/var/lib/kubelet/pods/7c26307b-b290-4bac-9a3b-6f18ffc26776/volumes/kubernetes.io~empty-dir[root@k8s-node2-1-73 kubernetes.io~empty-dir]# ls data-volume/
aaa  bbb  hello

Pod是節點級別的,Pod中的容器都是捆綁在一個節點上,所以 Pod刪除了,卷也會被刪除

[root@k8s-master-1-71 ~]# kubectl delete -f emptydir-test.yaml
[root@k8s-node2-1-73 kubernetes.io~empty-dir]# ls data-volume/
ls: 無法訪問data-volume/: 沒有那個文件或目錄

1.2 節點數據卷:hostPath

hostPath卷掛載Node的文件系統(即Pod所在節點)上文件或者目 錄到Pod中的容器。

應用場景:Pod中容器需要訪問宿主機的文件

選項:

  • path:? ? //將宿主機的目錄或文件映射到容器中去

  • type:? ? //指定類型(目錄或文件)


示例:將宿主機/tmp目錄掛載到容器/data目錄
apiVersion: v1
kind: Pod
metadata:name: hostpath-test
spec:containers:- name: busyboximage: busyboxargs:- /bin/sh- -c- sleep 36000volumeMounts:- name: data-volumemountPath: /datavolumes:- name: data-volumehostPath:path: /tmp        //Pod所在節點的/tmp目錄type: Directory

驗證:

[root@k8s-master-1-71 ~]# kubectl apply -f hostpath-test.yaml[root@k8s-master-1-71 ~]# kubectl get pods -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP              NODE             NOMINATED NODE   READINESS GATES
hostpath-test   1/1     Running   0          86s   10.244.114.49   k8s-node2-1-73   <none>           <none># 查看Pod所在節點的/tmp目錄
[root@k8s-node2-1-73 ~]# ls /tmp/
systemd-private-85c79618aae44d7cbb01bccc046ecb10-chronyd.service-UMOhQf
systemd-private-fdf2b8d40ff841319feb738a463a8f6f-chronyd.service-GJT2Mn# 進入容器查看/data目錄是否有相關映射文件
[root@k8s-master-1-71 ~]# kubectl exec -it hostpath-test -- sh
/ # ls /data/
systemd-private-85c79618aae44d7cbb01bccc046ecb10-chronyd.service-UMOhQf
systemd-private-fdf2b8d40ff841319feb738a463a8f6f-chronyd.service-GJT2Mn

1.3 網絡數據卷:NFS

NFS:是一個主流的文件共享服務器(注:每個Node上都要安裝nfs-utils包)

# 服務端部署
[root@k8s-node1-1-72 ~]# yum install -y nfs-utils
[root@k8s-node1-1-72 ~]# vi /etc/exports     //NFS共享配置目錄
/ifs/kubernetes *(rw,no_root_squash)
# 解釋:
共享目錄 訪問來源限制(權限)
[root@k8s-node1-1-72 ~]# mkdir -p /ifs/kubernetes[root@k8s-node1-1-72 ~]# systemctl enable nfs --now# 客戶端測試
[root@k8s-node2-1-73 ~]# yum install -y nfs-utils
[root@k8s-node2-1-73 ~]# mount -t nfs 192.168.1.72:/ifs/kubernetes /mnt
[root@k8s-node2-1-73 ~]# df -Th | grep /ifs/kubernetes
192.168.1.72:/ifs/kubernetes nfs4       37G  4.3G   33G   12% /mnt

NFS卷:提供對NFS掛載支持,可以自動將NFS共享路徑 掛載到Pod中

選項:

  • server: //指定NFS地址

  • path: /指定NFS共享目錄


示例:將Nginx網站程序根目錄持久化到 NFS存儲,為多個Pod提供網站程序文件
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nfs-podname: nfs-pod
spec:selector:matchLabels:app: nginxreplicas: 3template:metadata:labels:app: nginxspec:containers:- name: webimage: nginxvolumeMounts:- name: data-volumemountPath: /usr/share/nginx/html    //掛載的目錄volumes:- name: data-volume      //volume卷名稱nfs:server: 192.168.1.72     //指定NFS地址path: /ifs/kubernetes    //NFS共享目錄

驗證1:容器之間的數據是否共享

[root@k8s-node2-1-73 ~]# kubectl apply -f nfs-pod.yaml
[root@k8s-master-1-71 ~]# kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGEnfs-pod-9b57f886-d8rzx   1/1     Running   0          10m
nfs-pod-9b57f886-tk99z   1/1     Running   0          55s
nfs-pod-9b57f886-wpr9q   1/1     Running   0          10m# 進入容器1,創建文件測試
[root@k8s-node2-1-73 ~]# kubectl exec -it nfs-pod-9b57f886-d8rzx -- bash
root@nfs-pod-9b57f886-d8rzx:/# df -Th |grep /ifs/kubernetes
192.168.1.72:/ifs/kubernetes nfs4      37G  4.3G   33G  12% /usr/share/nginx/html
root@nfs-pod-9b57f886-d8rzx:~# touch /usr/share/nginx/html/aaaaa
root@nfs-pod-9b57f886-d8rzx:~# ls /usr/share/nginx/html/
aaaaa# 進入容器2,查看文件
[root@k8s-node2-1-73 ~]# kubectl exec -it nfs-pod-9b57f886-tk99z -- bash
root@nfs-pod-9b57f886-tk99z:/# ls /usr/share/nginx/html/
aaaaa

驗證2:增加/刪除Pod是否能繼續使用共享存儲數據

# 刪除Pod,查看是否能繼續使用共享存儲數據
[root@k8s-master-1-71 ~]# kubectl delete pod nfs-pod-9b57f886-tk99z[root@k8s-master-1-71 ~]# kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
nfs-pod-9b57f886-d8rzx   1/1     Running   0          10m
nfs-pod-9b57f886-fg7n7   1/1     Running   0          55s    //新增Pod
nfs-pod-9b57f886-wpr9q   1/1     Running   0          10m[root@k8s-node2-1-73 ~]# kubectl exec -it nfs-pod-9b57f886-fg7n7 -- bash
root@nfs-pod-9b57f886-fg7n7:/# ls /usr/share/nginx/html/
aaaaa# 增加Pod,查看是否能繼續使用共享存儲數據
[root@k8s-master-1-71 ~]# kubectl scale deployment nfs-pod --replicas=5
[root@k8s-node2-1-73 ~]# kubectl exec -it nfs-pod-9b57f886-sj7m6 -- bash
root@nfs-pod-9b57f886-sj7m6:/# df -Th | grep /ifs/kubernetes
192.168.1.72:/ifs/kubernetes nfs4      37G  4.3G   33G  12% /usr/share/nginx/html
root@nfs-pod-9b57f886-sj7m6:/# ls /usr/share/nginx/html/
aaaaa

1.4 持久數據卷概述

持久卷(Persistent Volumes, PV) 是用于管理存儲的重要概念。

安全性:如果要設置安全方面的認證,都需要提前將安全配置寫入YAML,因此將會暴露在YAML文件中,導致安全性減低;

專業性:在應用的部署上,使用者對K8S、存儲的不了解,對于建設者來說,倡導職責上的分離。

1.4.1 PV、PVC

持久卷(Persistent Volumes, PV)

  • 定義:持久卷是集群中的一塊存儲,由管理員配置和管理。它們獨立于 Pod 的生命周期,可以被多個 Pod 使用。
  • 生命周期:持久卷的生命周期獨立于 Pod,即使 Pod 被刪除,數據仍然保留。

對存儲資源創建和使用的抽象,使得存儲作為集群中的資源管理(定義后端存儲)

持久卷聲明(Persistent Volume Claims, PVC)

  • 定義:持久卷聲明是用戶對持久卷的請求。用戶不需要了解底層存儲的細節,只需要聲明所需的存儲大小和訪問模式。
  • 生命周期:持久卷聲明的生命周期與 Pod 的生命周期無關,可以獨立存在。
  • 綁定:持久卷聲明會被綁定到一個滿足其請求的持久卷上。一旦綁定,PVC 和 PV 之間是一對一的關系。

讓用戶不需要關心具體的Volume實現細節(訪問模式、存儲容量大小)

Pod申請PVC作為卷來使用,Kubernetes通過PVC查找綁定的PV,并Mount給Pod。

支持持久卷的存儲插件:Persistent Volumes | Kubernetes

1.4.2 PV與PVC使用流程

官網:配置 Pod 以使用 PersistentVolume 作為存儲 | Kubernetes

PVC配置示例:

---   //容器應用
apiVersion: apps/v1
kind: Deployment
metadata: labels:app: my-podname: my-pod
spec:selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: webimage: nginxvolumeMounts:- name: data-volumemountPath: /usr/share/nginx/html    //掛載的目錄volumes:- name: data-volumepersistentVolumeClaim:claimName: my-pvc---   //PVC 卷需求模板
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: my-pvc      //與claimName對應進行關聯
spec:accessModes:- ReadWriteManyresources:requests:storage: 5Gi
  • 查看PVC命令:kubectl get pvc
[root@k8s-master-1-71 ~]# kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
my-pod-6fbc98b678-42m29   0/1     Pending   0          10s
[root@k8s-master-1-71 ~]# kubectl get pvc
NAME     STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
my-pvc   Pending                                                     18s

注意:如果沒有可用的PV,PVC無法進行資源分配會處于在Pending狀態

PV配置示例:

apiVersion: v1
kind: PersistentVolume
metadata:name: my-pv      //隨便定義
spec:capacity:storage: 5Gi     //后端存儲定義資源accessModes:- ReadWriteManynfs:path: /ifs/kubernetesserver: 192.168.1.72
  • 查看PV命令:kubectl get pv
[root@k8s-master-1-71 ~]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
my-pv   5Gi        RWX            Retain           Bound    default/my-pvc                           11s
[root@k8s-master-1-71 ~]# kubectl get pvc
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
my-pvc   Bound    my-pv    5Gi        RWX                           2m30s
[root@k8s-master-1-71 ~]# kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
my-pod-6fbc98b678-42m29   1/1     Running   0          3m5s

測試:

[root@k8s-master-1-71 ~]# kubectl exec -it my-pod-6fbc98b678-42m29 -- bash
root@my-pod-6fbc98b678-42m29:/# df -Th | grep /ifs/kubernetes
192.168.1.72:/ifs/kubernetes nfs4      37G  4.3G   33G  12% /usr/share/nginx/html
root@my-pod-6fbc98b678-42m29:/# ls /usr/share/nginx/html/
aaaaa

思考:多PV配置

掛載PV的時候,不能將掛載點掛到同一目錄,為保證應用的唯一性,需要在掛載點的節點上創建各自的目錄,避免沖突

多PV配置示例:

apiVersion: v1
kind: PersistentVolume
metadata:name: pv001      //隨便定義
spec:capacity:storage: 5Gi     //后端存儲定義資源accessModes:- ReadWriteManynfs:path: /ifs/kubernetes/pv001server: 192.168.1.72
---
apiVersion: v1
kind: PersistentVolume
metadata:name: pv002      //隨便定義
spec:capacity:storage: 15Gi     //后端存儲定義資源accessModes:- ReadWriteManynfs:path: /ifs/kubernetes/pv002server: 192.168.1.72

總結:

1、PV與PVC怎么匹配?

主要根據PVC的存儲容量訪問模式進行匹配

2、存儲容量怎么匹配?

容量只會向上匹配,如已有未使用PV有10G、20G,申請5G,向上取最近的PV容量10G

3、PV與PVC的關系?

一對一,存在綁定關系

4、容量請求是否有實際的限制?

目前容量請求主要用作于PVC與PV進行匹配的,只是抽象的存在,而具體的限制取決于后端存儲,即請求容量不能超過共享存儲的實際容量

1.4.3 PV 生命周期

1)AccessModes(訪問模式):

AccessModes 是用來對 PV 進行訪問模式的設置,用于描述用戶應用對存儲資源的訪問權限,訪問權限包括下面幾種方式:

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

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

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

備注:塊存儲(單節點)、文件系統、對象存儲(多節點)

2)RECLAIM POLICY(回收策略):

目前 PV 支持的策略有三種:

  • Retain(保留): 保留數據,需要管理員手工清理數據(默認策略)

  • Recycle(回收):清除 PV 中的數據,效果相當于執行 rm -rf /ifs/kuberneres/*(一般結合StorageClass使用,NFS暫時無法看出效果)

  • Delete(刪除):與 PV 相連的后端存儲同時刪除(一般結合StorageClass使用,NFS暫時無法看出效果)

persistentVolumeReclaimPolicy: 回收策略

3)STATUS(狀態):

一個 PV 的生命周期中,可能會處于4中不同的階段:

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

  • Bound(已綁定):表示 PV 已經被 PVC 綁定

  • Released(已釋放):PVC 被刪除,但是資源還未被集群重新聲明

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


示例:觀察回收狀態和默認的Retain回收策略
[root@k8s-master-1-71 ~]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
my-pv   5Gi        RWX            Retain           Bound    default/my-pvc                           7h7m## 解釋:目前回收策略為 Retain ,狀態為 Bound(表示 PV 已經被 PVC 綁定)
[root@k8s-master-1-71 ~]# kubectl delete -f my-pvc.yaml
[root@k8s-master-1-71 ~]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM            STORAGECLASS   REASON   AGE
my-pv   5Gi        RWX            Retain           Released   default/my-pvc                           7h18m## 解釋:連著刪除Pod和PCV后,回收策略為 Retain ,狀態為 Released(PVC 被刪除,但是資源還未被集群重新聲明)
[root@k8s-node1-1-72 ~]# ls /ifs/kubernetes/    //PV中的資源依舊保留,需要管理員手工清理數據
aaaaa

注意:刪除PVC后,原來Bound的PV就無法繼續使用,即使重新apply pvc.yaml,也是Pending狀態。

思考:現在PV使用方式稱為靜態供給,需要K8s運維工程師提前創 建一堆PV,供開發者使用

1.5 PV 動態供給(StorageClass)

PV靜態供給明顯的缺點是維護成本太高了,需要提前創建PV且不靈活! 因此,K8s開始支持PV動態供給,使用StorageClass對象實現。StorageClass可以根據客戶的PVC需求,通過PVC需求自動創建后端存儲PV,且自動去綁定,無需像NFS還要創建目錄隔離應用。

優點:

  • PV無需額外的提前獨立創建;

  • PVC直接獲取,也不用等待合適的PV;

支持動態供給的存儲插件:Storage Classes | Kubernetes

相關GitHub部署:https://github.com/kubernetes-sigs/sig-storage-lib-external-provisioner

了解:Volume Plugin是支持存儲的類型,Internal Provisioner內部是否支持

例如NFS內部是不支持的(不能直接PVC動態供給),且K8s默認不支持NFS動態供給,需要單獨部署社區開發的插件

項目地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

部署StorageClass插件需要的3個文件:

cd deploy
kubectl apply -f rbac.yaml           # 授權訪問apiserver
kubectl apply -f deployment.yaml     # 部署插件,需修改里面NFS服務器地址與共享目錄
kubectl apply -f class.yaml          # 創建存儲類(標識使用哪個存儲)kubectl get sc                       # 查看存儲類

補充:一個集群中可以有多個存儲類,而一個存儲類一般對應一個存儲

流程圖:


  • rbac.yaml 示例:

[root@k8s-master-1-71 nfs-external-provisioner]# cat rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:name: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: nfs-client-provisioner-runner
rules:- apiGroups: [""]resources: ["persistentvolumes"]verbs: ["get", "list", "watch", "create", "delete"]- apiGroups: [""]resources: ["persistentvolumeclaims"]verbs: ["get", "list", "watch", "update"]- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get", "list", "watch"]- apiGroups: [""]resources: ["events"]verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: run-nfs-client-provisioner
subjects:- kind: ServiceAccountname: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
roleRef:kind: ClusterRolename: nfs-client-provisioner-runnerapiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
rules:- apiGroups: [""]resources: ["endpoints"]verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: leader-locking-nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
subjects:- kind: ServiceAccountname: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
roleRef:kind: Rolename: leader-locking-nfs-client-provisionerapiGroup: rbac.authorization.k8s.io
  • class.yaml 配置示例:
[root@k8s-master-1-71 nfs-external-provisioner]# cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:name: managed-nfs-storage     //StroagaClass存儲類,在PVC中需要指定的標識(類似ingressclass選擇Nginx)
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'  //與Deployment的變量PROVISIONER_NAME保持一致 
parameters:archiveOnDelete: "false"
  • deployment.yaml 配置示例:
[root@k8s-master-1-71 nfs-external-provisioner]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nfs-client-provisionerlabels:app: nfs-client-provisioner# replace with namespace where provisioner is deployednamespace: default
spec:replicas: 1strategy:type: Recreateselector:matchLabels:app: nfs-client-provisionertemplate:metadata:labels:app: nfs-client-provisionerspec:serviceAccountName: nfs-client-provisionercontainers:- name: nfs-client-provisioner    //部署了NFS供給程序的容器image: lizhenliang/nfs-subdir-external-provisioner:v4.0.1    //鏡像地址volumeMounts:- name: nfs-client-rootmountPath: /persistentvolumesenv:- name: PROVISIONER_NAME     //class.yaml中的PROVISIONER_NAMEvalue: k8s-sigs.io/nfs-subdir-external-provisioner- name: NFS_SERVERvalue: 192.168.1.72     //需要指定后端NFS存儲- name: NFS_PATHvalue: /ifs/kubernetesvolumes:- name: nfs-client-rootnfs:server: 192.168.1.72     //需要指定后端NFS存儲path: /ifs/kubernetes
  • PVC指定存儲類配置示例:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: my-pvc
spec:storageClassName: "managed-nfs-storage"    //指定StorageClass存儲類(class.yaml)accessModes:- ReadWriteMany  resources:requests:storage: 5Gi

測試1:基于NFS提供PVC動態供給

步驟1:部署NFS-StorageClass 存儲類插件

[root@k8s-master-1-71 nfs-external-provisioner]# kubectl apply -f .
storageclass.storage.k8s.io/managed-nfs-storage created
deployment.apps/nfs-client-provisioner created
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created# 創建的Pod為deployment.yaml中的NFS供給程序容器
[root@k8s-master-1-71 nfs-external-provisioner]# kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGEnfs-client-provisioner-5848c9cddc-zkts2   1/1     Running   0          2m27s# 創建的storageclass為class.yaml中指定的存儲類
[root@k8s-master-1-71 nfs-external-provisioner]# kubectl get storageclass
NAME                  PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
managed-nfs-storage   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  2m54s

步驟2:在PVC中指定存儲類名稱

[root@k8s-master-1-71 ~]# kubectl apply -f my-pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: my-podname: my-pod
spec:selector:matchLabels:app: my-podtemplate:metadata:labels:app: my-podspec:containers:- name: my-podimage: nginxvolumeMounts:- name: data-volumemountPath: /usr/share/nginx/htmlvolumes:- name: data-volumepersistentVolumeClaim:claimName: my-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: my-pvcspec:storageClassName: "managed-nfs-storage"accessModes:- ReadWriteManyresources:requests:storage: 5Gi[root@k8s-master-1-71 ~]# kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
my-pod-6fbc98b678-t2gvg                   1/1     Running   0          4m11s
nfs-client-provisioner-5848c9cddc-zkts2   1/1     Running   0          24m[root@k8s-master-1-71 ~]# kubectl get pvc     //查看PVC
NAME     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
my-pvc   Bound    pvc-51d00de4-52ea-4f1a-988a-bc3e5b7e961e   5Gi        RWX            managed-nfs-storage   3s[root@k8s-master-1-71 ~]# kubectl get pv      //查看PV
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM            STORAGECLASS          REASON   AGE
pvc-51d00de4-52ea-4f1a-988a-bc3e5b7e961e   5Gi        RWX            Delete           Bound      default/my-pvc   managed-nfs-storage            6s# 進入容器查看掛載
[root@k8s-master-1-71 ~]# kubectl exec -it my-pod-6fbc98b678-t2gvg -- bash
root@my-pod-6fbc98b678-t2gvg:/# df -Th | grep pvc-51d00de4-52ea-4f1a-988a-bc3e5b7e961e
192.168.1.72:/ifs/kubernetes/default-my-pvc-pvc-51d00de4-52ea-4f1a-988a-bc3e5b7e961e nfs4      37G  4.4G   33G  12% /usr/share/nginx/html

# 查看NFS服務器的掛載目錄,可看到隨機生成的PV目錄

結論:通過基于NFS提供PVC動態供給,無需再定義單獨的PV,也無需為了指定到某個NFS目錄手動創建子目錄,動態供給會自動幫忙實現PV及隨機生成NFS子目錄

注意:由于NFS提供PVC動態供給的PV的默認回收策略是 Delete ,所以在刪除PVC的同時,也會將PV一起刪除;在NFS目錄上的文件也一并刪除。


測試2:

[root@k8s-master-1-71 ~]# kubectl apply -f my-pvc2.yaml
[root@k8s-node1-1-72 ~]# ls /ifs/kubernetes/
aaaaa  default-my-pvc2-pvc-b7769112-aea6-4533-9e5c-5d14cd67fc65  default-my-pvc-pvc-51d00de4-52ea-4f1a-988a-bc3e5b7e961e[root@k8s-master-1-71 ~]# kubectl delete -f my-pvc2.yaml
[root@k8s-node1-1-72 ~]# ls /ifs/kubernetes/
aaaaa  default-my-pvc-pvc-51d00de4-52ea-4f1a-988a-bc3e5b7e961e

由于考慮數據的重要性,希望刪除PVC時保留數據備份

[root@k8s-master-1-71 nfs-external-provisioner]# vi class.yaml
...archiveOnDelete: "True"     //將archiveOnDelete修改為 True,即可在刪除PVC時保留備份# 需要刪除class.yaml并重新apply應用
[root@k8s-master-1-71 nfs-external-provisioner]# kubectl delete -f class.yaml[root@k8s-master-1-71 nfs-external-provisioner]# kubectl apply -f class.yaml
# 測試刪除PVC
[root@k8s-master-1-71 ~]# kubectl delete -f my-pvc.yaml

# 查看NFS服務器的掛載目錄,原來的PV目錄已重新命名(備份)

0

2、有狀態應用部署初探

無狀態與有狀態:

Deployment控制器設計原則:管理的所有Pod一模一樣提供同一個服務(replicas),使用共享存儲,之間沒有連接關系,也不考慮在哪臺Node運 行,可隨意擴容和縮容。這種應用稱為“無狀態”,例如Web服務

在實際的場景中,這并不能滿足所有應用,尤其是分布式應用,會部署多個實例,這些實例之間往往有 依賴關系,部署的角色也不一樣,例如主從關系、主備關系,這種應用稱為“有狀態”,例如MySQL主從、Etcd集群

無狀態特點:

  1. 每個Pod都一樣,且提供同一種服務

  2. Pod之間沒有連接關系

  3. 使用共享存儲

有狀態特點:

  1. 每個Pod不對等,角色屬性也不同

  2. Pod之間有連接關系(類似數據庫主從)

  3. 每個Pod的數據都是有差異化的,需要獨立的存儲進行持久化,否則會產生沖突

2.1 StatefulSet 控制器介紹

StatefulSet控制器用于部署有狀態應用,滿足一些有狀態應用的需求:

  • Pod有序的部署、擴容、刪除和停止

  • Pod分配一個穩定的且唯一的網絡標識

  • Pod分配一個獨享的存儲

2.2 StatefulSet 部署應用實踐

1)穩定的網絡ID(域名)

使用 Headless Service(相比普通Service只是將spec.clusterIP定義為None)來維護Pod網絡身份。 并且添加 serviceName: “headless-svc” 字段指定 StatefulSet控制器 要使用這個Headless Service。讓StatefulSet控制器為其創建每個Pod固定的域名解析地址。

DNS解析名稱:<statefulsetName-index>.<service-name> .<namespace-name>.svc.cluster.local

[root@k8s-master-1-71 ~]# kubectl create deployment stateful-pod --image=nginx
[root@k8s-master-1-71 ~]# kubectl expose deployment stateful-pod --port=80 --target-port=80 --dry-run=client -o yaml > headless-svc.yaml
[root@k8s-master-1-71 ~]# kubectl apply -f headless-svc.yaml
apiVersion: v1
kind: Service
metadata:labels:app: headless-svcname: headless-svc
spec:clusterIP: None     //指定SVC的clusterIP為Noneports:- port: 80protocol: TCPtargetPort: 80selector:app: stateful-pod[root@k8s-master-1-71 ~]# kubectl get svc
NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
headless-svc   ClusterIP   None             <none>        80/TCP    8s

補充:Cluster-IP為None,標識該Service為headlress無頭服務,這種Service將沒有負載均衡轉發的功能;

2)穩定的存儲

StatefulSet的存儲卷 使用VolumeClaimTemplate創建,稱為卷申請模板(針對StatefulSet專門設置的類型),當StatefulSet使用VolumeClaimTemplate創建 一個PersistentVolume時,同樣也會為每個Pod分配并創建一個編號的PVC(一個PV對應一個PVC)

參考文檔:StatefulSets | Kubernetes

參考:https://github.com/lizhenliang/k8s-statefulset


示例:StatefulSet部署(包括無頭服務、StatefulSet+卷申請模)

[root@k8s-master-1-71 ~]# kubectl apply -f statefulset-test.yaml
# headless Service 服務配置示例
apiVersion: v1
kind: Service
metadata:name: nginx-headless     //headlessService服務名稱,需要和StatefulSet的ServiceName保持一致labels:app: nginx
spec:ports:- port: 80name: webclusterIP: None     //設置cluster-IP為Noneselector:app: nginx     //指定StatefulSet的Pod# StatefulSet 配置示例
---
apiVersion: apps/v1
kind: StatefulSet
metadata:name: web
spec:selector:matchLabels:app: nginx # has to match .spec.template.metadata.labelsserviceName: "nginx-headless"  # 指定 headless Service 服務名稱replicas: 3          # by default is 1minReadySeconds: 10  # by default is 0template:metadata:labels:app: nginx # has to match .spec.selector.matchLabelsspec:terminationGracePeriodSeconds: 10containers:- name: nginximage: nginxports:- containerPort: 80name: webvolumeMounts:- name: www-datamountPath: /usr/share/nginx/htmlvolumeClaimTemplates:     //卷申請模板(為StatefulSet專門設置的類型)- metadata:name: www-dataspec:accessModes: [ "ReadWriteOnce" ]storageClassName: "managed-nfs-storage"    # 指定 storageClass(kubectl get sc)resources:requests:storage: 1Gi

查看信息:

[root@k8s-master-1-71 ~]# kubectl get pods
NAME                                      READY   STATUS    RESTARTS      AGE
web-0                                     1/1     Running   0             4m32s
web-1                                     1/1     Running   0             3m31s
web-2                                     1/1     Running   0             2m51s# 查看 headless Service
[root@k8s-master-1-71 ~]# kubectl get svc
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx-headless   ClusterIP   None         <none>        80/TCP    9m52s# 查看 headless Service 對應后端的Pod
[root@k8s-master-1-71 ~]# kubectl get ep
NAME                                          ENDPOINTS                                            AGE
nginx-headless                                10.244.114.10:80,10.244.117.50:80,10.244.117.51:80   13m# 查看 PVC
[root@k8s-master-1-71 ~]# kubectl get pvc
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
www-data-web-0   Bound    pvc-c8f06f51-5048-4a43-b822-9f6bcd1bd20c   1Gi        RWO            managed-nfs-storage   10m
www-data-web-1   Bound    pvc-ae9c2a66-0bcb-489e-98d0-0350d480fb68   1Gi        RWO            managed-nfs-storage   9m37s
www-data-web-2   Bound    pvc-50d69a6e-d3ef-42e2-bd13-e6c954d78677   1Gi        RWO            managed-nfs-storage   8m57s# 查看 PV
[root@k8s-master-1-71 ~]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                    STORAG                                                 ECLASS          REASON   AGE
pvc-50d69a6e-d3ef-42e2-bd13-e6c954d78677   1Gi        RWO            Delete           Bound      default/www-data-web-2   manage                                                 d-nfs-storage            9m1s
pvc-ae9c2a66-0bcb-489e-98d0-0350d480fb68   1Gi        RWO            Delete           Bound      default/www-data-web-1   manage                                                 d-nfs-storage            9m41s
pvc-c8f06f51-5048-4a43-b822-9f6bcd1bd20c   1Gi        RWO            Delete           Bound      default/www-data-web-0   manage                                                 d-nfs-storage            10m

測試網絡:

  • ① 一個普通的headless-service對應Deplyment的域名解析,以及headless-service對應statefulset的域名解析
  • ② 測試 statefulset的域名 網絡連通性
# 創建普通的headless-service對應Deplyment的域名解析
[root@k8s-master-1-71 ~]# kubectl create deployment web --image=nginx[root@k8s-master-1-71 ~]# kubectl expose deployment web --port=80 --target-port=80 --dry-run=client -o yaml > test-svc.yaml
[root@k8s-master-1-71 ~]# kubectl apply -f test-svc.yaml(   //修改 clusterIP: None
[root@k8s-master-1-71 ~]# kubectl get svc
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx-headless   ClusterIP   None         <none>        80/TCP    30m
web              ClusterIP   None         <none>        80/TCP    6m45s
[root@k8s-master-1-71 ~]# kubectl get ep
NAME                                          ENDPOINTS                                            AGE
nginx-headless                                10.244.114.10:80,10.244.117.50:80,10.244.117.51:80   31m
web                                           10.244.117.52:80                                     7m34s# 創建測試bs鏡像pod
[root@k8s-master-1-71 ~]# kubectl run bs --image=busybox:1.28.4 -- sleep 24h
[root@k8s-master-1-71 ~]# kubectl exec -it bs -- sh
/ # nslookup web
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name:      web
Address 1: 10.244.117.52 10-244-117-52.web.default.svc.cluster.local
## DNS解析名稱:<PodIP>.<service-name> .<namespace-name>.svc.cluster.local/ # nslookup nginx-headless
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name:      nginx-headless
Address 1: 10.244.114.10 web-1.nginx-headless.default.svc.cluster.local
Address 2: 10.244.117.50 web-0.nginx-headless.default.svc.cluster.local
Address 3: 10.244.117.51 web-2.nginx-headless.default.svc.cluster.local
## DNS解析名稱:<statefulsetName-index>.<service-name> .<namespace-name>.svc.cluster.local[root@k8s-master-1-71 ~]# kubectl exec -it bs -- sh
/ # ping web-1.nginx-headless.default.svc.cluster.local
PING web-1.nginx-headless.default.svc.cluster.local (10.244.114.10): 56 data bytes
64 bytes from 10.244.114.10: seq=0 ttl=62 time=0.539 ms
64 bytes from 10.244.114.10: seq=1 ttl=62 time=0.474 ms

測試存儲:

[root@k8s-node1-1-72 ~]# ls /ifs/kubernetes/     //自動生成獨立的PV,
default-www-data-web-1-pvc-ae9c2a66-0bcb-489e-98d0-0350d480fb68
default-www-data-web-2-pvc-50d69a6e-d3ef-42e2-bd13-e6c954d78677
default-www-data-web-0-pvc-c8f06f51-5048-4a43-b822-9f6bcd1bd20c[root@k8s-master-1-71 ~]# kubectl exec -it web-0 -- bash
root@web-0:/# cd /usr/share/nginx/html/ ; echo 111 > index.html[root@k8s-node1-1-72 ~]# cat /ifs/kubernetes/default-www-data-web-0-pvc-c8f06f51-5048-4a43-b822-9f6bcd1bd20c/index.html
111
[root@k8s-node1-1-72 ~]# ls /ifs/kubernetes/default-www-data-web-2-pvc-50d69a6e-d3ef-42e2-bd13-e6c954d78677///目錄為空
## 因此Statefulset控制器創建的每個Pod的存儲為獨立的

思考:在有狀態環境部署下,分布式應用組件的角色不同,每個Pod也不相同,而在上述 StatefulSet部署示例中,假設運行一個etcd數據集群,有3個副本且肯定只有一個指定的鏡像(鏡像相同),如何區分這3個Pod的角色

解答:通過配置文件區分(每個節點的名稱、IP、存儲目錄區分),需要保證啟動的3個副本容器,每一個都能按照自己的角色(配置文件)進行啟動。而配置文件則需要根據statefulset控制器部署的Pod容器編號進行區分,判斷當前啟動的是第幾個容器,就使用哪個配置文件進行啟動,從而實現Pod的角色。例如:etcd-0.conf、etcd-1.conf、etcd-2.conf

參考同類型的案例:運行 ZooKeeper,一個分布式協調系統 | Kubernetes


— StatefulSet 與 Deployment區別:有身份的!

身份三要素(唯一性):

  • 域名

  • 主機名

  • 存儲(PVC)

3、應用程序數據存儲

  • ConfigMap:存儲配置文件
  • Secret:存儲敏感數據

3.1 ConfigMap 存儲應用配置

創建ConfigMap后,數據實際會持久化存儲在K8s中Etcd,然后通過創建Pod時引用該數據。

應用場景:應用程序配置(類似配置管理中心如apollo、nacos)

Pod使用configmap數據有兩種方式:

  1. 變量注入到容器里

  2. 數據卷掛載

兩種數據類型:

  • 鍵值
  • 多行數據

相關命令:

創建ConfigMapkubectl create configmap --from-file=path/to/bar

kubectl create configmap my-configmap --from-literal=abc=123 --from-literal=cde=456

查看ConfigMap:kubectl get configmap

官方:ConfigMap | Kubernetes


ConfigMap 配置示例:

1)部署ConfigMap的YAML

[root@k8s-master-1-71 ~]# kubectl apply -f configmap-demo.yaml
apiVersion: v1
kind: ConfigMap
metadata:name: configmap-demo
data:abc: "123"     //key/value鍵值方式(字符串需要“”)cde: "456"redis.properties: |     //多行數據方式port: 6379host: 192.168.31.10# 查看創建的ConfigMap
[root@k8s-master-1-71 ~]# kubectl get configmap
NAME               DATA   AGE
configmap-demo     3      7s
## 備注:DATA顯示為3,表示存儲了3個數據,包括abc、cde、redis.properties

2)部署Pod的YAML

[root@k8s-master-1-71 ~]# kubectl apply -f configmap-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: configmap-demo-pod
spec:containers:- name: nginximage: nginx# 定義環境變量env:- name: ABCD # 容器中的變量,請注意這里和 ConfigMap 中的鍵名是不一樣的valueFrom:configMapKeyRef:name: configmap-demo      # 這個值來自 ConfigMapkey: abc     # 需要取值的鍵- name: CDEFvalueFrom:configMapKeyRef:name: configmap-demokey: cdevolumeMounts:- name: configmountPath: "/config"   # 掛載到哪個目錄readOnly: true         # 掛載文件為只讀volumes:# 在 Pod 級別設置卷,然后將其掛載到 Pod 內的容器中- name: configconfigMap:name: configmap-demo    # 提供想要掛載的 ConfigMap 的名字# 來自 ConfigMap 的一組鍵,將被創建為文件items:- key: "redis.properties"   # configmap-demo的Keypath: "redis.conf"     # 掛載后的名字

測試:進入pod中驗證是否注入變量和掛載

[root@k8s-master-1-71 ~]# kubectl exec -it configmap-test-pod-5dff5f64c6-ncmnd -- bash
root@configmap-test-pod-5dff5f64c6-ncmnd:/# echo $ABCD
123
root@configmap-test-pod-5dff5f64c6-ncmnd:/# echo $CDEF
456
root@configmap-test-pod-5dff5f64c6-ncmnd:/# cat /config/redis.conf
port: 6379
host: 192.168.31.10

3.2 Secret 存儲敏感信息

與ConfigMap類似,區別在于Secret主要存儲敏感數據,所有的數據要經過base64編碼。

應用場景:憑據

kubectl create secret 支持三種數據類型:

  • docker-registry:存儲鏡像倉庫認證信息(鏡像倉庫需要賬戶密碼認證)
  • generic:存儲用戶名、密碼:
    • 例如:kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub
    • 例如:kubectl create secret generic my-secret --from-literal=username=produser --from-literal=password=123456
  • tls:存儲證書:kubectl create secret tls --cert=path/to/tls.cert --key=path/to/tls.key
    • 例如 :05 K8s網絡 使用ingress - tls 部署https

相關命令:

  • 查看Secret:kubectl get secret

相關base64命令:

  • # echo -n 'admin' | base64? ? ? ? ? //加密(YWRtaW4=)
  • # echo YWRtaW4= | base64 -d? //解密(admin)

補充: 在Secret 配置文件中未作顯式設定時,默認的 Secret 類型是 Opaque


命令示例:

[root@k8s-master ~]# kubectl create secret generic my-secret --from-literal=username=admin --from-literal=password=123456

YAML示例:

1)將用戶名密碼進行編碼

[root@k8s-master-1-71 ~]# echo -n 'admin' | base64   //用戶名加密
YWRtaW4=
[root@k8s-master-1-71 ~]# echo -n '123456' | base64  //密碼加密
MTIzNDU2

2)部署Secret的YAML

[root@k8s-master-1-71 ~]# vi secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:name: my-secret
type: Opaque    //默認的 Secret 類型是 Opaque
data:username: YWRtaW4=password: MTIzNDU2# 查看創建的ConfigMap
[root@k8s-master-1-71 ~]# kubectl get secret
NAME              TYPE                DATA   AGE
secret-demo       Opaque              2      5s

TYPE類型參考:Secrets | Kubernetes

3)部署Pod的YAML

apiVersion: v1
kind: Pod
metadata:name: secret-demo-pod
spec:containers:- name: nginximage: nginx env:- name: USERNAME    # 容器中的變量valueFrom:secretKeyRef:name: secret-demokey: username- name: PASSWORD    # 容器中的變量valueFrom:secretKeyRef:name: secret-demokey: passwordvolumeMounts:- name: configmountPath: "/config"readOnly: truevolumes:- name: configsecret:secretName: secret-demoitems:- key: username path: username.txt- key: passwordpath: password.txt

備注:Pod使用Secret數據與ConfigMap方式一樣

測試:進入pod中驗證是否注入變量和掛載

[root@k8s-master-1-71 ~]# kubectl exec -it secret-test-pod-6554b98c8-8hrbb -- bash
root@secret-test-pod-6554b98c8-8hrbb:/# echo $USERNAME
admin
root@secret-test-pod-6554b98c8-8hrbb:/# echo $PASSWORD
123456
root@secret-test-pod-6554b98c8-8hrbb:/# ls /config/
password.txt  username.txt

課后作業

1、創建一個secret,并創建2個pod,pod1掛載該secret,路徑為/secret,pod2使用環境變量引用該 secret,該變量的環境變量名為ABC

  • secret名稱:my-secret
  • pod1名稱:pod-volume-secret
  • pod2名稱:pod-env-secret

2、 創建一個pv,再創建一個pod使用該pv

  • 容量:5Gi
  • 訪問模式:ReadWriteOnce

3、創建一個pod并掛載數據卷,不可以用持久卷

  • 卷來源:emptyDir、hostPath任意
  • 掛載路徑:/data

4、將pv按照名稱、容量排序,并保存到/opt/pv文件

小結

本篇為 【Kubernetes CKA認證 Day7】的學習筆記,希望這篇筆記可以讓您初步了解到?數據卷與數據持久卷、有狀態應用部署、應用程序數據存儲案例 ;課后還有擴展實踐,不妨跟著我的筆記步伐親自實踐一下吧!


Tip:畢竟兩個人的智慧大于一個人的智慧,如果你不理解本章節的內容或需要相關筆記、視頻,可私信小安,請不要害羞和回避,可以向他人請教,花點時間直到你真正的理解。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/64423.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/64423.shtml
英文地址,請注明出處:http://en.pswp.cn/web/64423.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python調用R語言中的程序包來執行回歸樹、隨機森林、條件推斷樹和條件推斷森林算法

要使用Python調用R語言中的程序包來執行回歸樹、隨機森林、條件推斷樹和條件推斷森林算法&#xff0c;重新計算中國居民收入不平等&#xff0c;并進行分類匯總&#xff0c;我們可以使用rpy2庫。rpy2允許在Python中嵌入R代碼并調用R函數。以下是一個詳細的步驟和示例代碼&#x…

關于JAVA方法值傳遞問題

1.1 前言 之前在學習C語言的時候&#xff0c;將實參傳遞給方法&#xff08;或函數&#xff09;的方式分為兩種&#xff1a;值傳遞和引用傳遞&#xff0c;但在JAVA中只有值傳遞&#xff08;顛覆認知&#xff0c;基礎沒學踏實&#xff09; 參考文章&#xff1a;https://blog.csd…

Excel基礎知識

一&#xff1a;數組 一行或者一列數據稱為一維數組&#xff0c;多行多列稱為二維數組&#xff0c;數組支持算術運算&#xff08;如加減乘除等&#xff09;。 行&#xff1a;{1,2,3,4} 數組中的每個值用逗號分隔列&#xff1a;{1;2;3;4} 數組中的每個值用分號分隔行列&#xf…

基于DIODES AP43781+PI3USB31531+PI3DPX1207C的USB-C PD Video 之全功能顯示器連接端口方案

隨著USB-C連接器和PD功能的出現&#xff0c;新一代USB-C PD PC顯示器可以用作個人和專業PC工作環境的電源和數據集線器。 雖然USB-C PD顯示器是唯一插入墻壁插座的交流電源輸入設備&#xff0c;但它可以作為數據UFP&#xff08;上游接口&#xff09;連接到連接到TCD&#xff0…

gazebo_world 基本圍墻。

如何使用&#xff1f; 參考gazebo harmonic的官方教程。 本人使用harmonic的template&#xff0c;在里面進行修改就可以分流暢地使用下去。 以下是world 文件. <?xml version"1.0" ?> <!--Try sending commands:gz topic -t "/model/diff_drive/…

解決無法在 Ubuntu 24.04 上運行 AppImage 應用

在 Ubuntu 24.04 中運行 AppImage 應用的完整指南 在 Ubuntu 24.04 中&#xff0c;許多用戶可能會遇到 AppImage 應用無法啟動的問題。即使你已經設置了正確的文件權限&#xff0c;AppImage 仍然拒絕運行。這通常是由于缺少必要的庫文件所致。 問題根源&#xff1a;缺少 FUSE…

Pytorch使用手冊-DCGAN 指南(專題十四)

1. Introduction 本教程將通過一個示例介紹 DCGANs(深度卷積生成對抗網絡)。我們將訓練一個生成對抗網絡(GAN),在給它展示大量真實名人照片后,它能夠生成新的“名人”圖片。這里的大部分代碼來源于 PyTorch 官方示例中的 DCGAN 實現,而本文檔將對該實現進行詳細解釋,并…

springboot配置oracle+達夢數據庫多數據源配置并動態切換

項目場景&#xff1a; 在工作中很多情況需要跨數據庫進行數據操作,自己總結的經驗希望對各位有所幫助 問題描述 總結了幾個問題 1.識別不到mapper 2.識別不到xml 3.找不到數據源 原因分析&#xff1a; 1.配置文件編寫導致識別mapper 2.配置類編寫建的格式有問題 3.命名…

html+css+js網頁設計 美食 家美食1個頁面

htmlcssjs網頁設計 美食 家美食1個頁面 網頁作品代碼簡單&#xff0c;可使用任意HTML輯軟件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html編輯軟件進行運行及修改編輯等操作&#xff09;。 獲取源碼 1&#xf…

【機器學習】【樸素貝葉斯分類器】從理論到實踐:樸素貝葉斯分類器在垃圾短信過濾中的應用

&#x1f31f; 關于我 &#x1f31f; 大家好呀&#xff01;&#x1f44b; 我是一名大三在讀學生&#xff0c;目前對人工智能領域充滿了濃厚的興趣&#xff0c;尤其是機器學習、深度學習和自然語言處理這些酷炫的技術&#xff01;&#x1f916;&#x1f4bb; 平時我喜歡動手做實…

Vue使用Tinymce 編輯器

目錄 一、下載并重新組織tinymce結構二、使用三、遇到的坑 一、下載并重新組織tinymce結構 下載 npm install tinymce^7 or yarn add tinymce^7重構目錄 在node_moudles里找到tinymce文件夾&#xff0c;把里面文件拷貝一份放到public下&#xff0c;如下&#xff1a; -- pub…

odoo中@api.model, @api.depends和@api.onchange 裝飾器的區別

文章目錄 1. api.model用途特點示例 2. api.depends用途特點示例 3. api.onchange用途特點示例 總結 在 Odoo 中&#xff0c;裝飾器&#xff08;decorators&#xff09;用于修飾方法&#xff0c;以指定它們的行為和觸發條件。api.model、api.depends 和 api.onchange 是三個常用…

EMNLP'24 最佳論文解讀 | 大語言模型的預訓練數據檢測:基于散度的校準方法

點擊藍字 關注我們 AI TIME歡迎每一位AI愛好者的加入&#xff01; 點擊 閱讀原文 觀看作者講解回放&#xff01; 作者簡介 張偉超&#xff0c;中國科學院計算所網絡數據科學與技術重點實驗室三年級直博生 內容簡介 近年來&#xff0c;大語言模型&#xff08;LLMs&#xff09;的…

大數據技術-Hadoop(一)Hadoop集群的安裝與配置

目錄 一、準備工作 1、安裝jdk&#xff08;每個節點都執行&#xff09; 2、修改主機配置 &#xff08;每個節點都執行&#xff09; 3、配置ssh無密登錄 &#xff08;每個節點都執行&#xff09; 二、安裝Hadoop&#xff08;每個節點都執行&#xff09; 三、集群啟動配置&a…

PilotGo

title: 解鎖 PilotGo&#xff1a;智能化運維的得力助手 date: ‘2024-12-29’ category: blog tags: PilotGo運維管理智能化工具技術應用 sig: ops archives: ‘2024-12’ author:way_back summary: PilotGo 作為一款創新的運維管理工具&#xff0c;憑借其智能化的特性和豐富的…

折騰日記:如何讓吃灰筆記本發揮余熱——搭建一個相冊服務

背景 之前寫過&#xff0c;我在家里用了一臺舊的工作站筆記本做了服務器&#xff0c;連上一個綠聯的5位硬盤盒實現簡單的網盤功能&#xff0c;然而&#xff0c;還是覺的不太理想&#xff0c;比如使用filebrowser雖然可以備份文件和圖片&#xff0c;當使用手機使用網頁&#xf…

使用seata實現分布式事務管理

配置 版本說明&#xff1a;springCloud Alibaba組件版本關系 我用的是spring cloud Alibaba 2.2.1.RELEASE 、springboot 2.2.1.RELEASE、nacos 2.0.1、seata1.2.0,jdk1.8 seata 主要用于在分布式系統中對數據庫進行事務回滾&#xff0c;保證全局事務的一致性。 seata的使用…

【總結】動態規劃

線性dp LeetCode題單&#xff0c; 從記憶化搜索到遞推 Pre&#xff1a; 從最初狀態到最終狀態等價&#xff0c;那么從最終狀態開始和最初狀態開始結果一樣。 遞歸時不會產生其他負面結果&#xff0c;即無論何時進入遞歸&#xff0c;只要遞歸參數相同&#xff0c;結果就相同。 …

RabbitMQ中的異步Confirm模式:提升消息可靠性的利器

在現代分布式系統中&#xff0c;消息隊列&#xff08;Message Queue&#xff09;扮演著至關重要的角色&#xff0c;它能夠解耦系統組件、提高系統的可擴展性和可靠性。RabbitMQ作為一款廣泛使用的消息隊列中間件&#xff0c;提供了多種機制來確保消息的可靠傳遞。其中&#xff…

買賣預測工具

設計一個用于在交易市場中尋找確定性或大概率盈利的買賣預測工具是一個具有挑戰性但非常有潛力的項目。你可以通過以下幾個步驟進行思路規劃&#xff1a; 1. 明確目標 大概率盈利&#xff1a;工具的目的是找出大概率盈利的交易機會。不能完全依賴于100%確定性&#xff0c;因為…