k8s之StorageClass+NFS
参考:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
参考:https://jimmysong.io/kubernetes-handbook/practice/using-nfs-for-persistent-storage.html
一、什么是StorageClass
参考:https://kubernetes.io/zh/docs/concepts/storage/storage-classes/
StorageClass翻译过来是存储类的意思。
PV这个对象的创建,是由运维人员完成的。但是在大规模的生产环境里面,这是一个非常麻烦的操作。
这是因为,一个大规模的kubernetes集群里面很可能有成千上万个PVC,这就意味着运维人员必须事先创建出成千上万个PV。更麻烦的是,随着PVC不断被提交,运维人员就不得不继续添加新的、能满足条件的PV,否则新的Pod就会因为PVC绑定不到PV而失败,在实际操作中,这几乎没办法靠人工做到。
所以,kubernetes为我们提供了一套可以自动创建PV的机制,即:Dynamic Privisioning。
相比之下,人工管理的PV就叫做Static Provisioning。
Dynamic Provisioning机制工作的核心,在于一个名叫StorageClass的API对象。
而StorageClass对象的作用,其实就是创建PV的模板。
具体的说,StorageClass对象会定义如下两个部分的内容:
- 第一,PV的属性,比如存储类型,Volume大小等等。
- 第二:创建PV需要用到的存储插件。比如,Ceph等。
有了这两个信息之后,Kubernetes就能根据用户提交的PVC,找到一个对应的StorageClass了。然后,Kubernetes就会调用该StorageClass声明的存储插件,创建出需要的PV。
举个例子,如果我们使用的GCE的Persistent Disk,需要定义这样一个StorageClass:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: block-service
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
这个YAML文件里面,我们定义了一个名叫block-service的StorageClass。
provisioner字段值为kubernetes.io/gce-pd
,这个正是Kubernetes内置的GCE PD存储插件的名字,其他可以参考这里。
parameters字段是PV的参数,上面type=pd-ssd
指的是这个PV的类型是“SSD格式的GCE远程磁盘。”
这时候,作为应用开发者,只需要在PVC里面指定要使用的StorageClass名字即可。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: claim1
spec:
accessModes:
- ReadWriteOnce
storageClassName: block-service
resources:
requests:
storage: 30Gi
当然,如果kubernetes官方文档里面没有找到想要的插件,则可以通过external-storage这个库来编写一个外部插件来完成这个工作。
就例如我们今天使用的NFS,k8s官方就没有内置的存储插件,不过有已经做好的例子,参考nfs-subdir-external-provisioner
二、部署nfs-server
随便找一个节点部署nfs-server即可,我放到k8s-master节点了
我是ubuntu系统
[root@k8s ~]# apt install nfs-kernel-server rpcbind -y
[root@k8s ~]# mkdir /data/nfs -p
[root@k8s ~]# chmod 777 /data/nfs/
[root@k8s ~]# vim /etc/exports
[root@k8s ~]# tail -1 /etc/exports
/data/nfs 192.168.66.0/24(rw,sync,no_subtree_check,no_root_squash)
[root@k8s ~]# systemctl restart nfs-kernel-server.service rpcbind
[root@k8s ~]# systemctl enable nfs-kernel-server.service rpcbind
[root@k8s ~]# showmount -e 192.168.66.143
Export list for 192.168.66.143:
/data/nfs 192.168.66.0/24
注意,node节点需要安装nfs-common,不然后面挂载pvc会失败
三、下载yaml清单文件
修改deployment.yaml文件里面的nfs地址和路径
https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/tree/master/deploy
[root@k8s nfs-sc]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: shuangchenyue/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.66.143
- name: NFS_PATH
value: /data/nfs
volumes:
- name: nfs-client-root
nfs:
server: 192.168.66.143
path: /data/nfs
四、创建rbac,deployment,storageclass
创建好后要确认pod正常运行,不正常的话需要自己排查下,大都是nfs挂载失败等
[root@k8s nfs-sc]# kubectl create -f rbac.yaml
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
[root@k8s nfs-sc]# kubectl create -f deployment.yaml
deployment.apps/nfs-client-provisioner created
[root@k8s nfs-sc]# kubectl create -f class.yaml
storageclass.storage.k8s.io/managed-nfs-storage created
五、设置默认存储
参考:https://kubernetes.io/zh/docs/tasks/administer-cluster/change-default-storage-class/
[root@k8s nfs-sc]# kubectl patch storageclass managed-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
storageclass.storage.k8s.io/managed-nfs-storage patched
六、创建pod测试
[root@k8s nfs-sc]# cat test-pod.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-volume
spec:
accessModes:
- ReadWriteOnce
storageClassName: managed-nfs-storage
resources:
requests:
storage: 1Mi
---
apiVersion: v1
kind: Pod
metadata:
name: web-nginx
spec:
volumes:
- name: web
persistentVolumeClaim:
claimName: pv-volume
containers:
- name: web-nginx
image: nginx:alpine
volumeMounts:
- name: web
mountPath: /usr/share/nginx/html
[root@k8s nfs-sc]# kubectl create -f test-pod.yaml
persistentvolumeclaim/pv-volume created
pod/web-nginx created
[root@k8s nfs-sc]# kubectl exec -it web-nginx -- sh -c "echo hello > /usr/share/nginx/html/index.html"
[root@k8s nfs-sc]# curl --noproxy "*" http://172.20.0.49/
hello
#删掉pod重建数据不变,说明pvc挂载成功
[root@k8s nfs-sc]# kubectl delete po web-nginx
pod "web-nginx" deleted
[root@k8s nfs-sc]# kubectl create -f test-pod.yaml
pod/web-nginx created
Error from server (AlreadyExists): error when creating "test-pod.yaml": persistentvolumeclaims "pv-volume" already exists
[root@k8s nfs-sc]# kubectl get po web-nginx -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-nginx 0/2 PodInitializing 0 12s 172.20.0.50 192.168.66.143 <none> <none>
[root@k8s nfs-sc]# curl --noproxy "*" http://172.20.0.50
hello