一、k8s存储类型简介

1.类比docker的存储类型
回顾docker的数据持久化。
docker的容器层可以提供存储:存储在可写层(CopyOnWrite)
docker的数据持久化解决方案:

data volume---->1、bind mount 2、docker manager volume

其实两者没有什么显著差别,不同点在于是否需要提前准备dockerHost上的相关文件或目录。
2.k8s存储类型详解
volume
与docker类似:将宿主机上的某个文件或者目录挂载到Pod内。
emptyDir
写一个emptyDir.yaml的文件

[root@master ~]# vim emptyDir.yaml
kind: Pod
apiVersion: v1
metadata:
  name: producer-consumer
spec:
  containers:
  - name: producer
    image: busybox
    volumeMounts:
    - name: shared-volume
      mountPath: /producer_dir  #容器内的路径
    args:
    - /bin/sh
    - -c
    - echo "hello world" > /producer_dir/hello.txt; sleep 30000
  - name: consumer
    image: busybox
    volumeMounts:
    - name: shared-volume
      mountPath: /consumer_dir
    args:
    - /bin/sh
    - -c
    - cat /consumer_dir/hello.txt; sleep 30000
  volumes:
  - name: shared-volume
    emptyDir: {}

总结:根据上述yaml文件分析,volumes是指k8s的存储方案.容器内volumeMounts使用的是volumes内定义的存储,所以现在可以理解为,volumes定义的dockerHost上的目录或文件,分别挂载到了producer(/producer_dir)和consumer(/consumer_dir)这个两个容器的对应目录。可以判断出在consumer这个容器的/consumer_dir目录下,应该也会有一个hello.txt的文件。
验证查看conumer容器的日志

[root@master ~]# kubectl logs producer-consumer consumer
hello world

查看一个Pod运行在了那个Node节点上

[root@master ~]# kubectl get pod -o wide

到对应Node节点上查看该容器的详细信息(Mounts)

        "Mounts": [
                 {
                       "Type": "bind",
                       "Source": "/var/lib/kubelet/pods/9dcfac16-
c55b-458c-bf49-f20867shared-volume",
                       "Destination": "/producer_dir",
                       "Mode": "",
                       "RW": true,
                       "Propagation": "rprivate"
                 },

注意:查看到该容器的Mounts字段,等于是运行docker容器的时候使用这么一条命令:

docker run -v /producer_dir busybox

emptyDir的使用场景:如果Pod被删除,那么数据也会被删除,不具备持久化。Pod内的容器,需要共享数据卷的时候,使用的临时数据卷。
hostpath
hostPath就等于运行容器时使用下面的命令

docker run -v /host/path:/container/path

编写一个hostpath.yaml文件,直接将emptyDir.yaml文件的volumes字段更改为:hostPath。

[root@master volume]# mkdir -p /data/hostPath
[root@master ~]# vim hostpath.yaml
kind: Pod
apiVersion: v1
metadata:
  name: producer-consumer
spec:
  containers:
  - name: producer
    image: busybox
    volumeMounts:
    - name: shared-volume
      mountPath: /producer_dir  #容器内的路径
    args:
    - /bin/sh
    - -c
    - echo "hello world" > /producer_dir/hello.txt; sleep 30000
  - name: consumer
    image: busybox
    volumeMounts:
    - name: shared-volume
      mountPath: /consumer_dir
    args:
    - /bin/sh
    - -c
    - cat /consumer_dir/hello.txt; sleep 30000
  volumes:
  - name: shared-volume
    hostPath:
      path: "/data/hostPath"

总结:HostPath这种方式相比emptyDir来说,持久化功能强,但它实际增加了Pod与host的耦合,所以大部分资源不会使用这种持久化方案,通常关于docker或者k8s集群本身才会使用。

二、PV和PVC相关介绍

1.pv与pvc简介

PV:PersistentVolume
是k8s集群的外部存储系统,一般是设定好的存储空间(文件系统中的一个目录);

PVC:PersistentVolumeClaim
如果应用需要用到持久化的时候,可以直接向PV申请空间;

2.基于nfs服务来创建的pv
(1)master和node节点都需要安装nfs-utils、rpcbind。

[root@master ~]# yum -y install nfs-utils rpcbind

(2)将NFS服务部署在master节点上,需要在master节点上提前规划好共享的目录。

[root@master ~]# mkdir /nfsdata
[root@master ~]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash)
[root@master ~]# systemctl start rpcbind
[root@master ~]# systemctl enable rpcbind
[root@master ~]# systemctl start nfs-server
[root@master ~]# systemctl enable nfs-server
[root@master ~]# showmount -e
Export list for master:
/nfsdata *
[root@node1 ~]# showmount -e 192.168.229.187
[root@node2 ~]# showmount -e 192.168.229.187

(3)创建pv.yaml文件。

[root@master ~]# mkdir yaml
[root@master ~]# mkdir -p /nfsdata/pv1
[root@master ~]# cd yaml
[root@master yaml]# vim pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: pv1
spec:
  capacity:  #PV的容量
    storage: 1Gi
  accessModes:  #访问模式
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs
  nfs:
    path: /nfsdata/pv1
    server: 192.168.229.187
[root@master yaml]# kubectl apply -f pv.yaml
[root@master yaml]# kubectl get pv

pv所支持的访问模式

ReadWriteOnce:PV能以read-write的模式mount到单个节点;

ReadOnlyMany:PV能以read-only的模式mount到多个节点;

ReadWriteMany:PV能以read-write的模式Mount到多个节点;

关于pv所支持的访问模式的理解:
主要分为两个方面

读写方面:如果是可以读写的,则认为pod可以在挂载的路径下执行读写操作。
如果是只读的,那么pod就只能够读取pv共享目录下的数据。

节点方面:挂载到单个或者多个节点,指的是kubernetes的工作节点。

验证结果:
k8s官方表示,readonly是以只读的方式挂载,但实际上仍需要在挂载时指定其挂载类型为readonly:true,才可以实现只读。
这里所说的挂载到单个或多个节点,和官方描述不一致,需进一步验证。

persistentVolumeReclaimPolicy:PV空间的回收策略

Recycle:会清除数据,自动回收;

Retain:需要手动清理回收;

Delete:云存储专用的回收空间使用命令;

(4)创建一个PVC,向刚才的PV申请使用空间。注意这里PV与PVC的绑定是通过storageClassName和accessModes这两个字段共同决定。

[root@master yaml]# vim pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc1
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 200Mi
  storageClassName: nfs
[root@master yaml]# kubectl apply -f pvc.yaml
[root@master yaml]# kubectl get pvc

总结

1.当系统中的PV被绑定之后,就不会被其他PVC所绑定了。

2.如果系统中有多个可以满足PVC要求的PV,则系统会自动选择一个符合PVC申请空间大小的PV进行绑定,尽量不浪费存储空间。

(5)创建一个Pod,来使用上述PVC。

[root@master yaml]# vim pod.yaml
kind: Pod
apiVersion: v1
metadata:
  name: pod1
spec:
  containers:
  - name: pod1
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 30000
    volumeMounts:
    - name: mydata
      mountPath: "/data"
  volumes:
  - name: mydata
    persistentVolumeClaim:
      claimName: pvc1
[root@master yaml]# kubectl apply -f pod.yaml
[root@master yaml]# kubectl get pod

(6)验证/nfsdata/pv1目录与Pod内"/data"目录的一致性。

[root@master pv1]# pwd
/nfsdata/pv1
[root@master pv1]# echo "hello persistentVolume" > test.txt
[root@master pv1]# kubectl exec pod1 cat /data/test.txt
hello persistentVolume

三、pv的空间回收策略验证

1.回收策略为:recycle

[root@master ~]# kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM
POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv1 1Gi RWO Recycle
Bound default/pvc1 nfs 21h

(1)验证master上PV上存放的数据

[root@master ~]# ls /nfsdata/pv1/
test.txt

(2)删除pod资源和pvc

[root@master ~]# kubectl delete pod pod1
[root@master ~]# kubectl delete pvc pvc1

(3)查看PV的状态为Released然后变为Available

[root@master ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS
CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWO Recycle Released default/pvc1 nfs 21h
[root@master ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS
CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWO Recycle Available nfs 21h

(4)验证数据被删除

[root@master ~]# ls /nfsdata/pv1/

注意:在释放空间的过程中,其实K8S生成了一个新的Pod,由这个Pod执行删除数据的操作。
2.回收策略为:Retain

...
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
...

(1)重新运行pvc,pod资源,然后在Pod内,创建对应的资源。

[root@master storage]# kubectl apply -f pvc.yaml
[root@master storage]# kubectl apply -f pod.yaml
[root@master storage]# kubectl exec pod1 touch /data/test.txt
[root@master storage]# ls /nfsdata/pv1/
test.txt

(2)再次删除Pod和PVC,验证PV目录下存放的数据。

[root@master storage]# kubectl delete pod pod1
[root@master storage]# kubectl delete pvc pvc1
[root@master storage]# ls /nfsdata/pv1/
test.txt
四、pv和pvc的运用示例

部署一个MySQL服务,并且将MySQL的数据进行持久化存储。
1.创建PV和PVC

[root@master mysql]# vim mysql-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
  name: mysql-pv
spec:
  accessModes:
    - ReadWriteOnce
  capacity:
    storage: 1Gi
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /nfsdata/mysql-pv
    server: 192.168.229.187
[root@master mysql]# vim mysql-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs
[root@master mysql]# mkdir -p /nfsdata/mysql-pv
[root@master mysql]# kubectl apply -f mysql-pv.yaml
[root@master mysql]# kubectl get pv
[root@master mysql]# kubectl apply -f mysql-pvc.yaml
[root@master mysql]# kubectl get pvc

2.部署mysql

[root@master mysql]# vim mysql.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: mysql
spec:
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: 123.com
        volumeMounts:
        - name: mysql-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
---
kind: Service
apiVersion: v1
metadata:
  name: mysql
spec:
  type: NodePort
  selector:
    app: mysql
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306
    nodePort: 31306

3.在MySQL数据库中添加数据

[root@master mysql]# kubectl exec -it pod mysql-6fccccd487-pkx86 bash
mysql -u root -p123.com
mysql> SHOW DATABASES;  #查看当前的库
mysql> CREATE DATABASE TEST;  #创建test库
mysql> USE TEST;  #选择使用test库
mysql> SHOW TABLES;  #查看test库中的表
mysql> CREATE TABLE my_id(id int(4));  #创建my_id表
mysql> INSERT my_id values (9527);  #往my_id表中插入数据
mysql> SELECT * FROM my_id;  #查看my_id表中所有数据

4.模拟MySQL服务故障
k8s集群会生产一个新的Pod,验证这个Pod内是否有之前数据。
先查看运行MySQL服务的Pod在哪个节点,然后将该节点挂起,我们知道k8s肯定会在另外一个节点重新生成一个Pod。

[root@master ~]# kubectl get pod -o wide

新生成Pod后,同样进入Pod验证数据是否存在?存在。

[root@master ~]# kubectl get pod
[root@master ~]# kubectl exec -it pod mysql-6fccccd487-5q2dt bash
mysql -u root -p123.com
mysql> show databases;
mysql> use test;
mysql> show tables;
mysql> select * from my_id;
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐