关注微信公众号:CodingTechWork,一起学习进步。
NFS介绍
概述
网络文件系统(Network File System, NFS),是基于内核的文件系统,nfs主要是通过网络实现服务器和客户端之间的数据传输,采用远程过程调用RPC(Romete Procedure Call)机制,让不同的机器节点共享文件目录。只需将nfs服务器共享的文件目录挂载到nfs客户端,这样客户端就可以对远程服务器上的文件进行读写操作。
一个NFS服务器可以对应多个nfs客户端,基于RPC机制,用户可以像访问本地文件一样访问远端的共享目录文件,使用起来很nice!
原理
挂载原理
如图所示,在NFS服务器创建并设置好一个共享目录/nfs
,其他网络互通的NFS客户端可以将该目录挂载到本地文件系统中的某个挂载点(可自定义),如NFS客户端A挂载到/nfs-a/data
中,NFS客户端B挂载到/nfs-b/data
中,这样NFS客户端可以在本地的挂载目录即可看到NFS服务器共享目录/nfs
内的所有数据。具体的权限(如只读、读写等权限)根据服务器的配置而定。
通信原理
如图所示,通过RPC和NFS服务传输数据。
- NFS服务端启动RPC服务,开启111端口,可以通过nfsnetstat。
- NFS服务端启动NFS服务,并向RPC注册端口信息。
- NFS客户端启动RPC服务,向服务端RPC服务请求NFS服务端口。
- NFS服务端RPC服务反馈NFS端口信息给NFS客户端。
- NFS客户端通过获取的NFS端口简历和服务端的NFS连接,并通过RPC及底层TCP/IP协议进行数据传输。
NFS服务器搭建
部署步骤
可以在linux系统的k8s集群中任意一个node节点做nfs服务端。
-
检查防火墙服务
$ systemctl status firewalld
若防火墙未关闭,使用如下命令进行关闭$ systemctl stop firewalld
$ systemctl disable firewalld
-
检查SELinux
$ cat /etc/selinux/config
若未关闭禁用,使用如下命令:$ setenforce 0
$ sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config
-
安装nfs相关服务软件包
$ yum install -y nfs-utils rpcbind
-
创建共享存储文件夹
$ mkdir /nfs
-
配置nfs
$ vi /etc/exports
输入以下内容,格式为:nfs共享目录 nfs客户端地址1(param1, param2,...) nfs客户端地址2(param1, param2,...)
/nfs 10.1.1.0/24(rw,async,no_root_squash)
-
启动服务
先启动rpc服务,再启动nfs服务$ systemctl start rpcbind
$ systemctl enable rpcbind
$ systemctl enable nfs && systemctl restart nfs
-
查看服务状态
$ systemctl status rpcbind
$ systemctl status nfs
-
查看可用的nfs地址
showmount -e 127.0.0.1
或showmount -e localhost
[root@k8s ~]# showmount -e localhost
Export list for localhost:
/nfs 10.1.1.0/24
共享目录修改
创建好共享目录通过/etc/exports
进行编辑配置,若修改后,可以通过systemctl reload nfs
或者exportfs -avr
进行nfs服务的重新加载发布,从而使修改过的/etc/exports
配置文件生效。
NFS客户端配置
配置步骤
使用nfs共享目录的都需要配置一遍以下步骤。
- 安装nfs-utils和rpcbind
$ yum install -y nfs-utils rpcbind
- 创建挂载的文件夹
$ mkdir -p /nfs/data
- 挂载nfs
$ mount -t nfs 10.1.1.1:/nfs /nfs/data
其中:mount
:表示挂载命令-t
:表示挂载选项nfs
:挂载的协议10.1.1.1
:nfs服务器的ip地址/nfs
:nfs服务器的共享目录/nfs/data
:本机客户端要挂载的目录 - 查看挂载信息
$ df -Th
- 测试挂载
可以进入本机的/nfs/data
目录,上传一个文件,然后去nfs服务器查看/nfs目录中是否有该文件,若有则共享成功。反之在nfs服务器操作/nfs
目录,查看本机客户端的目录是否共享。 - 取消挂载
$ umount /nfs/data
挂载的方式
除了上述通过mount -t nfs
命令指定的方式进行目录挂载以外,还可以通过vim /etc/fstab
文件进行挂载。
10.1.1.1:/nfs /nfs/data nfs defaults 1 1
其中:
- 第一列
10.1.1.1:/nfs
:(Device)磁盘设备文件或该设备的Label或者UUID,此处即为nfs服务器的地址和共享目录 - 第二列
/nfs/data
:(Mount point)是设备的挂载点,即本机挂载目录 - 第三列
nfs
:(Filesystem)是磁盘文件系统的格式,如ext2、nfs、vfat等。 - 第四列
defaults
:(parameters)是文件系统的参数,defaults
即具有rw,suid,dev,exec,auto,nouser,async
等默认参数。 - 第五列
1
:(Dump)能够被dump备份命令作用,一般是0或者1,0表示不用做dump备份,1表示每天进行dump操作,当然还有2,表示不定期进行dump操作。 - 第六列
1
:是否检验扇区,0表示不要检验,1表示最早检验(根目录一般会设置),2表示1级别检验完成之后进行检验。
k8s基于nfs创建storageclass
下载开源插件
- 下载
git clone https://github.com/kubernetes-incubator/external-storage.git
或者git clone https://github.com/kubernetes-retired/external-storage.git
- 进入部署目录
cd external-storage/nfs-client/deploy
部署授权
[root@k8s deploy]# cat rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- 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
# replace with namespace where provisioner is deployed
namespace: default
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
# replace with namespace where provisioner is deployed
namespace: default
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
# replace with namespace where provisioner is deployed
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
[root@k8s deploy] kubectl create -f rbac.yaml
[root@k8s deploy] kubectl get sa
NAME SECRETS AGE
default 1 82d
nfs-client-provisioner 1 25s
部署插件
[root@k8s deploy]# 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: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
# 必须与class.yaml中的provisioner的名称一致
value: fuseim.pri/ifs
- name: NFS_SERVER
# NFS服务器的ip地址
value: 10.1.1.0
- name: NFS_PATH
# 修改为实际创建的共享挂载目录
value: /nfs
volumes:
- name: nfs-client-root
nfs:
# NFS服务器的ip地址
server: 10.154.2.154
# 修改为实际创建的共享挂载目录
path: /nfs
[root@k8s deploy]# kubectl create -f deployment.yaml
[root@k8s deploy]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-client-provisioner 1/1 1 1 10s
部署storageclass
[root@k8s deploy]# cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
# 必须与deployment.yaml中的PROVISIONER_NAME一致
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
archiveOnDelete: "false"
[root@k8s deploy]# kubectl create -f class.yaml
[root@k8s deploy]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
managed-nfs-storage fuseim.pri/ifs Delete Immediate false 15s
测试
测试pvc
[root@k8s deploy]# cat test-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
[root@k8s deploy]# kubectl create -f test-claim.yaml
[root@k8s deploy]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-claim Bound pvc-938bb7ec-8a1f-44dd-afb8-2659e824564a 1Mi RWX managed-nfs-storage 10s
测试pod
[root@k8s deploy]# cat test-pod.yaml
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: gcr.io/google_containers/busybox:1.24
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim
[root@k8s deploy]# kubectl create -f test-pod.yaml
[root@k8s deploy]# kubectl get pods
NAME READY STATUS RESTARTS AGE
test-pod 1/1 Running 0 12s
至此,完美!
附
NFS配置文件参数
参数 | 说明 |
---|---|
ro | 只读(默认) |
rw | 读写 |
sync | 同步,同时将数据写入内存和硬盘中,保证不丢数据 |
async | 异步,优先将数据保存到内存,再写入硬盘,有可能丢数据 |
root_squash | 当nfs客户端以root管理员访问时,映射为nfs服务器的匿名用户 |
no_root_squash | 当nfs客户端以root管理员访问时,映射为nfs服务器的root管理员用户 |
all_squash | 无论nfs客户端以什么账户访问,都映射为nfs服务器的匿名用户 |