linux运维、架构之路-K8s数据管理

一、Volume介绍

容器和Pod是短暂的,它们的生命周期可能很短,会被频繁的销毁和创建,存在容器中的数据会被清除,为了持久化保存容器的数据,k8s提供了Volume。
Volume的生命周期独立于容器,它是一个目录,Volume会被mount到Pod,Pod中的所有容器都可以访问这个Volume,和Docker Volume类似。
Volume支持的类型:emptyDir、hostPath、AWS Elastic Block Store、NFS、Ceph等。

1、emptyDir

       emptyDir是最基础的Volume类型,它对于容器来说是持久的,对于Pod刚不是,当Pod从节点删除时Volume中的数据也会被删除,如果只是容器被销毁而Pod还在,则Volume不受影响。

①创建示例应用

apiVersion: v1
kind: Pod
metadata:
  name: hello-world
spec:
  containers:
  - image: busybox
    name: hello
    volumeMounts:
    - mountPath: /hello_dir   #②hello容器将shared-volume mount到/hello_dir目录 
      name: shared-volume
    args:
    - /bin/sh       #③hello通过echo将数据写到文件hello里
    - -c
    - echo "hello world" >/hello_dir/hello; sleep 30000

  - image: busybox
    name: world    #④world容器将 shared-volume mount到 /world_dir目录
    volumeMounts:
    - mountPath: /world_dir
      name: shared-volume
    args:
    - /bin/sh     #⑤world通过cat从文件hello读取数据
    - -c
    - cat /world_dir/hello; sleep 30000

  volumes:
  - name: shared-volume   #①定义了一个emptyDir类型的Volume shared-volume
    emptyDir: {}

②查看验证

[root@k8s-node1 volume]# kubectl apply -f emptyDir.yaml 
pod "hello-world" created

[root@k8s-node1 volume]# kubectl get pod
NAME          READY     STATUS    RESTARTS   AGE
hello-world   2/2       Running   0          36s

[root@k8s-node1 volume]# kubectl logs hello-world world 
hello world

上述显示容器world成功读到了hello容器写入的数据,验证了两个容器共享emptyDir Volume,其效果相当于执行了docker run -v /hello_dir 和/docker run -v /world_dir

emptyDir是Host主机上创建的临时目录,其优点能够方便地为Pod中的容器提供共享存储,但不具有持久性,如果Pod不存在了,emptyDir也就没有了,适合Pod中容器需要临时共享存储空间的应用场景

2、HostPath

        hostPath Volume的作用是将Docker Host文件系统中已经存在的目录mount给Pod的容器,大部分应用不会使用此类型,因为这实际上增加上了Pod与节点的耦合,有些需要访问k8s内部数据,比如配置文件和二进制库这样的应用需要使用hostPath,例如k8s自身的应用kube-apiserver和kube-controller-manager。

3、外部Storage Provider

       如果k8s部署在AWS、GCE、Azure等公有云上,可以直接使用云盘作为Volume。因资源有限,此处无法演示。

二、PV & PVC

  • PV是外部存储系统中的一块存储空间,由管理员创建,与Volume一样具有持久性,生命周期独立于Pod。
  • PVC刚是对PV的申请,PVC通常由普通用户创建,需要为Pod分配存储资源时,用户可以创建一个PVC,指明存储资源的容量大小和访问权限等,k8s会查找并提供满足条件的PV。
  • k8s支持多种类型的PV,比如AWS EBS、Ceph、NFS等

1、NFS PV

①在k8s-master节点搭建一个NFS服务,目录为/nfsdata

[root@k8s-node1 ~]# showmount -e
Export list for k8s-node1:
/nfsdata *

NFS服务具体部署请参照https://www.cnblogs.com/yanxinjiang/p/7419469.html

②创建应用示例

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv
spec:
  capacity:
    storage: 1Gi    #指定PV的容量为1GB
  accessModes:
    - ReadWriteOnce  #表示PV能为read-write模式mount到单个节点,ReadOnlyMany表示只读,mount到多个节点,ReadWriteMany表示读写可以mount到多节点
  persistentVolumeReclaimPolicy: Recycle  #PV的回收策略,清除PV中的数据,Retain表示管理员手工回收
  storageClassName: nfs    #指定PV的class为nfs,相当于为PV设置了一个分类,PVC可以指定class申请相应的PV
  nfs:
    path: /nfsdata/pv1     #指定PV在NFS服务器上对应的目录
    server: 192.168.56.11
[root@k8s-node1 nfs-pv]# kubectl apply -f nfs-pv1.yaml 
persistentvolume "mypv1" created 
[root@k8s-node1 nfs-pv]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE   #STATUS为Available,表示mypv1就绪,可以被PVC申请
mypv1     1Gi        RWO            Recycle          Available             nfs                      4s       

③创建PVC

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mypv
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs
[root@k8s-node1 nfs-pv]# kubectl apply -f nfs-pvc1.yaml 
persistentvolumeclaim "mypvc1" created
[root@k8s-node1 nfs-pv]# kubectl get pvc
NAME      STATUS    VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc1    Bound     mypv1     1Gi        RWO            nfs            13s
[root@k8s-node1 nfs-pv]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM            STORAGECLASS   REASON    AGE
mypv1     1Gi        RWO            Recycle          Bound     default/mypvc1   nfs                      22m

结果:mypvc1已经成功绑定到mypv1上面

④在Pod中使用存储

kind: Pod
apiVersion: v1
metadata:
  name: mypod1
spec:
  containers:
    - name: mypod1
      image: busybox
      args:
      - /bin/sh
      - -c
      - sleep 30000
      volumeMounts:
      - mountPath: "/mydata"
        name: mypv
  volumes:
    - name: mypv
      persistentVolumeClaim:
        claimName: mypv

⑤测试验证

[root@k8s-node1 nfs-pv]# kubectl apply -f pod1.yaml
[root@k8s-node1 nfs-pv]# kubectl get pod -o wide
NAME      READY     STATUS    RESTARTS   AGE       IP           NODE
mypod1    1/1       Running   0          11m       10.2.83.14   192.168.56.12
[root@k8s-node1 nfs-pv]# kubectl exec mypod1 touch /mydata/readme.md
[root@k8s-node1 nfs-pv]# ls /nfsdata/pv1/
readme.md

在Pod中创建的文件/mydata已经存储到了NFS服务器目录/nfsdata/pv1中。

⑥回收PV

  • 当不需要使用PV时,可用删除PVC回收PV
[root@k8s-node1 nfs-pv]# kubectl delete pvc mypvc1 
persistentvolumeclaim "mypvc1" deleted

因PV的回收策略设置为Recycle,所以数据会被清除,如想保存数据,可以将策略设置为Retain

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv1
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain  #Recycle
  storageClassName: nfs
  nfs:
    path: /nfsdata/pv1
    server: 192.168.56.11
[root@k8s-node1 nfs-pv]# kubectl apply -f nfs-pv1.yaml 
persistentvolume "mypv1" configured 
[root@k8s-node1 nfs-pv]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM            STORAGECLASS   REASON    AGE
mypv1     1Gi        RWO            Retain           Bound     default/mypvc1   nfs

⑦验证

[root@k8s-node1 nfs-pv]# kubectl apply -f nfs-pvc1.yaml 
[root@k8s-node1 nfs-pv]# kubectl exec mypod1 touch /mydata/hello.world
[root@k8s-node1 nfs-pv]# ls /nfsdata/pv1/
hello.world
[root@k8s-node1 nfs-pv]# kubectl delete pvc mypvc1 
persistentvolumeclaim "mypvc1" deleted
[root@k8s-node1 nfs-pv]# ls /nfsdata/pv1/
hello.world

2、PV动态供给

  • 静态供给:我们提前创建PV,通过PVC申请PV并在Pod中使用
  • 动态供给:如果没有满足PVC条件的PV,会动态创建PV,不需要提前创建PV,效率高,通过StorageClass实现。     

3、k8s中MySQL数据持久化存储

①创建PV和PVC

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    server: 192.168.56.11
    path: /data/k8s/mysql-pv

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

查看pv,pvc状态

[root@k8s-node1 mysql]# kubectl apply -f mysql_pv.yaml 
persistentvolume "mysql-pv" created
persistentvolumeclaim "mysql-pvc" created
 
[root@k8s-node1 mysql]# kubectl get pv,pvc
NAME                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM               STORAGECLASS   REASON    AGE
persistentvolume/mysql-pv   2Gi        RWO            Retain           Bound     default/mysql-pvc   nfs                      4s

NAME                              STATUS    VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/mysql-pvc   Bound     mysql-pv   2Gi        RWO            nfs            4s

②部署MySQL

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.6
        imagePullPolicy: IfNotPresent
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: password
        ports:
        - name: mysql
          containerPort: 3306
        volumeMounts:
        - mountPath: /var/lib/mysql
          name: mysql-persistent-storage
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: mysql

创建应用查看

[root@k8s-node1 mysql]# kubectl apply -f mysql.yaml 
deployment.apps "mysql" created
[root@k8s-node1 k8s]# kubectl get pod -o wide
NAME                     READY     STATUS    RESTARTS   AGE       IP          NODE
mysql-57c44d9d5f-5v7qc   1/1       Running   0          7m        10.2.8.25   192.168.56.13

③进入MySQL数据库创建测试数据

kubectl exec -it mysql-57c44d9d5f-5v7qc /bin/bash
root@mysql-57c44d9d5f-5v7qc:/# mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.6.46 MySQL Community Server (GPL)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 
mysql> 
mysql> 
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
mysql> create database test;
Query OK, 1 row affected (0.01 sec)

mysql> use test;
Database changed

mysql> create table my_id(id int(4));
Query OK, 0 rows affected (0.03 sec)

mysql> insert my_id values(111);
Query OK, 1 row affected (0.01 sec)


mysql> select * from my_id;
+------+
| id   |
+------+
|  111 |
+------+
1 row in set (0.00 sec)

④模拟k8s-node3节点故障

 此时node3节点变为不可用

[root@k8s-node1 mysql]# kubectl get node
NAME            STATUS     ROLES     AGE       VERSION
192.168.56.12   Ready      <none>    6d        v1.10.3
192.168.56.13   NotReady   <none>    6d        v1.10.3

⑤等待一段时间后,k8s会将MySQL迁移至node2节点

[root@k8s-node1 mysql]# kubectl get pod -o wide
NAME                     READY     STATUS    RESTARTS   AGE       IP           NODE
mysql-57c44d9d5f-5v7qc   1/1       Unknown   0          47m       10.2.8.25    192.168.56.13
mysql-57c44d9d5f-6gvh5   1/1       Running   0          18m       10.2.93.74   192.168.56.12
[root@k8s-node1 mysql]# kubectl exec -it mysql-57c44d9d5f-6gvh5 /bin/bash

⑥再次登录MySQL验证数据的一致性

root@mysql-57c44d9d5f-6gvh5:/# mysql -uroot -ppassword
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.46 MySQL Community Server (GPL)

Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.02 sec)
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| my_id          |
+----------------+
1 row in set (0.00 sec)

mysql> select * from my_id;
+------+
| id   |
+------+
|  111 |
+------+
1 row in set (0.00 sec)

结果:MySQL服务恢复,数据无丢失

posted @ 2019-12-23 15:23  闫新江  阅读(584)  评论(0编辑  收藏  举报