Kubernetes部署NFS持久存储(静态和动态)
LiuSw Lv6

Kubernetes部署NFS持久存储(静态和动态)

参考文章 https://www.jianshu.com/p/5e565a8049fc

NFS简介

NFS是网络文件系统Network File System的缩写,NFS服务器可以让PC将网络中的NFS服务器共享的目录挂载到本地的文件系统中,而在本地的系统中来看,那个远程主机的目录就好像是自己的一个磁盘分区一样。

kubernetes使用NFS共享存储有两种方式:

  • 1.手动方式静态创建所需要的PV和PVC。
  • 2.通过创建PVC动态地创建对应PV,无需手动创建PV。

1.k8s集群前提准备

在master节点上部署NFS服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# master节点安装nfs
yum -y install nfs-utils

# 创建nfs目录
mkdir -p /nfs/data/

# 修改权限
chmod -R 777 /nfs/data

# 编辑export文件,这个文件就是nfs默认的配置文件
vim /etc/exports
/nfs/data *(rw,no_root_squash,sync)

# 配置生效
exportfs -r
# 查看生效
exportfs

# 启动rpcbind、nfs服务
systemctl restart rpcbind
systemctl enable rpcbind
systemctl restart nfs
systemctl enable nfs

# 查看 RPC 服务的注册状况
rpcinfo -p localhost

# showmount测试
showmount -e 192.168.88.111

所有node节点安装客户端,开机启动

1
2
yum -y install nfs-utils
systemctl start nfs && systemctl enable nfs

2.静态申请PV卷

添加pv卷对应目录,这里创建2个pv卷,则添加2个pv卷的目录作为挂载点。

1
2
3
4
5
6
7
8
9
10
11
12
# 创建pv卷对应的目录
mkdir -p /nfs/data/pv001

# 配置exportrs(我觉得可以不用这步,因为父目录/nfs/data,已经设为共享文件夹)
vim /etc/exports
/nfs/data *(rw,no_root_squash,sync)
/nfs/data/pv001 *(rw,no_root_squash,sync)

# 配置生效
exportfs -r
# 重启rpcbind、nfs服务
systemctl restart rpcbind && systemctl restart nfs

创建PV

下面创建名为pv001的PV卷,配置文件 nfs-pv001.yaml 如下: vim nfs-pv001.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv001
labels:
pv: nfs-pv001
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /nfs/data/pv001
server: 192.168.1.1

配置说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
① capacity 指定 PV 的容量为 1G。
② accessModes 指定访问模式为 ReadWriteOnce,支持的访问模式有:

2.1ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点。
2.2ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点。
2.3ReadWriteMany – PV 能以 read-write 模式 mount 到多个节点。
③ persistentVolumeReclaimPolicy 指定当 PV 的回收策略为 Recycle,支持的策略有:

3.1Retain – 需要管理员手工回收。
3.2Recycle – 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*。
3.3Delete – 删除 Storage Provider 上的对应存储资源,例如 AWS EBS、GCE PD、Azure
Disk、OpenStack Cinder Volume 等。
④ storageClassName 指定 PV 的 class 为 nfs。相当于为 PV 设置了一个分类,PVC 可以指定 class 申请相应 class 的 PV。
⑤ 指定 PV 在 NFS 服务器上对应的目录。

创建对应pv:

1
2
3
4
5
6
7
kubectl apply -f nfs-pv001.yaml

# persistentvolume/nfs-pv001 created

kubectl get pv
# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
# nfs-pv001 1Gi RWO Recycle Available nfs 4s

STATUS 为 Available,表示 pv就绪,可以被 PVC 申请。

创建PVC

接下来创建一个名为pvc001的PVC,配置文件 nfs-pvc001.yaml 如下:vim nfs-pvc001.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc001
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: nfs
selector:
matchLabels:
pv: nfs-pv001

执行yaml文件创建 pvc:

1
2
3
4
5
6
7
8
9
10
11
12
13
kubectl apply -f nfs-pvc001.yaml

# persistentvolumeclaim/nfs-pvc001 created

kubectl get pvc

# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
# nfs-pvc001 Bound pv001 1Gi RWO nfs 6s

kubectl get pv

# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
# nfs-pv001 1Gi RWO Recycle Bound default/pvc001 nfs 9m12s

从 kubectl get pvc 和 kubectl get pv 的输出可以看到 pvc001绑定到pv001,申请成功。注意pvc绑定到对应pv通过labels标签方式实现,也可以不指定,将随机绑定到pv。 接下来就可以在 Pod 中使用存储了,Pod 配置文件 nfs-pod001.yaml 如下:vim nfs-pod001.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kind: Pod
apiVersion: v1
metadata:
name: nfs-pod001
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: nfs-pv001
volumes:
- name: nfs-pv001
persistentVolumeClaim:
claimName: nfs-pvc001

与使用普通 Volume 的格式类似,在 volumes 中通过 persistentVolumeClaim 指定使用nfs-pvc001申请的 Volume。

执行yaml文件创建nfs-pdo001:

1
2
3
4
5
6
7
8
9
kubectl apply -f nfs-pod001.yaml

# pod/nfs-pod001 created

kubectl get pod

# NAME READY STATUS RESTARTS AGE
# nfs-client-provisioner-75bf876d88-sqqpv 1/1 Running 0 25m
# nfs-pod001 1/1 Running 0 12s

验证 PV 是否可用:

1
2
3
4
kubectl exec nfs-pod001 touch /var/www/html/index001.html
ls /nfs/data/pv001/

# index001.html

进入pod查看挂载情况

1
2
3
4
5
6
7
kubectl exec -it nfs-pod001 /bin/bash

# root@nfs-pod001:/# df -h
# ......
# 192.168.92.56:/nfs/data/pv001 47G 5.2G 42G 11% /var/www/html
# ......
# root@nfs-pod001:/#

删除pv

删除pod,pv和pvc不会被删除,nfs存储的数据不会被删除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
kubectl delete -f nfs-pod001.yaml

# pod "nfs-pod001" deleted

kubectl get pv

# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
# nfs-pv001 1Gi RWO Recycle Bound default/pvc001 nfs 34m

kubectl get pvc

# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
# nfs-pvc001 Bound pv001 1Gi RWO nfs 25m

ls /nfs/data/pv001/

# index001.html

继续删除pvc,pv将被释放,处于 Available 可用状态,并且nfs存储中的数据被删除。

1
2
3
4
5
6
7
8
9
10
kubectl delete -f nfs-pvc001.yaml

# persistentvolumeclaim "nfs-pvc001" deleted

kubectl get pv

# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
# nfs-pv001 1Gi RWO Recycle Available nfs 35m

ls /nfs/data/pv001/

继续删除pv

1
2
3
kubectl delete -f nfs-pv001.yaml

# persistentvolume "pv001" deleted

动态申请PV卷

External NFS驱动的工作原理 K8S的外部NFS驱动,可以按照其工作方式(是作为NFS server还是NFS client)分为两类:

  • 1.nfs-client:
    也就是我们接下来演示的这一类,它通过K8S的内置的NFS驱动挂载远端的NFS服务器到本地目录;然后将自身作为storage provider,关联storage class。当用户创建对应的PVC来申请PV时,该provider就将PVC的要求与自身的属性比较,一旦满足就在本地挂载好的NFS目录中创建PV所属的子目录,为Pod提供动态的存储服务。
  • 2.nfs:
    与nfs-client不同,该驱动并不使用k8s的NFS驱动来挂载远端的NFS到本地再分配,而是直接将本地文件映射到容器内部,然后在容器内使用ganesha.nfsd来对外提供NFS服务;在每次创建PV的时候,直接在本地的NFS根目录中创建对应文件夹,并export出该子目录。 利用NFS动态提供Kubernetes后端存储卷 本文将介绍使用nfs-client-provisioner这个应用,利用NFS Server给Kubernetes作为持久存储的后端,并且动态提供PV。前提条件是有已经安装好的NFS服务器,并且NFS服务器与Kubernetes的Slave节点都能网络连通。将nfs-client驱动做一个deployment部署到K8S集群中,然后对外提供存储服务。 nfs-client-provisioner 是一个Kubernetes的简易NFS的外部provisioner,本身不提供NFS,需要现有的NFS服务器提供存储

部署nfs-client-provisioner,在master上操作
首先克隆仓库获取yaml文件

1
2
3
git clone https://github.com/kubernetes-incubator/external-storage.git
cp -R external-storage/nfs-client/deploy/ $HOME
cd deploy

修改deployment.yaml文件
这里修改的参数包括NFS服务器所在的IP地址(192.168.1.1),以及NFS服务器共享的路径(/nfs/data),两处都需要修改为你实际的NFS服务器和共享目录。
cat deployment.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
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
value: fuseim.pri/ifs
- name: NFS_SERVER
value: 192.168.1.1
- name: NFS_PATH
value: /nfs/data
volumes:
- name: nfs-client-root
nfs:
server: 192.168.1.1
path: /nfs/data

部署deployment.yaml

1
kubectl apply -f deployment.yaml

查看创建的POD

1
2
3
4
 kubectl get pod -o wide

# NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
# nfs-client-provisioner-75bf876d88-578lg 1/1 Running 0 51m 10.244.2.131 k8s-node2 <none> <none>

创建StorageClass

storage class的定义,需要注意的是:provisioner属性要等于驱动所传入的环境变量PROVISIONER_NAME的值。否则,驱动不知道知道如何绑定storage class。 此处可以不修改,或者修改provisioner的名字,需要与上面的deployment的PROVISIONER_NAME名字一致。 (此yaml无需修改)
cat class.yaml

1
2
3
4
5
6
7
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
archiveOnDelete: "false"

部署yaml文件

1
kubectl apply -f class.yaml

查看创建的storageclass

1
2
3
4
kubectl get sc

# NAME PROVISIONER AGE
# managed-nfs-storage fuseim.pri/ifs 95m

配置授权

如果集群启用了RBAC,则必须执行如下命令授权provisioner。(k8s1.6+默认开启) 此yaml无需修改
cat rbac.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
kind: ServiceAccount
apiVersion: v1
metadata:
name: nfs-client-provisioner
---
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
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
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
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

部署yaml文件

1
kubectl create -f rbac.yaml

测试

创建测试PVC

1
kubectl create -f test-claim.yaml

可以看到PVC状态为Bound,绑定的volume为pvc-a17d9fd5-237a-11e9-a2b5-000c291c25f3。

1
2
3
4
kubectl get pvc

# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
# test-claim Bound pvc-a17d9fd5-237a-11e9-a2b5-000c291c25f3 1Mi RWX managed-nfs-storage 34m

查看自动创建的PV

1
2
3
4
kubectl get pv

# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
# pvc-a17d9fd5-237a-11e9-a2b5-000c291c25f3 1Mi RWX Delete Bound default/test-claim managed-nfs-storage 34m

然后,我们进入到NFS的export目录,可以看到对应该volume name的目录已经创建出来了。 其中volume的名字是namespace,PVC name以及uuid的组合:

1
2
3
4
5
cd /nfs/data/
ll

# total 0
# drwxrwxrwx 2 root root 21 Jan 29 12:03 default-test-claim-pvc-a17d9fd5-237a-11e9-a2b5-000c291c25f3
 评论