1。 ConfigMap
ConfigMap 是一種 API 物件,用來將非機密性的資料儲存到鍵值對中。使用時,Pods 可以將其用作環境變數、命令列引數或者儲存卷中的配置檔案。
ConfigMap 的主要作用就是為了讓映象和配置檔案解耦,以便實現映象的可移植性和可複用性。
ConfigMap 並不提供保密或者加密功能。 如果你想儲存的資料是機密的,請使用 Secret, 或者使用其他第三方工具來保證你的資料的私密性,而不是用 ConfigMap。
ConfigMap 的名字必須是一個合法的 DNS 子域名。
ConfigMap 建立的4種方式
注意:此處我們用到的例子中的 cm1, cm2, cm3, cm4 後續例子中也會引用到。
這裡先給出幾個檢視 configmap 的命令:
# 檢視 configmap 列表kubectl get cm# 檢視某個 configmap 內容kubectl describe cm cm1複製程式碼
透過直接在命令列中指定configmap引數建立
,即(——from-literal=key=value):
kubectl create configmap cm1 ——from-literal=host=127。0。0。1 ——from-literal=port=3306複製程式碼
透過指定檔案建立
,即(——from-file=file):
echo -n 127。0。0。1 > hostecho -n 3306 > port複製程式碼
kubectl create configmap cm2 ——from-file=。/host ——from-file=。/port複製程式碼
透過一個檔案內多個鍵值對
,即(——from-env-file=file):
vim env。txt複製程式碼
host=127。0。0。1port=3306複製程式碼
kubectl create configmap cm3 ——from-env-file=env。txt複製程式碼
透過 YMAL 檔案建立
(推薦使用):
vim cm4。yml複製程式碼
apiVersion: v1kind: ConfigMapmetadata: name: cm4data: host: 127。0。0。1 port: “3306”複製程式碼
kubectl apply -f cm4。yml複製程式碼
ConfigMap 的2種使用方式
透過環境變數的方式傳遞給 pod
:
vim pod-cm1。yml複製程式碼
apiVersion: v1kind: Podmetadata: name: pod-cm1spec: containers: - name: mysql-pod image: mysql:5。7 args: [ “/bin/sh”, “-c”, “sleep 10000” ] envFrom: # env方式 - configMapRef: name: cm1 # configmap名稱複製程式碼
kubectl apply -f pod-cm1。ymlkubectl exec pod-cm1 ——env複製程式碼
透過 volume 的方式掛載到 pod 內
:
vim pod-cm2。yml複製程式碼
apiVersion: v1kind: Podmetadata: name: pod-cm2spec: containers: - name: mysql-pod image: mysql:5。7 args: [ “/bin/sh”, “-c”, “sleep 10000” ] volumeMounts: # 用volume掛載方式 - name: vol-cm # 對應下面的volume名 mountPath: “/etc/mysql” # 掛載到容器內部的路徑 readOnly: true # 只讀 volumes: - name: vol-cm # 卷名稱 configMap: name: cm2 # configmap的名稱複製程式碼
kubectl apply -f pod-cm2。ymlkubectl exec pod-cm2 – cat /etc/mysql/hostkubectl exec pod-cm2 – cat /etc/mysql/port複製程式碼
使用 subpath 引數覆蓋檔案
:
cat index。html(內容是 ABCDEFG)複製程式碼
kubectl create configmap nginx-index ——from-file=index。html複製程式碼
vim subpath-cm。yaml複製程式碼
apiVersion: v1kind: Podmetadata: name: subpath-cmspec: containers: - name: c1 image: nginx:1。17。1-alpine volumeMounts: - name: nginx-config mountPath: /usr/share/nginx/html/index。html # configmap要掛載並覆蓋的絕對路徑 subPath: index。html # 這裡要寫相對路徑 volumes: - name: nginx-config configMap: name: nginx-index # 對應上面建立的configmap複製程式碼
kubectl apply -f subpath-cm。yaml複製程式碼
此時 nginx 的首頁內容就已經被覆蓋成了“ABCDEFG”。
ConfigMap 的熱更新
透過環境變數的方式傳遞給 pod,這種方式不會熱更新。
透過 volume 的方式掛載到 pod 內。這種方式會熱更新, 大概需要半分鐘左右
。
但是使用 subpath 掛載檔案,這種方式也不能熱更新。
我們現在就來驗證這種方式:
kubectl edit cm cm2複製程式碼
apiVersion: v1data: host: 127。0。0。1 port: “3308” 修改成3308kind: ConfigMapmetadata: creationTimestamp: “2020-11-07T12:09:15Z” managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: 。: {} f:host: {} f:port: {} manager: kubectl operation: Update time: “2020-11-07T12:09:15Z” name: cm2 namespace: default resourceVersion: “169707” selfLink: /api/v1/namespaces/default/configmaps/cm2複製程式碼
驗證對應的 pod 裡的變化,一段時間後會改變:
kubectl exec pod-cm2 – cat /etc/mysql/port複製程式碼
2。 Secret
Secret 與 ConfigMap 類似, 主要區別是 Secret 儲存的是密文, 而 ConfigMap 儲存的是明文。
所以 ConfigMap 可以用配置檔案管理, 而 Secret 可用於密碼, 金鑰, token 等敏感資料的配置管理。
Secret 的4種類型
Opaque
: base64 編碼格式的 Secret,用來儲存密碼、金鑰、資訊、證書等,型別識別符號為 generic;
Service Account
: 用來訪問 Kubernetes API,由 Kubernetes 自動建立,並且會自動掛載到 Pod的/run/secrets/kubernetes。io/serviceaccount目錄中;
kubernetes.io/dockerconfigjson
: 用來儲存私有 docker registry 的認證資訊,型別標識為docker-registry。
kubernetes.io/tls
: 用於為 SSL 通訊模式儲存證書和私鑰檔案,命令式建立型別標識為 tls。
使用 Opaque 型別來建立 mysql 密碼 Secret
:
將明文密碼進行base64編碼
echo -n 123456 |base64複製程式碼
MTIzNDU2複製程式碼
編寫建立secret的YAML檔案
vim secret-mysql。yml複製程式碼
apiVersion: v1kind: Secretmetadata: name: secret-mysqldata: password: MTIzNDU2複製程式碼
建立secret並確認
kubectl apply -f secret-mysql。ymlkubectl get secret |grep secret-mysql複製程式碼
Secret 的2種使用方式
Secret結構與ConfigMap類似,均是鍵/值對的對映。Secret的使用方法也與ConfigMap相同。
透過環境變數的方式傳遞給 pod
:
vim pod-mysql-secret。yml複製程式碼
apiVersion: v1kind: Podmetadata: name: pod-mysql-secret1spec: containers: - name: mysql-pod image: mysql:5。7 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: secret-mysql # 對應建立的secret名字 key: password複製程式碼
kubectl apply -f pod-mysql-secret。yml複製程式碼
透過 volume 的方式掛載到 pod 內
:
vim pod-mysql-secret2。yml複製程式碼
apiVersion: v1kind: Podmetadata: name: pod-mysql-secret2spec: containers: - name: busybox image: busybox args: - /bin/sh - -c - sleep 100000 volumeMounts: - name: vol-secret # 定義掛載的卷,對應下面定義的卷名 mountPath: “/opt/passwd” # 掛載目錄(支援熱更新),也可以使用subPath掛載檔案(但不支援熱更新) readOnly: true # 只讀 volumes: - name: vol-secret # 定義卷名 secret: # 使用secret secretName: secret-mysql # 對應建立好的secret名複製程式碼
kubectl apply -f pod-mysql-secret2。yml複製程式碼
3。 Volume
Pod 本身具有生命週期,這就帶了一系列的問題,
第一,當一個容器損壞之後,kubelet 會重啟這個容器,但是檔案會丟失-這個容器會是一個全新的狀態;第二,當很多容器在同一 Pod 中執行的時候,很多時候需要資料檔案的共享
。Docker 支援配置容器使用儲存卷將資料持久儲存於容器自身檔案系統之外的儲存空間之中,它們可以是節點檔案系統或網路檔案系統之上的儲存空間。相應的,Kubernetes 也支援類似的儲存卷功能,不過,其儲存卷是與 Pod 資源繫結而非容器。
Kubernetes 中的卷有明確的壽命 —— 與封裝它的 Pod 相同。所以,卷的生命比 Pod 中的所有容器都長,當這個容器重啟時資料仍然得以儲存。當然,當 Pod 不再存在時,卷也將不復存在。也許更重要的是,Kubernetes 支援多種型別的卷,Pod 可以同時使用任意數量的卷。
Kubernetes 支援非常豐富的儲存卷型別,包括本地儲存(節點)和網路儲存系統中的諸多儲存機制,還支援
ConfigMap
和
Secret
這樣的特殊儲存資源。 透過命令
kubectl explain pod。spec
可以檢視當前 kubernetes 版本支援的儲存卷型別。常用型別如下:
非永續性儲存emptyDirhostPath網路連線性儲存SAN:iscsiNFS:nfs、cfs分散式儲存glusterfs、cephfs、rbd雲端儲存awsElasticBlockStore、azureDisk、gitRepo
EmptyDir 儲存卷
emptyDir 儲存卷是 Pod 物件生命週期中的一個臨時目錄,類似於 Docker 上的 “docker 掛載卷”,在 Pod 物件啟動時即被建立,而在 Pod 物件被移除時會被一併刪除(永久刪除)。Pod 中的容器都可以讀寫這個目錄,這個目錄可以被掛載到各個容器相同或者不相同的路徑下。
注意:一個容器崩潰了不會導致資料的丟失,因為容器的崩潰並不移除 Pod
。
emptyDir 的作用
:
普通空間,基於磁碟的資料儲存
作為從崩潰中恢復的備份點
儲存那些需要長久儲存的資料,例如 web 服務中的資料
emptyDir 的示例
:
這裡定義了一個 Pod資源物件(vol-emptydir-pod),在其內部定義了兩個容器,其中一個容器是輔助容器 sidecar,每隔10秒生成一行資訊追加到 index。html 檔案中;另一個是 nginx 容器,將儲存卷掛載到站點家目錄。然後訪問 nginx 的 html 頁面驗證兩個容器之間掛載的 emptyDir 實現共享。
vim vol-emptydir。yaml複製程式碼
apiVersion: v1kind: Podmetadata: name: vol-emptydir-podspec: volumes: #定義儲存卷 - name: html #定義儲存卷的名稱 emptyDir: {} #定義儲存卷的型別 containers: - name: nginx image: nginx:1。12 volumeMounts: #在容器中定義掛載儲存卷的名和路徑 - name: html mountPath: /usr/share/nginx/html - name: sidecar image: alpine volumeMounts: #在容器中定義掛載儲存卷的名和路徑 - name: html mountPath: /html command: [“/bin/sh”, “-c”] args: - while true; do echo $(hostname) $(date) >> /html/index。html; sleep 10; done複製程式碼
kubectl apply -f vol-emptydir。yaml 複製程式碼
HostPath 儲存卷
hostPath 型別的儲存卷是指將工作節點上的某檔案系統的目錄或檔案掛載於 Pod 中的一種儲存卷,獨立於 Pod 資源的生命週期,具有永續性。在 Pod 刪除時,資料不會丟失。
hostPath 儲存卷的 type 型別
:
type
說明
DirectoryOrCreate
指定的路徑不存在時自動建立其許可權為0755的空目錄,屬主和屬組為kubelet
Directory
必須存在的目錄路徑
FileOrCreate
指定的路徑不存在時自動建立其許可權為0644的空檔案,屬主和屬組為kubelet
File
必須存在的檔案路徑
Socket
必須存在的Socket檔案路徑
CharDevice
必須存在的字元裝置檔案路徑
BlockDevice
必須存在的塊裝置檔案路徑
hostPath 的示例
:
vim vol-hostpath。yaml複製程式碼
apiVersion: v1kind: Podmetadata: name: pod-vol-hostpath namespace: defaultspec: containers: - name: myapp image: nginx:1。17。1 imagePullPolicy: IfNotPresent volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /data/pod/volume1 type: DirectoryOrCreate複製程式碼
kubectl apply -f vol-hostpath。yaml複製程式碼
NFS 儲存卷
NFS 是 Network FileSystem 的縮寫,顧名思義就是網路檔案儲存系統, 分為服務端(Server)和客戶端(Client)。最早由 sun 公司開發,是類 unix 系統間實現磁碟共享的一種方法。 它允許網路中的計算機之間透過 TCP/IP 網路共享資源。透過 NFS,我們本地 NFS 的客戶端應用可以透明地讀寫位於服務端 NFS 伺服器上的檔案,就像訪問本地檔案一樣方便。簡單的理解,NFS 就是可以透過網路,讓不同的主機、不同的作業系統可以共享儲存的服務。
NFS 在檔案傳送或資訊傳送過程中依賴於 RPC(Remote Procedure Call) 協議,即遠端過程呼叫,NFS 的各項功能都必須要向 RPC 來註冊,如此一來 RPC 才能瞭解 NFS 這個服務的各項功能 Port、PID、NFS 在伺服器所監聽的 IP 等,而客戶端才能夠透過 RPC 的詢問找到正確對應的埠,所以,NFS必須要有 RPC 存在時才能成功的提供服務,簡單的理解二者關係:NFS是 一個檔案儲存系統,而 RPC是負責資訊的傳輸。
宿主機搭建 NFS
:
(1) 透過 yum 安裝
yum -y install rpcbind nfs-utils 複製程式碼
(2) 建立網路上的芳鄰共享目錄
mkdir /mnt/share複製程式碼
(3) 配置這個共享目錄
vim /etc/exports複製程式碼
寫入下邊的內容:
/mnt/share 192。168。138。0/24(rw,no_root_squash,async,fsid=0)複製程式碼
(4) 使配置內容生效
exportfs -r 複製程式碼
(5) 啟動 rpcbind、nfs 服務及開機自啟動
systemctl start rpcbindsystemctl start nfssystemctl enable rpcbindsystemctl enable nfs複製程式碼
4。 PV 和 PVC
前面提到 Kubernetes 提供那麼多儲存介面,但是首先 Kubernetes 的各個 Node 節點能管理這些儲存,但是各種儲存引數也需要專業的儲存工程師才能瞭解,由此我們的 Kubernetes 管理變的更加複雜。由此 kubernetes 提出了 PV 和 PVC 的概念,這樣開發人員和使用者就不需要關注後端儲存是什麼,使用什麼引數等問題。
PV
PersistentVolume(PV)是叢集中已由管理員配置的一段網路儲存。叢集中的資源就像一個節點是一個叢集資源。PV 是諸如卷之類的卷外掛,但是具有獨立於使用 PV 的任何單個 Pod 的生命週期。該 API 物件捕獲儲存的實現細節,即 NFS,ISCSI或雲提供商特定的儲存系統。
PVC
PersistentVolumeClaim(PVC)是使用者儲存的請求。它類似於 Pod。Pod 消耗節點資源,PVC 消耗儲存資源。Pod 可以請求特定級別的資源(CPU 和記憶體)。許可權要求可以請求特定的大小和訪問模式。
雖然 PersistentVolumeClaims 允許使用者使用抽象儲存資源,但是常見的是,使用者需要具有不同屬性(如效能)的 PersistentVolumes ,用於不同的問題。叢集管理員需要能夠提供多種不同於 PersistentVolumes 的 PersistentVolumes ,而不僅僅是大小和訪問模式,而不會使使用者瞭解這些卷的實現細節。對於這些需求,存在 StorageClass 資源。
StorageClass 為管理員提供了一種描述他們提供的儲存的“類”的方法
。不同的類可能對映到服務質量級別,或備份策略,或者由叢集管理員確定的任意策略。Kubernetes 本身對於什麼類別代表是不言而喻的。這個概念有時在其它儲存系統中稱為“配置檔案”。
生命週期
PV 是叢集中的資源。PVC 是對這些資源的請求,也是對資源的索賠檢查。PV 和 PVC 之間的相互作用遵循這個生命週期:
Provisioning —> Binding —> Using —> Releasing —> Recycling複製程式碼
供應準備(Provisioning)
PV 有兩種提供方式:靜態或者動態
Static:叢集管理員建立多個 PV 。它們攜帶可供叢集使用者使用的真實儲存的詳細資訊。它們存在於 Kubernetes API 中,可用於消費。
Dynamic:當管理員建立的靜態 PV 都不匹配使用者的 PersistentVolumesClaim 時,叢集可能會嘗試為 PVC 動態配置卷。此配置基於 StorageClasses:PVC 必須請求一個類,並且管理員必須已經建立並配置該類才能進行動態配置。要求該類的宣告有效地為自己禁用動態配置。
繫結(Binding)
使用者建立 PVC 並指定需要的資源和訪問模式。在找到可用 PV 之前,PVC 會保持未繫結狀態。
使用(Using)
使用者可在 Pod 中像 volume 一樣使用 PVC。
釋放(Releasing)
使用者刪除 PVC 來回收儲存資源,PV 將變成 “released” 狀態。由於還保留著之前的資料,這些資料要根據不同的策略來處理,否則這些儲存資源無法被其它 PVC 使用。
回收(Recycling)
PV 可以設定三種回收策略:保留(Retain)、回收(Recycle)和刪除(Delete)。
PV 欄位說明
PersistentVolume Spec 主要支援以下幾個通用欄位,用於定義 PV 的容量、訪問模式、和回收策略:
欄位
說明
capacity
當前PV的容量;目前,capacity僅支援空間設定,將來應該還可以指定IOPS和throughput。
accessModes
訪問模式;儘管在PV層看起來並無差異,但儲存裝置支援及啟用的功能特性卻可能不盡相同。例如NFS儲存支援多客戶端同時掛載及讀寫操作,但也可能是在共享時僅啟用了只讀操作,其他儲存系統也存在類似的可配置特性。因此,PV底層的裝置或許存在其特有的訪問模式,使用者使用時必須在其特性範圍內設定其功能。
-
ReadWribeOnce
:僅可被單個節點讀寫掛載;命令列中簡寫為RWO。
-
ReadOnlyMany
:可被多個節點同時只讀掛載;命令列中簡寫為ROX。
-
ReadWriteMany
:可被多個節點同時讀寫掛載;命令列中簡寫為RWX。
persistentVolumeReclaimPolicy
PV空間被釋放時的處理機制;可用型別僅為Retain(預設)、Recycle或Delete,具體說明如下。
-
Retain
:保持不動,由管理員隨後手動回收。
-
Recycle
:空間回收,即刪除儲存卷目錄下的所有檔案(包括子目錄和隱藏檔案),目前僅NFS和hostPath支援此操作。
-
Delete
:刪除儲存卷,僅部分雲端儲存系統支援,如AWS EBS、GCE PD、Azure Disk和Cinder。
volumeMode
卷模型,用於指定此卷可被用作檔案系統還是裸格式的塊裝置;預設為Filesystem。
storageClassName
當前PV所屬的StorageClass的名稱;預設為空值,即不屬於任何StorageClass。
mountOptions
掛載選項組成的列表,如ro、soft和hard等。
PVC 欄位說明
PersistentVolumeClaim 是儲存卷型別的資源,它透過申請佔用某個 PersistentVolume 而建立,它與 PV 是一對一的關係,使用者無須關係其底層實現細節。申請時,使用者只需要指定目標空間的大小、訪問模式、PV標籤選擇器和 StorageClass 等相關資訊即可。PVC 的 Spec 欄位的可巢狀欄位具體如下:
欄位
說明
accessModes
當前PVC的訪問模式,其可用模式與PV相同
resources
當前PVC儲存卷需要佔用的資源量最小值;目前,PVC的資源限定僅指其空間大小
selector
繫結時對PV應用的標籤選擇器(matchLabels)或匹配條件表示式(matchEx-pressions),用於挑選要繫結的PV;如果同時指定了兩種挑選機制,則必須同時滿足兩種選擇機制的PV才能被選出
storageClassName
所依賴的儲存卷的名稱
volumeMode
卷模型,用於指定此卷可被用作於檔案系統還是裸格式的塊裝置;預設為“Filesystem”
volumeName
用於直接指定要繫結的PV的卷名
示例使用 PV 和 PVC
準備了一臺 NFS Server 建立了幾個共享目錄提供給 Kubernetes 作為 PV 使用。在建立 PV 的同時指定了不同的大小和不同的訪問許可權,然後在建立 PVC 時候指定了大小為 6Gi ,故滿足條件的 PV 只有 pv003~pv005 ,這裡透過標籤選擇器選擇了 pv003 。Pod中的容器使用了 MySQL,並將 MySQL 的資料目錄掛載到 PV 上。示例圖如下:
準備 NFS 服務
(1)建立儲存卷對應的目錄[root@storage ~]# mkdir /data/volumes/v{1。。5} -p(2)修改nfs的配置檔案[root@storage ~]# vim /etc/exports/data/volumes/v1 192。168。1。0/24(rw,no_root_squash)/data/volumes/v2 192。168。1。0/24(rw,no_root_squash)/data/volumes/v3 192。168。1。0/24(rw,no_root_squash)/data/volumes/v4 192。168。1。0/24(rw,no_root_squash)/data/volumes/v5 192。168。1。0/24(rw,no_root_squash)(3)檢視nfs的配置[root@storage ~]# exportfs -arvexporting 192。168。1。0/24:/data/volumes/v5exporting 192。168。1。0/24:/data/volumes/v4exporting 192。168。1。0/24:/data/volumes/v3exporting 192。168。1。0/24:/data/volumes/v2exporting 192。168。1。0/24:/data/volumes/v1(4)使配置生效[root@storage ~]# showmount -eExport list for storage:/data/volumes/v5 192。168。1。0/24/data/volumes/v4 192。168。1。0/24/data/volumes/v3 192。168。1。0/24/data/volumes/v2 192。168。1。0/24/data/volumes/v1 192。168。1。0/24複製程式碼
建立 PV;這裡建立 5 個 PV ,儲存大小各不相等,是否可讀也不相同
vim pv-nfs-demo。yaml複製程式碼
apiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-001 labels: name: pv001spec: nfs: path: /data/volumes/v1 server: 192。168。1。34 readOnly: false accessModes: [“ReadWriteOnce”,“ReadWriteMany”] capacity: storage: 2Gi persistentVolumeReclaimPolicy: Retain——-apiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-002 labels: name: pv002spec: nfs: path: /data/volumes/v2 server: 192。168。1。34 readOnly: false accessModes: [“ReadWriteOnce”] capacity: storage: 5Gi persistentVolumeReclaimPolicy: Retain——-apiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-003 labels: name: pv003spec: nfs: path: /data/volumes/v3 server: 192。168。1。34 readOnly: false accessModes: [“ReadWriteOnce”,“ReadWriteMany”] capacity: storage: 10Gi persistentVolumeReclaimPolicy: Retain——-apiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-004 labels: name: pv004spec: nfs: path: /data/volumes/v4 server: 192。168。1。34 readOnly: false accessModes: [“ReadWriteOnce”,“ReadWriteMany”] capacity: storage: 15Gi persistentVolumeReclaimPolicy: Retain——-apiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-005 labels: name: pv005spec: nfs: path: /data/volumes/v5 server: 192。168。1。34 readOnly: false accessModes: [“ReadWriteOnce”,“ReadWriteMany”] capacity: storage: 20Gi persistentVolumeReclaimPolicy: Retain複製程式碼
kubectl apply -f pv-nfs-demo。yaml 複製程式碼
建立 PVC ,繫結 PV
vim vol-nfs-pvc。yaml複製程式碼
#建立PVCapiVersion: v1kind: PersistentVolumeClaimmetadata: name: nfs-pvcspec: accessModes: [“ReadWriteMany”] resources: requests: storage: 6Gi #指定PVC大小為6Gi selector: #這裡透過標籤選擇器指定了所使用的pv卷為key為name,value為pv003的pv資源 matchLabels: name: pv003——-#建立PodapiVersion: v1kind: Podmetadata: name: pvc-mysql labels: app: mysqlspec: containers: - name: pvc-mysql-pod image: mysql:latest imagePullPolicy: IfNotPresent ports: - name: mysqlport containerPort: 3306 volumeMounts: - name: mysqldata mountPath: /var/lib/mysql env: - name: MYSQL_ROOT_PASSWORD value: “mysql” volumes: - name: mysqldata persistentVolumeClaim: #透過該欄位定義使用pvc claimName: nfs-pvc #指定pvc的名稱 readOnly: false #關閉只讀複製程式碼
kubectl apply -f vol-nfs-pvc。yaml