NFS在kubernetes中做为共享存储,用的还是比较多的,之前也就是一直用着,也没有太关注是如何实现Dynamic provisioning,今天花了点时间研究了一下原理,还是挺有意思.
NFS Servers
1 | # 安装 |
NFS Client
client端只需要二步即可使用server端share出来的目录
1 | # 创建目录 |
当然,在kubernetes中主要还是使用Dynamic NFS provisioning为主, 不会直接像上面这样使用nfs
这里还是将3种方式都贴一下.
使用volume
nfs做为volume还是有好几种使用方式的:
做为普通volume
1 | apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 |
作为persistentVolume
1 | apiVersion: v1 |
上面两种方式在kubernetes用nfs做为持久卷时用的还是比较少,因为需要事先在nfs中创建好相关的目录,存在一些手工操作. 重点在下.
作为Dynamic NFS provisioning
helm部署参考nfs-client-provisioner
这里选择重要的资源对象来阐述nfs是如何实现dynamic provision功能的
首先来看一下storageclass,这个也没什么好说的.
1 | apiVersion: storage.k8s.io/v1 |
还会部署一个deployment资源
1 | kind: Deployment |
这个deployment其实是做为一个nfs client起作用,它把整个nfs server的共享目录/nfs/data都挂载到了/persistentvolumes下, 这为后面根据pvc自动生成创建pv目录有关.
生成一个pvc
1 | apiVersion: v1 |
当使用一个pod指定使用使用上面的pvc后,上面的deployment会根据pvc自动生成一个pv, pvc与该pv进行绑定, 且在nfs servers上创建相应的目录,pod将该目录挂载进了自己容器目录中,这样就实现了Dynamic provisioning功能了
1 | $ kubectl apply -f nfs_pvc_dynamic.yaml |
nfs-pvc-test为pvc, pvc-620ff5b1-b2df-11e9-a66a-080027db98ca为pv, default-nfs-pvc-test-pvc-620ff5b1-b2df-11e9-a66a-080027db98ca即为在nfs-server共享目录下创建的目录,这个目录最后被为使用该pvc的pod挂载.
这个deployment的源码可参考nfs-client-provisioner, deployment核心代码如下:
1 | func (p *nfsProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) { |
因此整个流程为:
pod生成使用一个pvc, 当pvc发布到集群中时, nfs-client-provisioner deployment就会根据该pvc的yaml文件获取namespace, pvc-name等信息在挂载的nfs共享目录下创建新的目录, 然后生成一个pv与该pvc绑定,pod使用该pv就相当于使用nfs server共享目录一样
那nfs server的共享目录是如何做到的呢?
NFS 原理
NFS 使用RPC(Remote Procedure Call)的机制进行实现,RPC使得客户端可以调用服务端的函数。同时,由于有 VFS 的存在,客户端可以像使用其它普通文件系统一样使用 NFS 文件系统。经由操作系统的内核,将 NFS 文件系统的调用请求通过 TCP/IP 发送至服务端的 NFS 服务。NFS服务器执行相关的操作,并将操作结果返回给客户端
我觉得上面那段话说的很明白, nfs实现共享存储还是通过网络将本地操作写入到nfs server端,只不过这个网络操作由RPC来完成, 同时也需要内核的支持.
nfs更加详细的原理,感兴趣的可以参考NFS原理详解