关于

PV 的全称是:PersistentVolume(持久化卷),是对底层的共享存储的一种抽象,PV 由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。

PVC 的全称是:PersistentVolumeClaim(持久化卷声明),PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。

但是通过 PVC 请求到一定的存储空间也很有可能不足以满足应用对于存储设备的各种需求,而且不同的应用程序对于存储性能的要求可能也不尽相同,比如读写速度、并发性能等,为了解决这一问题,Kubernetes 又为我们引入了一个新的资源对象:StorageClass,通过 StorageClass 的定义,管理员可以将存储资源定义为某种类型的资源,比如快速存储、慢速存储等,用户根据 StorageClass 的描述就可以非常直观的知道各种存储资源的具体特性了,这样就可以根据应用的特性去申请合适的存储资源了。

NFS server 安装

NFS 使用RPC(Remote Procedure Call)的机制进行实现,RPC使得客户端可以调用服务端的函数。同时,由于有 VFS 的存在,客户端可以像使用其它普通文件系统一样使用 NFS 文件系统。经由操作系统的内核,将 NFS 文件系统的调用请求通过 TCP/IP 发送至服务端的 NFS 服务。NFS服务器执行相关的操作,并将操作结果返回给客户端。

使用NFS作为存储资源,我这里准备了一台服务单独部署 NFS server,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 关闭防火墙
systemctl stop firewalld.service
systemctl disable firewalld.service

# 安装 nfs
yum -y install nfs-utils rpcbind

# 设置共享目录权限
mkdir /nfs/k8s -p
chmod 755 /nfs/k8s

# 配置nfs,nfs 的默认配置文件在 /etc/exports 文件下,在该文件中添加下面的配置信息
echo "/nfs/k8s *(rw,async,no_root_squash)" >> /etc/exports

/nfs/k8s:是共享的数据目录
*:表示任何人都有权限连接,当然也可以是一个网段,一个 IP,也可以是域名
rw:读写的权限
sync:表示文件同时写入硬盘和内存
no_root_squash:当登录 NFS 主机使用共享目录的使用者是 root 时,其权限将被转换成为匿名使用者,通常它的 UID 与 GID,都会变成 nobody 身份
启动服务

启动服务 nfs 需要向 rpc 注册,rpc 一旦重启了,注册的文件都会丢失,向他注册的服务都需要重启

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 启动 rpc
systemctl enable rpcbind && systemctl start rpcbind

# 启动 nfs
systemctl start nfs && systemctl enable nfs

# 查看是否安装正常
rpcinfo -p|grep nfs
    100003    3   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100227    3   tcp   2049  nfs_acl
    100003    3   udp   2049  nfs
    100003    4   udp   2049  nfs
    100227    3   udp   2049  nfs_acl

# 查看具体目录挂载权限
cat /var/lib/nfs/etab 
/nfs/k8s	*(rw,sync,wdelay,hide,nocrossmnt,secure,no_root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,rw,secure,no_root_squash,no_all_squash) 

NFS server 已经安装成功,接下来在k8s node节点上安装nfs客户端

NFS client 安装

 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
# 安装 nfs
yum -y install nfs-utils rpcbind

# 启动 rpc
systemctl enable rpcbind && systemctl start rpcbind

# 启动 nfs
systemctl start nfs && systemctl enable nfs

# 检查 NFS 是否有共享目录
showmount -e 192.168.11.115
Export list for 192.168.11.115:
/nfs/k8s *

# 客户端创建共享目录
mkdir /data

# 挂载 nfs 共享目录
mount -t nfs 192.168.11.115:/nfs/k8s /data

# 测试,在客户端创建一个文件
touch /data/test.txt

# 切换到服务端查看,能看到文件就挂载成功了
ls /nfs/k8s
test.txt

在剩下的K8s node客户端上按照上面的方法安装nfs

创建 PV

PV 作为存储资源,主要包括存储能力、访问模式、存储类型、回收策略等关键信息,下面新建一个 PV 对象,使用 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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
cat nfs-pv.yaml

apiVersion: v1 
kind: PersistentVolume 
metadata: 
  name: nfs-pv 
spec: 
  capacity: 
    storage: 5Gi 
  volumeMode: Filesystem 
  accessModes: 
  - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Recycle 
  nfs:
    path: /nfs/k8s            # path 设置的共享目录
    server: 192.168.11.115    # server nfs服务端的IP

## capacity(存储能力)
一般来说,一个 PV 对象都要指定一个存储能力,通过 PV 的 capacity属性来设置的,目前只支持存储空间的设置,就是我们这里的 storage=5Gi

## accessModes
AccessModes 是用来对 PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
ReadWriteMany(RWX):读写权限,可以被多个节点挂载
一些 PV 可能支持多种访问模式,但是在挂载的时候只能使用一种访问模式,多种访问模式是不会生效的

## persistentVolumeReclaimPolicy(回收策略)
我这里指定的 PV 的回收策略为 Recycle,目前 PV 支持的策略有三种:

Retain(保留)- 保留数据,需要管理员手工清理数据
Recycle(回收)- 清除 PV 中的数据,效果相当于执行 rm -rf /thevoluem/*
Delete(删除)- 与 PV 相连的后端存储完成 volume 的删除操作,这常见于云服务商的存储服务

## 状态
一个 PV 的生命周期中,可能会处于4中不同的阶段:(我们平时使用的资源就是PVC)
Available(可用):表示可用状态,还未被任何 PVC 绑定
Bound(已绑定):表示 PV 已经被 PVC 绑定
Released(已释放):PVC 被删除,但是资源还未被集群重新声明
Failed(失败): 表示该 PV 的自动回收失败

# 创建pv
kubectl create -f nfs-pv.yaml

kubectl get pv 
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-pv   5Gi        RWO            Recycle          Available                                   56m

查看pv创建成功,状态时 Available ,表示pv就绪,可以被pvc申请
部署 PVC
 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
cat nfs-pvc.yaml

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nfs-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

# 创建 pvc
kubectl create -f nfs-pvc.yaml

kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc   Bound    nfs-pv   5Gi        RWO                           4s

kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
nfs-pv   5Gi        RWO            Recycle          Bound    default/nfs-pvc                           88m

可以看到 PV PVC 状态都是Bound,绑定成功
pv和pvc怎么关联起来的:系统自动帮我们去匹配的,他会根据我们的声明要求去查找处于 Available 状态的 PV,如果没有找到的话那么我们的 PVC 就会一直处于 Pending 状态,找到了的话当然就会把当前的 PVC 和目标 PV 进行绑定,这个时候状态就会变成 Bound 状态了

可以试试新建一个pvc, 不能绑定到PV上,PVC状态会处于pending,没有找到合适的PV来用,接下来在新建一个PV,可以发现PVC和PV已经关联上了,还可以给pv和pvc打上标签,显得更专业0.0
#改变容量大小:
1.PV 容量声明5Gi,PVC 声明容量 2Gi,是可以绑定的,但是你会发现 pvc的CAPACITY 值为5Gi,也就是说我们声明的2Gi没用,PV是多少,你PVC就得多少,不能叛变
2.PV 容量声明5Gi, PVC 声明容量6Gi 大于PV的容量,结果当然是绑定不上的,处于pending
PVC 案列使用

接下来使用PVC ,创建一个nginx测试一下

 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
cat pvc-deploy.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: pvc-nfs
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nfs
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
      volumes:
      - name: www
        persistentVolumeClaim:
          claimName: nfs-pvc

---

apiVersion: v1
kind: Service
metadata:
  name: pvc-nfs
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nfs

# 创建
kubectl create -f pvc-deploy.yaml

通过node:Nodeport访问看到403,因为/usr/share/nginx/html下面什么也没有,接下来在192.168.11.115的 /nfs/k8s/目录下新建一个文件

1
echo "<h1>Hello Nginx~</h1>" >> /nfs/k8s/index.html

在访问网页可以看到添加的内容 如果以后又有一个新的nginx容器也做了数据挂载,就需要添加一个新的属性:subPath,只需要在yaml文件更改如下

1
2
3
4
volumeMounts:
- name: www
  subPath: nginx-test
  mountPath: /usr/share/nginx/html

更新yaml之后,发现nfs共享目录下面生成了 nginx-test目录,访问又会是403页面,因为nginx-test目录下还是没有文件,把 /nfs/k8s/index.html文件移动到nginx-test目录下,又可以访问了

PVC 数据持久性

删除deploy,这样下面的pod也会被删除,查看nfs共享数据目录,数据还在没有丢失,重新创建deployment,访问服务,看到页面依然是 Hello Nginx~,持久化成功

接下来删除pv,(必须在没有POD的情况,否则无法删除),在看看PVC,依然是Bound状态,我们依旧可以正常使用

  • 如果有一个新的pod正在使用此PVC,新建POD仍可使用,如果无POD使用此PVC则会失败

把PV和deployment创建好,删除deploy,这样下面的pod也会被删除,然后在删除PVC,可以看到PV已经变成Released状态,nfs共享数据目录下已经没有数据了,把PVC删掉了,然后回收了数据