天天看點

k8s資料持久化k8s資料持久化

k8s資料持久化

Docker容器是有生命周期的,是以資料卷可以實作資料持久化

資料卷主要解決的問題:

  • 資料持久性:當我們寫入資料時,檔案都是暫時性的存在,當容器崩潰後,host就會将這個容器殺死,然後重新從鏡像建立容器,資料就會丢失
  • 資料共享:在同一個Pod中運作容器,會存在共享檔案的需求

存儲類(Storage class)是k8s資源類型的一種,它是有管理者為管理PV更加友善建立的一個邏輯組,可以按照存儲系統的性能高低,或者綜合服務品質,備份政策等分類。不過k8s本身不知道類别到底是什麼,它這是作為一個描述。

存儲類的好處之一就是支援PV的動态建立,當使用者用到持久性存儲時,不必再去提前建立PV,而是直接建立PVC就可以了,非常的友善。

存儲類對象的名稱很重要,并且出了名稱之外,還有3個關鍵字段

Provisioner(供給方):

及提供了存儲資源的存儲系統。k8s内建有多重供給方,這些供給方的名字都以“kubernetes.io”為字首。并且還可以自定義。

Parameters(參數):存儲類使用參數描述要關聯到的存儲卷,注意不同的供給方參數也不同。

reclaimPolicy:PV的回收政策,可用值有Delete(預設)和Retain

Volume:

emptyDir(空目錄):使用情況比較少,一般隻做臨時使用,類似Docker資料 持久化的:docker manager volume,該資料卷初始配置設定時,是一個空目錄,同一個Pod中的容器可以對該目錄有執行讀寫操作,并且共享資料

​ 使用場景:在同一個Pod裡,不同的容器,共享資料卷

​ 如果容器被删除,資料仍然存在,如果Pod被删除,資料也會被删除

使用執行個體:

[root@master ~]# vim emptyDir.yaml
apiVersion: v1
kind: Pod
metadata:
  name: producer-consumer
spec:
  containers:
  - image:  busybox
    name: producer
    volumeMounts:
    - mountPath:  /producer_dir  //容器内的路徑
      name: shared-volume  //指定本地的目錄名
    args:
    - /bin/sh
    - -c
    - echo  "hello k8s" > /producer_dir/hello;  sleep 30000

  - image:  busybox
    name: consumer
    volumeMounts:
    - mountPath:  /consumer_dir
      name: shared-volume
    args:
    - /bin/sh
    - -c
    - cat /consumer_dir/hello;  sleep 30000

  volumes:
  - name: shared-volume  //這裡的名字必須與上面的Pod的mountPath的name相對應
    emptyDir: {}   //定義資料持久化類型,即表示空目錄
[root@master ~]# kubectl  applky   -f  emptyDir.yaml
[root@master ~]# kubectl  get  pod
NAME                READY   STATUS    RESTARTS   AGE  
producer-consumer   2/2     Running   0          14s
[root@master ~]# kubectl  logs  producer-consumer  consumer 
hello  k8s           

//使用inspect檢視挂載的目錄在哪(檢視Mount字段)

[root@master ~]# kubectl  get  pod -o wide
NAME                READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
producer-consumer   2/2     Running   0          69s   10.244.1.2   node01   <none>           <none>
//可以看到容器運作在node01上,在node01上找到這個容器并檢視并檢視詳細資訊
[root@node01 ~]# docker ps
CONTAINER ID        IMAGE
f117beb235cf        busybox
13c7a18109a1        busybox
[root@node01 ~]# docker inspect 13c7a18109a1
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume",
                "Destination": "/producer_dir", //容器内的挂載目錄
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
//再檢視另一個容器
[root@node01 ~]# docker inspect f117beb235cf
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume",
                "Destination": "/consumer_dir",  //容器内的挂載目錄
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
//可以看到兩個容器使用的同一個挂載目錄
[root@node01 ~]# cd  /var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume
[root@node01 shared-volume]# ls
hello
[root@node01 shared-volume]# cat hello 
hello  k8s           

//将容器删除,驗證目錄是否存在

[root@node01 ~]# docker rm  -f  13c7a18109a1 
13c7a18109a1
[root@node01 ~]# docker ps
CONTAINER ID        IMAGE
a809717b1aa5        busybox
f117beb235cf        busybox
//它會重新生成一個新的容器,來達到我們使用者所期望的狀态,是以這個目錄還是存在的           

//删除Pod

[root@master ~]# kubectl  delete  pod producer-consumer
[root@master ~]# ls  /var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume
ls: 無法通路/var/lib/kubelet/pods/5225f542-0859-4a6a-8d99-1f23b9781807/volumes/kubernetes.io~empty-dir/shared-volume: 沒有那個檔案或目錄
//Pod删除後資料也會被删除           

hostPath Volume(使用場景也比較少):類似Docker資料持久化的:bind mount

将Pod所在節點的檔案系統上某一個檔案或目錄挂載進容器内

​ 如果Pod被删除,資料會保留,相比較emptyDir會好一點,不過,一旦host崩潰,hostPath也無法通路

docker或者k8s叢集本身的存儲會采用hostPath這種方式

k8s叢集中會有很多pod,如果都是用hostPath Volume的話管理起來很不友善,是以就用到了PV

Persistent Volume | PV(持久卷)提前做好的,資料持久化的資料存放目錄

是叢集中的一塊存儲空間,由叢集管理者管理或者由Storage class(存儲類)自動管理,PV和pod、deployment、Service一樣,都是一個資源對象

PersistentVolume(PV)是叢集中已由管理者配置的一段網絡存儲。 叢集中的資源就像一個節點是一個叢集資源。 PV是諸如卷之類的卷插件,但是具有獨立于使用PV的任何單個pod的生命周期。 該API對象捕獲存儲的實作細節,即NFS,iSCSI或雲提供商特定的存儲系統

Psesistent Volume Claim | PVC(持久卷使用聲明|申請)

PVC代表使用者使用存儲的請求,應用申請PV持久化空間的一個申請、聲明。K8s叢集可能會有多個PV,你需要不停的為不同的應用建立多個PV

它類似于pod。Pod消耗節點資源,PVC消耗存儲資源。 pod可以請求特定級别的資源(CPU和記憶體)。 權限要求可以請求特定的大小和通路模式

官方文檔有更詳細的說明:https://www.kubernetes.org.cn/pvpvcstorageclass

基于NFS服務來做的PV

[root@master ~]# yum  -y  install  nfs-utils (需要節點全部下載下傳,會報挂載類型錯誤)
[root@master ~]# yum  -y  install  rpcbind
[root@master ~]# mkdir  /nfsdata
[root@master ~]# vim  /etc/exports
/nfsdata  *(rw,sync,no_root_squash)
[root@master ~]# systemctl  start  rpcbind
[root@master ~]# systemctl  start  nfs-server
[root@master ~]# showmount  -e
Export list for master:
/nfsdata *           

1.建立PV(實際的存儲目錄) 2.建立PVC 3.建立pod

建立PV資源對象:

[root@master ~]# vim nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-pv
spec:
  capacity: //PV容量的大小
    storage:  1Gi
  accessModes: //PV支援的通路模式
    - ReadWriteOnce
  persistentVolumeReclaimPolicy:  Recycle //PV的存儲空間的回收政策是什麼
  storageClassName: nfs
  nfs:
    path: /nfsdata/pv1
    server: 192.168.1.70
[root@master ~]# kubectl  apply  -f  nfs-pv.yaml
[root@master ~]# kubectl  get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Recycle          Available           nfs                     9m30s           

accessModes: (PV支援的通路模式)

​ - ReadWriteOnce:能以讀-寫的方式mount到單個節點

​ - ReadWariteMany:能以讀-寫的方式mount到多個節點

​ - ReadOnlyOnce:能以隻讀的方式mount到單個節點

persistentVolumeReclaimPolicy:(PV的存儲空間的回收政策是什麼)

​ Recycle:自動清除資料

​ Retain:需要管理者手動回收

​ Delete:雲存儲專用。直接删除資料

PV和PVC互相的關聯:通過的是storageClassName && accessModes

建立PVC

[root@master ~]# vim  nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:    //通路模式
    - ReadWriteOnce  
  resources:
    requests:
      storage:  1Gi   //申請的容量大小
  storageClassName:  nfs    //向哪個PV申請
[root@master ~]# kubectl apply -f nfs-pvc.yaml
[root@master ~]# kubectl get pvc
NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc   Bound    test-pv   1Gi        RWO            nfs            14s           

PV的應用:

建立一個Pod資源:

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

之前建立PV的時候指定的挂載目錄是/nfsdata/pv1,我們并沒有建立pv1這個目錄,是以這個pod是運作不成功的。

以下是排錯方法:

  1. kubectl describe
  2. kubectl logs
  3. /var/log/messages
  4. 檢視該節點的kubelet的日志
//使用kubectl describe
[root@master ~]# kubectl  describe  pod  test-pod
mount.nfs: mounting 192.168.1.70:/nfsdata/pv1 failed, reason given by server: No such file or directory  //提示沒有檔案或目錄
           

建立目錄,再檢視pod狀态:

[root@master ~]# mkdir  /nfsdata/pv1
NAME       READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
test-pod   1/1     Running   0          12m   10.244.1.3   node01   <none>           <none>
           

驗證是否應用成功:

[root@master ~]# kubectl  exec  test-pod  touch /mydata/hello
[root@master ~]# ls  /nfsdata/pv1/
hello
[root@master ~]# echo  123  >  /nfsdata/pv1/hello 
[root@master ~]# kubectl  exec  test-pod  cat /mydata/hello
123
           

删除Pod,驗證回收政策(Recycle):

[root@master ~]# kubectl  delete  pod  test-pod
[root@master ~]# kubectl  delete  pvc test-pvc
[root@master ~]# kubectl  get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Recycle          Available           nfs                     42h
[root@master ~]# ls  /nfsdata/pv1/
[root@master ~]#
//驗證成功,資料已經回收
           

通常情況下不會設定為自動删除,不然就和emptyDir就差不多了

删除pv,修改回收政策:

之前是先建立PV--->PVC--->Pod,現在調整一下,先建立PV--->---Pod--->PVC

[root@master ~]# vim  nfs-pv.yaml 
  persistentVolumeReclaimPolicy:  Retain
[root@master ~]# kubectl  apply  -f  nfs-pv.yaml 
[root@master ~]# kubectl  get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Retain           Available           nfs                     7s
[root@master ~]# kubectl  apply  -f  pod.yaml 
[root@master ~]# kubectl  get pod
NAME       READY   STATUS    RESTARTS   AGE
test-pod   0/1     Pending   0          5s  //Pending正在被排程
[root@master ~]# kubectl  describe  pod test-pod
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  41s (x2 over 41s)  default-scheduler  persistentvolumeclaim "test-pvc" not found
//沒有發現對應的pvc

建立pvc
[root@master ~]# kubectl  apply  -f  nfs-pvc.yaml
[root@master ~]# kubectl  get pod
NAME       READY   STATUS    RESTARTS   AGE
test-pod   1/1     Running   0          114s
           

驗證Retain(管理者手動删除)回收政策:

[root@master ~]# kubectl  exec test-pod  touch  /mydata/k8s
[root@master ~]# ls  /nfsdata/pv1/
k8s
[root@master ~]# kubectl  delete  pod test-pod 
[root@master ~]# kubectl  delete  pvc test-pvc
[root@master ~]# ls  /nfsdata/pv1/
k8s
//可以看到并沒有回收
[root@master ~]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Retain           Available           nfs                     6s
           

mysql對資料持久化的應用:

//這裡就不再建立PV,PVC了,用之前的就行

[root@master ~]# kubectl  apply  -f  nfs-pvc.yaml 
[root@master ~]# kubectl  get pvc
NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc   Bound    test-pv   1Gi        RWO            nfs            7s
           

建立Deploment資源對象,mysql容器

[root@master ~]# vim mysql.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: test-mysql
spec:
  selector:
    matchLabels:  //基于等值的标簽
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: 123.com
        volumeMounts:
        - name: mysql-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: test-pvc
[root@master ~]# kubectl  get deployments.
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
test-mysql   1/1     1            1           61s
           
[root@master ~]# kubectl  get pod -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
test-mysql-569f8df4db-fnnxc   1/1     Running   0          32m   10.244.1.5   node01   <none>           <none>
[root@master ~]# kubectl  exec  -it  test-mysql-569f8df4db-fnnxc  --  mysql -u root -p123.com
mysql> create database yun33;  //建立資料庫
mysql> use yun33;  //選擇使用資料路
Database changed
mysql> create table my_id( id int(4));  建立表
mysql> insert my_id values(9527);  //在表中插入資料
mysql> select * from my_id;  //檢視表中所有資料
+------+
| id   |
+------+
| 9527 |
+------+
1 row in set (0.00 sec)
[root@master ~]# ls /nfsdata/pv1/
auto.cnf  ibdata1  ib_logfile0  ib_logfile1  k8s  mysql  performance_schema  yun33
           
[root@master ~]# kubectl get pod -o wide -w
NAME                          READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
test-mysql-569f8df4db-fnnxc   1/1     Running   0          36m   10.244.1.5   node01   <none>           <none>
test-mysql-569f8df4db-fnnxc   1/1     Terminating   0          38m   10.244.1.5   node01   <none>           <none>
test-mysql-569f8df4db-2m5rd   0/1     Pending       0          0s    <none>       <none>   <none>           <none>
test-mysql-569f8df4db-2m5rd   0/1     Pending       0          0s    <none>       node02   <none>           <none>
test-mysql-569f8df4db-2m5rd   0/1     ContainerCreating   0          0s    <none>       node02   <none>           <none>
test-mysql-569f8df4db-2m5rd   1/1     Running             0          2s    10.244.2.4   node02   <none>           <none>
[root@master ~]# kubectl get pod -o wide 
NAME                          READY   STATUS        RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
test-mysql-569f8df4db-2m5rd   1/1     Running       0          20s   10.244.2.4   node02   <none>           <none>
test-mysql-569f8df4db-fnnxc   1/1     Terminating   0          38m   10.244.1.5   node01   <none>           <none>
           
[root@master ~]# kubectl  exec -it test-mysql-569f8df4db-2m5rd  -- mysql -u root -p123.com
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| yun33              |
+--------------------+
4 rows in set (0.01 sec)

mysql> use yun33;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-----------------+
| Tables_in_yun33 |
+-----------------+
| my_id           |
+-----------------+
1 row in set (0.01 sec)

mysql> select *  from my_id;
+------+
| id   |
+------+
| 9527 |
+------+
1 row in set (0.01 sec)
[root@master ~]# ls  /nfsdata/pv1/
auto.cnf  ibdata1  ib_logfile0  ib_logfile1  k8s  mysql  performance_schema  yun33
           

繼續閱讀