1.
PV&&PVC基础概念
PersistentVolume(PV)是外部存储系统中的一块存储空间,管理员创建和维护.PV具有独立性,生命周期独立于Pod.
PersistentVolumeClaim(PVC)是对PV的申请.PVC一般普通用户创建和维护.
需要为Pod分配资源时,用户创建一个PVC,指明存储资源的容量大小和访问模式,kubernetes会查找并提供满足条件的PV.
2.
nfs部署
实验环境,部署nfs简单快捷.
真实环境,建议使用安全性高的分布式存储,ceph等.
nfs服务需要用到的软件
nfs-utils nfs主程序(rpc.nfsd,rbc.mountd)
rpcbind rpc主程序
一些基础情况说明:
现在整个集群环境4个节点,
k8s-master1 Ready
k8s-master2 Ready
k8s-master3 Ready
k8s-node1 Ready
其中k8s-node1的剩余空间最大,因此这边用的是k8s-node1来存储nfs目录和数据.
k8s-node1上部署nfs
安装软件包
[root@k8s-node1 ~]# yum install -y nfs-utils rpcbind
启动服务设置开机启动并查看当前状态
[root@k8s-node1 ~]# systemctl start rpcbind &&systemctl enable rpcbind
[root@k8s-node1 ~]# systemctl status rpcbind
● rpcbind.service - RPC bind service
Loaded: loaded (/usr/lib/systemd/system/rpcbind.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2019-04-01 13:46:48 CST; 3min 24s ago
Main PID: 36888 (rpcbind)
CGroup: /system.slice/rpcbind.service
└─36888 /sbin/rpcbind -w
Apr 01 13:46:48 k8s-node1 systemd[1]: Starting RPC bind service...
Apr 01 13:46:48 k8s-node1 systemd[1]: Started RPC bind service.
[root@k8s-node1 ~]# systemctl start nfs && systemctl enable nfs
[root@k8s-node1 ~]# systemctl status nfs
● nfs-server.service - NFS server and services
Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; disabled; vendor preset: disabled)
Active: active (exited) since Mon 2019-04-01 13:53:05 CST; 2s ago
Process: 38033 ExecStartPost=/bin/sh -c if systemctl -q is-active gssproxy; then systemctl restart gssproxy ; fi (code=exited, status=0/SUCCESS)
Process: 38016 ExecStart=/usr/sbin/rpc.nfsd $RPCNFSDARGS (code=exited, status=0/SUCCESS)
Process: 38015 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
Main PID: 38016 (code=exited, status=0/SUCCESS)
Memory: 0B
CGroup: /system.slice/nfs-server.service
Apr 01 13:53:05 k8s-node1 systemd[1]: Starting NFS server and services...
Apr 01 13:53:05 k8s-node1 systemd[1]: Started NFS server and services.
[root@k8s-node1 ~]#
[root@k8s-node1 ~]# rpcinfo -p localhost
program vers proto port service
100000 4 tcp 111 portmapper
100000 3 tcp 111 portmapper
100000 2 tcp 111 portmapper
100000 4 udp 111 portmapper
100000 3 udp 111 portmapper
100000 2 udp 111 portmapper
100005 1 udp 20048 mountd
100005 1 tcp 20048 mountd
100005 2 udp 20048 mountd
100005 2 tcp 20048 mountd
100005 3 udp 20048 mountd
100005 3 tcp 20048 mountd
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
100021 1 udp 53501 nlockmgr
100021 3 udp 53501 nlockmgr
100021 4 udp 53501 nlockmgr
100021 1 tcp 35799 nlockmgr
100021 3 tcp 35799 nlockmgr
100021 4 tcp 35799 nlockmgr
[root@k8s-node1 ~]#
配置nfs服务端
/etc/exports是默认的nfs程序配置文件,默认为空
加入配置
[root@k8s-node1 ~]# cat /etc/exports
[root@k8s-node1 ~]# echo "/mnt/data 192.168.32.0/24(rw,no_root_squash,no_all_squash,sync)" >/etc/exports
[root@k8s-node1 ~]#
重启rpcbind和nfs服务,检索nfs本机挂载情况
[root@k8s-node1 ~]# showmount -e localhost
Export list for localhost:
/mnt/data 192.168.32.0/24
注意:
192.168.32.0/24(rw,no_root_squash,no_all_squash,sync)
中间不能有空格,切记,不然报错.
注意:
必须在所有node安装rpcbind并启动,确保nfs能正常挂载。
否则报错:
mount failed: exit status 32
nfs客户端配置
客户端也需要安装nfs-utils和rpcbind,同时只需要启动rpcbind.
[root@k8s-master1 ~]# yum install -y nfs-utils rpcbind
[root@k8s-master1 ~]# showmount -e k8s-node1
Export list for k8s-node1:
/mnt/data 192.168.32.0/24
[root@k8s-master1 ~]#
3.
pv基础知识
创建pv
[root@k8s-master1 pv]# cat nfs-pv1.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv1
spec:
capacity:
storage: 100Mi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /mnt/data/pv1
server: 192.168.32.131
[root@k8s-master1 pv]#
capacity指定PV的容量
accessModes指定访问模式,支持的模式有:
ReadWriteOnce 能以read-write模式mount到单个节点
ReadOnlyMany 能以read-only模式mount到多个节点
ReadWriteMany 能以read-write模式mount到多个节点
节点其实就是pod,如果多个pod必须用ReadWriteMany
persistentVolumeReclaimPolicy指定pv的回收策略
Retain 需要管理员收工回收,安全性最高
Recycle 清除PV中的数据,效果相当于执行rm -rf
Delete 删除storage provider上对应的存储资源
storageClassName 指定PV的分类,PVC可以指定class申请相应的PV
path: /data/k8s/pv1 指定nfs上对应的目录,需手动建立
[root@k8s-master1 pv]# kubectl apply -f nfs-pv1.yml
persistentvolume "mypv1" created
[root@k8s-master1 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv1 100Mi RWX Retain Available nfs 35s
PV是有状态的资源对象,有以下几种状态:
Available:空闲状态
Bound:已经绑定到某个pvc上
Released:对应的pvc已经删除,但资源还没有被回收
Failed:pv自动回收失败
4.
pvc基础知识
创建pvc
[root@k8s-master1 pv]# cat nfs-pvc1.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc1
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Mi
storageClassName: nfs
[root@k8s-master1 pv]# kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mypvc1 Bound mypv1 100Mi RWX nfs 3m
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mypv1 100Mi RWX Retain Bound default/mypvc1 nfs 16m
[root@k8s-master1 pv]#
注意:pvc使用之后,pv的状态已经变成Bound
5.
pv和pvc是怎么对应上的呢?
上面测试的pv和pvc是通过指定 storageClassName: nfs 参数对应的.
如果不指定这个参数,会怎样呢?
根据官方的描述:
用户创建一个PVC,指明存储资源的容量大小和访问模式,kubernetes会查找并提供满足条件的PV.
也就是说,pvc会根据自己的需求去申请合适的pv.
测试见下:
pv
[root@k8s-master1 pv]# cat nfs-pv1.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv1
spec:
capacity:
storage: 100Mi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName:
nfs:
path: /mnt/data/pv1
server: 192.168.32.131
[root@k8s-master1 pv]# cat nfs-pv2.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv2
spec:
capacity:
storage: 10Mi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName:
nfs:
path: /mnt/data/pv1
server: 192.168.32.131
[root@k8s-master1 pv]#
pvc
[root@k8s-master1 pv]# cat nfs-pvc1.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc1
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Mi
storageClassName:
[root@k8s-master1 pv]# cat nfs-pvc2.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc2
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Mi
storageClassName:
[root@k8s-master1 pv]#
执行命令,查看对应情况:
[root@k8s-master1 pv]# kubectl apply -f nfs-pv2.yml
persistentvolume "mypv2" created 7s
[root@k8s-master1 pv]# kubectl apply -f nfs-pv1.yml
persistentvolume "mypv1" created
[root@k8s-master1 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv1 100Mi RWX Retain Available 2s
mypv2 10Mi RWX Retain Available 16s
[root@k8s-master1 pv]# kubectl apply -f nfs-pvc2.yml
persistentvolumeclaim "mypvc2" created
[root@k8s-master1 pv]# kubectl apply -f nfs-pvc1.yml
persistentvolumeclaim "mypvc1" created
[root@k8s-master1 pv]# kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mypv1 100Mi RWX Retain Bound default/mypvc2 24s
persistentvolume/mypv2 10Mi RWX Retain Bound default/mypvc1 38s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mypvc1 Bound mypv2 10Mi RWX 5s
persistentvolumeclaim/mypvc2 Bound mypv1 100Mi RWX 8s
可以看到,不指定任何匹配参数的情况下,pvc自动申请使用匹配的pv.
注意:
如果pv指定 storageClassName:参数,pvc不指定相对应的storageClassName:参数,pvc无法自动申请使用匹配的pv.
执行命令后,pvc一直是pending状态,见下:
[root@k8s-master1 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mypv1 100Mi RWX Retain Available my1 2m
mypv2 10Mi RWX Retain Available my2 2m
[root@k8s-master1 pv]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc1 Pending 2m
mypvc2 Pending 2m
[root@k8s-master1 pv]#
6.
mysql使用pv和pvc
手动创建pv的存储目录
[root@k8s-node1 ~]# mkdir -p /mnt/data/mysqlpv1
[root@k8s-node1 ~]# ll /mnt/data/
total 0
drwxr-xr-x 2 root root 6 Apr 8 17:26 mysqlpv1
drwxr-xr-x 2 root root 6 Apr 8 10:55 pv1
pv
[root@k8s-master1 pv]# cat mysql-pv1.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv1
spec:
capacity:
storage: 300Mi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName:
nfs:
path: /mnt/data/mysqlpv1
server: 192.168.32.131
[root@k8s-master1 pv]# kubectl apply -f mysql-pv1.yml
persistentvolume "mysql-pv1" created
[root@k8s-master1 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mysql-pv1 300Mi RWX Retain Available 31s
pvc
[root@k8s-master1 pv]# cat mysql-pvc1.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc1
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 300Mi
storageClassName:
[root@k8s-master1 pv]# kubectl apply -f mysql-pvc1.yml
persistentvolumeclaim "mysql-pvc1" created
[root@k8s-master1 pv]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pvc1 Bound mysql-pv1 300Mi RWX 5s
mysql中部署
[root@k8s-master1 pv]# cat mysql.yml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: mysql
spec:
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumes:
- name: mysql-data
persistentVolumeClaim:
claimName: mysql-pvc1
[root@k8s-master1 pv]#
[root@k8s-master1 pv]# kubectl apply -f mysql.yml
service "mysql" created
deployment.apps "mysql" created
[root@k8s-master1 pv]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
mysql-5f4c86bcf9-gtstz 1/1 Running 0 9m 172.30.79.2 k8s-master2
用docker inspect检索信息看看
[root@k8s-master2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
af22cadb3a3b mysql@sha256:de2913a0ec53d98ced6f6bd607f487b7ad8fe8d2a86e2128308ebf4be2f92667 "docker-entrypoint..." 9 minutes ago Up 9 minutes k8s_mysql_mysql-5f4c86bcf9-gtstz_default_7ff51d1a-5a71-11e9-ae21-000c291d7023_0
0dc35308a0fb registry.access.redhat.com/rhel7/pod-infrastructure:latest "/usr/bin/pod" 10 minutes ago Up 10 minutes k8s_POD_mysql-5f4c86bcf9-gtstz_default_7ff51d1a-5a71-11e9-ae21-000c291d7023_0
[root@k8s-master2 ~]# docker inspect af22cadb3a3b
"Mounts": [
{
"Type": "bind",
"Source": "/var/lib/kubelet/pods/7ff51d1a-5a71-11e9-ae21-000c291d7023/volumes/kubernetes.io~nfs/mysql-pv1",
"Destination": "/var/lib/mysql",
"Mode": "",
"RW": true,
"Propagation": ""
},
可以看到使用的pv
检索pv目录生成的数据
[root@k8s-node1 ~]# ll /mnt/data/mysqlpv1/
total 110604
-rw-rw---- 1 systemd-bus-proxy ssh_keys 56 Apr 9 10:46 auto.cnf
-rw-rw---- 1 systemd-bus-proxy ssh_keys 12582912 Apr 9 10:46 ibdata1
-rw-rw---- 1 systemd-bus-proxy ssh_keys 50331648 Apr 9 10:46 ib_logfile0
-rw-rw---- 1 systemd-bus-proxy ssh_keys 50331648 Apr 9 10:45 ib_logfile1
drwx------ 2 systemd-bus-proxy ssh_keys 4096 Apr 9 10:46 mysql
drwx------ 2 systemd-bus-proxy ssh_keys 4096 Apr 9 10:45 performance_schema
[root@k8s-node1 ~]#
7.
操作mysql,生成数据,测试效果
创建数据库t1
[root@k8s-master2 ~]# docker exec af22cadb3a3b mysql -uroot -ppassword -e"create database t1"
Warning: Using a password on the command line interface can be insecure.
[root@k8s-master2 ~]# docker exec af22cadb3a3b mysql -uroot -ppassword -e"show databases;"
Warning: Using a password on the command line interface can be insecure.
Database
information_schema
mysql
performance_schema
t1
在t1中创建数据表t1
[root@k8s-master2 ~]# docker exec af22cadb3a3b mysql -uroot -ppassword -e "use t1;create table t1(i int);"
Warning: Using a password on the command line interface can be insecure.
数据表t1插入数据并检索
[root@k8s-master2 ~]# docker exec af22cadb3a3b mysql -uroot -ppassword -e "use t1;create table t1(i int);"
Warning: Using a password on the command line interface can be insecure.
[root@k8s-master2 ~]# docker exec af22cadb3a3b mysql -uroot -ppassword -e "use t1;insert into t1 values(1),(3),(3);"
Warning: Using a password on the command line interface can be insecure.
[root@k8s-master2 ~]# docker exec af22cadb3a3b mysql -uroot -ppassword -e "use t1;select * from t1;"
i
1
3
3
Warning: Using a password on the command line interface can be insecure.
[root@k8s-master2 ~]#
已经生成了数据,我们看看nfs存储目录的情况和容器存储目录的情况
nfs目录
[root@k8s-node1 ~]# ll /mnt/data/mysqlpv1/
total 110604
-rw-rw---- 1 systemd-bus-proxy ssh_keys 56 Apr 9 10:46 auto.cnf
-rw-rw---- 1 systemd-bus-proxy ssh_keys 12582912 Apr 9 11:09 ibdata1
-rw-rw---- 1 systemd-bus-proxy ssh_keys 50331648 Apr 9 11:09 ib_logfile0
-rw-rw---- 1 systemd-bus-proxy ssh_keys 50331648 Apr 9 10:45 ib_logfile1
drwx------ 2 systemd-bus-proxy ssh_keys 4096 Apr 9 10:46 mysql
drwx------ 2 systemd-bus-proxy ssh_keys 4096 Apr 9 10:45 performance_schema
drwx------ 2 systemd-bus-proxy ssh_keys 48 Apr 9 11:08 t1
[root@k8s-node1 ~]# ll /mnt/data/mysqlpv1/t1
total 112
-rw-rw---- 1 systemd-bus-proxy ssh_keys 65 Apr 9 11:05 db.opt
-rw-rw---- 1 systemd-bus-proxy ssh_keys 8554 Apr 9 11:08 t1.frm
-rw-rw---- 1 systemd-bus-proxy ssh_keys 98304 Apr 9 11:09 t1.ibd
[root@k8s-node1 ~]#
容器
[root@k8s-master2 ~]# docker exec af22cadb3a3b ls /var/lib/mysql
auto.cnf
ib_logfile0
ib_logfile1
ibdata1
mysql
performance_schema
t1
[root@k8s-master2 ~]# docker exec af22cadb3a3b ls /var/lib/mysql/t1
db.opt
t1.frm
t1.ibd
[root@k8s-master2 ~]#
数据对比可知,pvc使用成功
现在模拟故障,k8s-master2机器死掉
[root@k8s-master2 ~]# init 0
Connection closing...Socket close.
Connection closed by foreign host.
Disconnected from remote host(k8s-master2) at 11:14:05.
Type `help' to learn how to use Xshell prompt.
[C:\~]$
[root@k8s-master1 pv]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
mysql-5f4c86bcf9-cz2np 1/1 Running 0 1m 172.30.27.2 k8s-master3
mysql-5f4c86bcf9-gtstz 1/1 Unknown 0 34m 172.30.79.2 k8s-master2
[root@k8s-master1 pv]#
pod自动切换到k8s-master3了
[root@k8s-master3 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e53dccc404b7 mysql@sha256:de2913a0ec53d98ced6f6bd607f487b7ad8fe8d2a86e2128308ebf4be2f92667 "docker-entrypoint..." About a minute ago Up About a minute k8s_mysql_mysql-5f4c86bcf9-cz2np_default_38792912-5a76-11e9-ae21-000c291d7023_0
228f7a798f7e registry.access.redhat.com/rhel7/pod-infrastructure:latest "/usr/bin/pod" 2 minutes ago Up 2 minutes k8s_POD_mysql-5f4c86bcf9-cz2np_default_38792912-5a76-11e9-ae21-000c291d7023_0
[root@k8s-master3 ~]#
检索数据
[root@k8s-master3 ~]# docker exec e53dccc404b7 mysql -uroot -ppassword -e "use t1;select * from t1;"
Warning: Using a password on the command line interface can be insecure.
i
1
3
3
[root@k8s-master3 ~]#
可以看到Mysql的数据已经和pod解耦。