Sitemap
Sergen

Sergen

NFS StorageClass

4 min readJan 4, 2024

--

Kubernetes üzerinde tanımlanabilecek bir StorageClass tipi olarak NFS tercih edilebilecek bir yöntemdir. ReadWriteOnce’ın yanı sıra ReadWriteMany yapabiliyor olması büyük avantajdır.

Kubernetes üzerinde depolama işleriyle ilgili genel olarak bilgi almak için aşağıdaki link göz atabilirsiniz.

NFS Server

Kubernetes tarafındaki ayarlara geçmeden önce bu ayarları yapılandıracağımız bir NFS Server kuralım. NFS kuracağımız sunucu IP’si 192.168.1.30 olacaktır.

# Red Hat Enterprise Linux
yum install nfs-utils

# Ubuntu
apt install nfs-kernel-server

Kurulumu yaptıktan sonra /etc/exportfs dosyasında aşağıdaki şekilde tanım yapalım. /data/nfs dizinine 192.168.1.0/24 adresinden erişilebilen bir NFS alanı oluşturmuş olduk.

vi /etc/exportfs
/data/nfs 192.168.1.0/24(rw,sync,root_squash,no_subtree_check,no_wdelay)

Sonra dizin tarafında yetkilendirmesini yapalım.

chmod -R 777 /data/nfs
chown -R nobody: /data/nfs

Son olarak servisi başlatalım ve konfigürasyona eklediğimiz tanımı uygulamaya alalım.

systemctl restart nfs-kernel-server
exportfs -a

Provisioner

Burada kullanacağımız provisioner topluluk tarafından oluşturulmuş ancak çalışma anında 4–5 ay civarında çalıştırdığım ve sorun yaşamadığım bir cluster mevcut; güvenilirlik için kısa bir süre olabilir ama geçici bir yapıda yahut test ortamlarında kullanılabilir. Detaylar için github deposuna bakılabilir.

# Önce bir namespace oluşturalım
kubectl create namespace nfs-system
# Kubernetes içerisinde ayağa kaldırılacak olan provisioner için Service Account ve Role tanımları yapalım.
# Bu satırları rbac.yaml olarak kayıt edelim.
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
namespace: nfs-system
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- 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: ServiceAccount
name: nfs-client-provisioner
namespace: nfs-system
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
namespace: nfs-system
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
namespace: nfs-system
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: nfs-system
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
# Dosyayı Kubernetes API'sine verelim.
kubectl apply -f rbac.yaml
# Provisioner olarak ayağa kaldırılacak asıl deployment budur.
# NFS_SERVER ve NFS_PATH satırlarında değişiklik yapalım.
# Bu satırları deployment.yaml olarak kayıt edelim.
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
namespace: nfs-system
spec:
replicas: 1
selector:
matchLabels:
app: nfs-client-provisioner
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.1.30
- name: NFS_PATH
value: /data/nfs/
volumes:
- name: nfs-client-root
nfs:
server: 192.168.1.30
path: /data/nfs/
# Dosyayı Kubernetes API'sine verelim.
kubectl apply -f deployment.yaml

Son olarak StorageClass tanımı yapacağız.

# Bu satırları storageclass.yaml olarak kayıt edelim.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiveOnDelete: "true"

Yukarıdaki tanımda parameters kısmı altında pathPattern ile oluşacak StorageClass kullanılarak oluşturulacak PVC objelerinin tutacağı veriyi sunucudaki dizin yapısının nasıl olacağını şekillendirebiliriz. Varsayılan olarak namespace-pvc-pod isimleri arka arkaya gelerek bir dizin oluşturur.

Get Sergen’s stories in your inbox

Join Medium for free to get updates from this writer.

Ayrıca provisioner kısmında yazan k8s-sigs.io/nfs-subdir-external-provisioner isimlendirmesi deployment içerisinde öyle olduğu içindir. Dilenirse organizasyonunuza göre değiştirilebilir. Ancak bu durumda deployment.yaml dosyasında da değiştirmek gerekecektir.

# Dosyayı Kubernetes API'sine verelim.
kubectl apply -f storageclass.yaml

Tüm bu süreçler sonunda StorageClass objemizi göreceğiz.

$ kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client cluster.local/nfs-subdir-external-provisioner Delete Immediate true 35d

Test

Bu oluşturduğumuz StorageClass objemizi kullanarak bir pod ayağa kaldıralım. Bunun için öncelikle bir PVC tanımı yapmamız gerekiyor.

# Bu satırları pvc.yaml olarak kayıt edelim.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-nfs-provisioner
namespace: default
spec:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Mi
# Dosyayı Kubernetes API'sine verelim.
$ kubectl apply -f pvc.yaml
persistentvolumeclaim/test-nfs-provisioner created

$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-nfs-provisioner Bound pvc-cc71af56-5d31-4ee8-80aa-25aeb9a250d9 10Mi RWX nfs-client 46s
Press enter or click to view image in full size
NFS sunucusundan baktığımızda dizinin şu şekilde oluştuğunu görebiliriz.

# Bu satırları test-pod.yaml olarak kayıt edelim.
apiVersion: v1
kind: Pod
metadata:
labels:
run: ubuntu
name: test-pod
namespace: default
spec:
containers:
- image: ubuntu
name: ubuntu
resources: {}
command: ["sleep", "3600"]
volumeMounts:
- mountPath: /nfs
name: nfs-vol
volumes:
- name: nfs-vol
persistentVolumeClaim:
claimName: test-nfs-provisioner
# Dosyayı Kubernetes API'sine verelim.
$ kubectl apply -f test-pod.yaml
pod/ubuntu-test-nfs created

$ kubectl get pod
NAME READY STATUS RESTARTS AGE
ubuntu-test-nfs 1/1 Running 0 7s

$ kubectl exec -it test-pod -- /bin/bash
Press enter or click to view image in full size
Podun içerisinde dosya ve dizin oluşturduğumuzda
Press enter or click to view image in full size
NFS sunucusundan görebiliyor olacağız

Helm

Aynı işlemleri helm üzerinden şu şekilde gerçekleştirebiliriz.

helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner
helm install nfs-subdir-external-provisioner \
nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=192.168.1.30 \
--set nfs.path=/data/nfs \
--set storageClass.onDelete=true \
-n nfs-system --create-namespace

--

--