---
# System prepended metadata

title: Create ReadWriteMany Persistent Volume in Google Kubernetes Engine
tags: [gke, persistent-volume, k8s, volume]

---

# Create ReadWriteMany Persistent Volume in Google Kubernetes Engine

Familiarity with [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) is suggested.

## Introduction

**Terminologies**：

- Persistent Volume (PV)：在 cluster 中已由管理員提供或使用 [Storage Classes](https://kubernetes.io/docs/concepts/storage/storage-classes/) 動態提供的一部分的儲存(storage)。它是 cluster 內的資源就像是 node 是一種 cluster 資源一樣。PV 擁有獨立於使用該 PV 的 pod 的生命週期。
- Persistent Volume Claim (PVC)：使用者對於儲存的請求。類似於 pod 消耗 node 的資源，而 PVCs 消耗 PV 的資源。Pod 請求特定級別的資源（CPU 和記憶體）。Claims 可以請求特定大小和存取模式。

*PersistentVolume* 有以下幾種[存取模式](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes)：

- ReadWriteOnce
- ReadOnlyMany
- ReadWriteMany
- ReadWriteOncePod

但目前 [Google Compute Engine persistent disk](https://kubernetes.io/docs/concepts/storage/volumes/#gcepersistentdisk) 只支援 RWO 和 ROX。因此想要擁有一個所有 nodes 都能夠讀寫的空間，最好的方法是使用 [Filestore](https://cloud.google.com/filestore)。但若是資料量較小的話，Filestore 則不太適合，因為它提供最小的空間為 1 TB，一個月就需要約 NT$ 6,000。

因此比較適合的方法就是在 K8s 建立一個網路檔案系統（NFS）。

## Steps

[GitHub Example](https://github.com/kubernetes/examples/tree/master/staging/volumes/nfs)

1. 先建立一個 GCE PD 作為 NFS 的掛載 volume

   ```yaml
   apiVersion: v1
   kind: PersistentVolumeClaim
   metadata:
     name: nfs-pvc
   spec:
     resources:
       requests:
         storage: 20Gi
     accessModes:
       - ReadWriteOnce
   ```
   ![GCE disk](https://i.imgur.com/5Shq5Ym.png)

2. 建立 NFS 並設定相關 ports，並連上剛建立的 Volume

   ```yaml
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: nfs-server
   spec:
     replicas: 1
     selector:
       matchLabels:
         role: nfs-server
     template:
       metadata:
         labels:
           role: nfs-server
       spec:
         containers:
         - name: nfs-server
           image: gcr.io/google_containers/volume-nfs:0.8
           ports:
             - name: nfs
               containerPort: 2049
             - name: mountd
               containerPort: 20048
             - name: rpcbind
               containerPort: 111
           securityContext:
             privileged: true
           volumeMounts:
             - mountPath: /exports
               name: mypvc
         volumes:
           - name: mypvc
             persistentVolumeClaim:
               claimName: nfs-pvc
   ```
   ![GKE workflow](https://i.imgur.com/LmfDu9K.png)

3. 將此 NFS pod 對外開放，設定叢集 IP

   ```yaml
   apiVersion: v1
   kind: Service
   metadata:
     name: nfs-server
   spec:
     ports:
       - name: nfs
         port: 2049
       - name: mountd
         port: 20048
       - name: rpcbind
         port: 111
     selector:
       role: nfs-server
   ```
   
![GKE service](https://i.imgur.com/z1F80tE.png)

4. 建立 RWX 的 PV & PVC 供其他人使用 
   ```yaml
   apiVersion: v1
   kind: PersistentVolume
   metadata:
     name: nfs-pv1
   spec:
     capacity:
       storage: 1Gi
     accessModes:
       - ReadWriteMany
     nfs:
       server: nfs-server.default.svc.cluster.local
       path: "/"
   ---
   kind: PersistentVolumeClaim
   apiVersion: v1
   metadata:
     name: nfs-pvc1
   spec:
     accessModes:
       - ReadWriteMany
     storageClassName: ""
     resources:
       requests:
         storage: 1Gi
     volumeName: nfs-pv1
   ```
   
   可使用 `kubectl get pv ; kubectl get pvc` 檢查
   ![pv & pvc](https://i.imgur.com/N2a78ir.png)

5. 將剛建立的 PVC 掛進你需要的 pod 即完成

   ```yaml
   apiVersion: v1
   kind: Deployment
   metadata:
     name: nfs-busybox
   spec:
     replicas: 2
     selector:
       name: nfs-busybox
     template:
       metadata:
         labels:
           name: nfs-busybox
       spec:
         containers:
         - image: busybox
           command:
             - sh
             - -c
             - 'while true; do date > /mnt/index.html; hostname >> /mnt/index.html; sleep $(($RANDOM % 5 + 5)); done'
           imagePullPolicy: IfNotPresent
           name: busybox
           volumeMounts:
             # name must match the volume name below
             - name: nfs
               mountPath: "/mnt"
         volumes:
         - name: nfs
           persistentVolumeClaim:
             claimName: nfs-pvc1
   ```

以上就完成一個在 GKE 的 ReadWriteMany volume


###### tags: `gke` `persistent-volume` `volume` `k8s`