[单master节点k8s部署]12.持久化存储

持久化存储需要定义pod的volume,在容器中使用volumemouts挂载存储

emptyDir临时存储

创建一个有挂载卷的pod

在 Kubernetes 中,Pod 的容器中的 volumeMountname 必须与 volumes 中定义的卷的 name 相同,以便正确地挂载卷到容器中。因此,在你的 YAML 文件中,volumeMounts 中的 namevolumes 中的 name 需要相同

apiVersion: v1
kind: Pod
metadata:
  name: empty-pod
spec: 
  containers:
  - name: empty-pod
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
      mountPath: /volume
      name: cache-volume
  volumes:
  - emptyDir:
      {}
    name: cache-volume

运行后查看pod的uid。可以看到pod运行在node1上

[root@master volume]# kubectl get pods -owide
NAME                                 READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
client-5c75576967-l258d              1/1     Running   0          76m   10.244.166.183   node1   <none>           <none>
empty-pod                            1/1     Running   0          9s    10.244.166.185   node1   <none>           <none>
[root@master volume]# kubectl get pods empty-pod  -o yaml | grep uid
  uid: 87622a4f-dcc0-4127-a51e-2bc1d3f24cb7

查看node1的文件目录,进入/var/lib/kubelet/pods目录下,通过uid进入该pod的目录

[root@node1 ~]# cd /var/lib/kubelet/pods
[root@node1 pods]# ls
3b5623f9-b593-431c-992d-a5672a6f3e43  781772e9-4825-4a5c-9639-ee14ca3ee328  929cb6a4-4194-4c1c-bd7a-6cbfa5bc7be3  e8b74cda-ce80-4e2b-9ef1-d2b9f534e99a
68280322-a7d6-4d63-8753-750d956229f4  87622a4f-dcc0-4127-a51e-2bc1d3f24cb7  d9a16ca2-e0b9-4ab0-bc6a-3b77f065ee6a
[root@node1 pods]# cd 87622a4f-dcc0-4127-a51e-2bc1d3f24cb7
[root@node1 87622a4f-dcc0-4127-a51e-2bc1d3f24cb7]# ls
containers  etc-hosts  plugins  volumes
[root@node1 87622a4f-dcc0-4127-a51e-2bc1d3f24cb7]# cd volumes
[root@node1 volumes]# ls
kubernetes.io~empty-dir  kubernetes.io~projected
[root@node1 volumes]# cd kubernetes.io~empty-dir/
[root@node1 kubernetes.io~empty-dir]# ls
cache-volume
[root@node1 kubernetes.io~empty-dir]# cd cache-volume/
[root@node1 cache-volume]# ls
[root@node1 cache-volume]# 

 进入emptyDir目录后,发现cache-volume为空,在该目录下新建目录aa,随后进入pod的内部,发现aa,也就是说yaml文件中的mountpath和物理节点上的emptyDir下的cache-volume是等价的,而name 相同是为了方便挂载的。

[root@master volume]# kubectl exec -it empty-pod -- /bin/sh
# ls
bin  boot  dev	docker-entrypoint.d  docker-entrypoint.sh  etc	home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume
# cd volume
# ls
aa
# 

此时删掉pod,node1上整个目录被删掉,aa自然也不复存在。

hostPath持久存储

写一个yaml文件,是在物理节点上的固定存储,这个pod包含两个container,他们两个都挂载在物理节点的/data1文件夹下

apiVersion: v1
kind: Pod
metadata:
  name: test-hostpath
spec:
  containers:
  - name: test-nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - mountPath: /test-nginx
      name: test-volume
  - name: test-tomcat
    iamge: tomcat:8.5-jre8-alpine
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - mountPath: /test-tomcat
      name: test-volume
  volumes:
    name: test-volume
    hostPath: /data1
    type: DirectoryOrCreate
 

进入物理节点查看,注意这个data1文件夹的权限使得无法通过ls命令查看。在该目录下创建一个文件夹aa

[root@node1 ~]# ls -ld /data1
drwxr-xr-x 3 root root 16 6月  27 20:18 /data1
[root@node1 ~]# cd /data1
[root@node1 data1]# ls
aa

查看两个container的目录结构,发现aa的存在,在两个container目录中分别 创建两个文件夹,也会体现在/data1文件夹中

[root@master volume]# kubectl exec -it test-hostpath -c test-nginx -- /bin/bash
root@test-hostpath:/# ls
bin   dev		   docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  test-nginx	usr
boot  docker-entrypoint.d  etc			 lib   media  opt  root  sbin  sys  tmp		var
root@test-hostpath:/# cd test-nginx
root@test-hostpath:/test-nginx# ls
aa
root@test-hostpath:/test-nginx# mkdir nginx1
root@test-hostpath:/test-nginx# ls
aa  nginx1
root@test-hostpath:/test-nginx# exit
exit
[root@master volume]# kubectl exec -it test-hostpath -c test-tomcat -- /bin/bash
bash-4.4# ls
BUILDING.txt     LICENSE          README.md        RUNNING.txt      conf             lib              native-jni-lib   webapps
CONTRIBUTING.md  NOTICE           RELEASE-NOTES    bin              include          logs             temp             work
bash-4.4# cd /test-tomcat/
bash-4.4# ls
aa      nginx1
bash-4.4# mkdir tomcat1
bash-4.4# ls
aa       nginx1   tomcat1
bash-4.4# ls -ld /test-tomcat
drwxr-xr-x    3 root     root            16 Jun 27 12:18 /test-tomcat
bash-4.4# exit
exit

 但是这个做法有一个弊端,就是如果删除pod后,新创建的pod没有调度到这个物理节点上,那么数据还是会丢失。

nfs网络存储

nfs全称network file system,是一种网络文件系统,允许多个客户端通过网络共享同一个文件系统,本身并不是持久化存储的实现,而是一种存储协议。

在 Kubernetes 集群中,只要一个节点上运行了 NFS 服务器,这个节点就可以对外提供 NFS 服务,所有共享的文件都存储在这个节点上。

先运行这个nfs服务,任何需要共享存储的node都需要把虚拟的存储目录挂载在自己本地的一个目录。

创建需要共享的目录:

[root@master ~]# mkdir /data/volumes -pv
mkdir: 已创建目录 "/data"
mkdir: 已创建目录 "/data/volumes"

在master节点上配置nfs服务器:

vim /etc/exports
>
/data/volumes *(rw,sync,no_subtree_check)
sudo exportfs -arv //重新导出共享目录,以应用新的配置

*代表允许所有客户端访问,可以规定只允许某个网段的客户端访问。

rw代表可以读写。

sync,强制数据同步写入磁盘,还有async,这个允许缓存数据从而提高性能,但是存在数据丢失的风险。

no_subtree_check: 禁用子树检查。子树检查是 NFS 服务器检查文件路径的完整性的一种机制,禁用它可以提高性能,尤其是在共享的目录不是根目录时。

然后把这个nfs目录挂载到不同的节点上。首先挂载在本身

[root@master ~]# mount 100.64.252.90:/data/volumes /nfs_mount/

然后挂载到node1

[root@node1 data1]# mount 100.64.252.90:/data/volumes /nfs_node1

在node1的nfs_node1目录下创建一个文件,可以看到nfs服务器的挂载点可以看到(master节点)

[root@node1 nfs_node1]# echo  "hello,this is io,the machine" > index.html
[root@node1 nfs_node1]# ls
index.html
[root@master ~]# cd /data/volumes/
[root@master volumes]# ls
index.html

创建一个pod,可以看到这里挂载的是nfs的服务器的卷

[root@master ~]# cat nfs.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test-nfs-volume
spec:
  containers:
  - name: test-nfs
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - containerPort: 80
      protocol: TCP
    volumeMounts:
    - name: nfs-volumes
      mountPath: /usr/share/nginx/html
  volumes:
  - name: nfs-volumes
    nfs:
     path: /data/volumes
     server: 100.64.252.90

启动后,进入pod,也可以看到这个文件

[root@master volumes]# kubectl exec -it test-nfs-volume -- /bin/bash
root@test-nfs-volume:/# cd /usr/share/nginx/html
root@test-nfs-volume:/usr/share/nginx/html# ls
index.html
pvc持久化存储

pvc全名PersistentVolumeClaim,是一个持久化存储的卷,在创建pod的时候可以定义这个类型的存储卷。PV是集群中的一块存储,由管理员配置或使用。PV是容量插件,其生命周期独立于使用PV的任何单个pod。

我们可以通过创建pod的方式创建PVC存储卷,pod消耗节点资源,PVC消耗PV资源。

如上面的yaml文件所示,如果创建的是pod文件或者是deployment文件,是可以挂载在nfs目录下,nfs目录在挂在物理节点上,实现持久化存储。但是如果每次都在pod中直接配置NFS挂载,可能会导致重复配置和管理困难。

PVC 提供了持久化存储卷的生命周期管理。即使 Pod 被删除或重新调度,PVC 仍然存在,并保持其绑定的 PV 和存储数据。使用 PVC,可以在一个地方定义存储请求,并在多个 Pod 中复用。

定义pv资源:

[root@master volume]# cat pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v1
spec:
  capacity:
    storage: 1Gi
  accessModes: ["ReadWriteOnce"]
  nfs:
    path: /data/volume_test/v1
    server: 100.44.252.90
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v2
spec:
  capacity:
    storage: 2Gi
  accessModes: ["ReadWriteMany"]
  nfs:
    path: /data/volume_test/v2
    server: 100.44.252.90
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v3
spec:
  capacity:
    storage: 2Gi
  accessModes: ["ReadWriteMany"]
  nfs:
    path: /data/volumes/aa
    server: 100.64.252.90

查看pv的状态,这里的3个pv资源都是可用的,表示没有被绑定

[root@master volume]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
v1     1Gi        RWO            Retain           Available                                   26m
v2     2Gi        RWX            Retain           Available                                   26m
v3     2Gi        RWX            Retain           Available                                   13s

创建pvc,用来绑定pv

[root@master volume]# cat pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
 accessModes: ["ReadWriteMany"]
 resources:
   requests:
     storage: 2Gi

应用以后,发现pvc自然绑定了一个pv,符合他的要求。如果再创建一个2.5Gi的pvc,则会绑定失败,这个未绑定的pvc会显示是pending

[root@master volume]# kubectl apply -f pvc.yaml
persistentvolumeclaim/my-pvc created
[root@master volume]# kubectl get pvc
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
my-pvc   Bound    v3       1Gi        RWX                           19h
pvc1     Bound    v2       2Gi        RWX                           5s

创建一个pod,用来绑定这个pvc,yaml如下

[root@master volume]# cat pod_pvc.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-pvc
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: nginx-html
      mountPath: /usr/share/nginx/html
  volumes:
  - name: nginx-html
    persistentVolumeClaim:
     claimName: my-pvc

发现绑定失败,所以pod创建失败,查看具体的问题

Events:
  Type     Reason       Age   From               Message
  ----     ------       ----  ----               -------
  Normal   Scheduled    2m8s  default-scheduler  Successfully assigned default/pod-pcv-1 to node1
  Warning  FailedMount  5s    kubelet            Unable to attach or mount volumes: unmounted volumes=[nginx-html], unattached volumes=[nginx-html kube-api-access-m2kwl]: timed out waiting for the condition

查看问题在哪里,查看nfs在本机的挂载点(发现一开始挂载目录不对):

[root@master volume]# mount | grep nfs
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)
nfsd on /proc/fs/nfsd type nfsd (rw,relatime)
100.64.252.90:/data/volumes on /nfs_mount type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=100.64.252.90,local_lock=none,addr=100.64.252.90)
100.64.252.90:/data/volume_test on /nfs_mount1 type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=100.64.252.90,local_lock=none,addr=100.64.252.90)

可以看到本机的挂载点是/nfs_mount1和/nfs_mount, 而在nfs服务器上的挂载点是100.64.252.90,目录是/data/volumes 和/data/volume_test,因为nfs服务器就是本机,所以这两个目录也在本机上。

查看node1上的挂载点

[root@node1 ~]# mount | grep nfs
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)
nfsd on /proc/fs/nfsd type nfsd (rw,relatime)
100.64.252.90:/data/volumes on /nfs_node1 type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=100.64.212.7,local_lock=none,addr=100.64.252.90)
100.64.252.90:/data/volumes/aa on /var/lib/kubelet/pods/04e4b76c-4f45-452a-a869-03632d80f1af/volumes/kubernetes.io~nfs/v3 type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=100.64.212.7,local_lock=none,addr=100.64.252.90)
100.64.252.90:/data/volume_test/v2 on /var/lib/kubelet/pods/7f1c4ae5-b779-430e-bc27-6c425a206912/volumes/kubernetes.io~nfs/v2 type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=100.64.212.7,local_lock=none,addr=100.64.252.90)

可以看到 这里提到了nfs服务器的/data/volumes的目录是挂载在/nfs_node1上,而后面两行显示/data/volumes/aa目录被挂载在pv的v3上,如下的v3的yaml所示,/data/volume_test/v2挂载在v2的pv上。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: v3
spec:
  capacity:
    storage: 1Gi
  accessModes: ["ReadWriteMany"]
  nfs:
    path: /data/volumes/aa
    server: 100.64.252.90

绑定pod成功后,查看pod:

[root@master volume]# kubectl get pods -owide
NAME              READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES
pod-pcv-1         1/1     Running   0          19m     10.244.166.189   node1   <none>           <none>
pod-pvc           1/1     Running   0          20h     10.244.166.188   node1   <none>           <none>
test-nfs-volume   1/1     Running   0          2d13h   10.244.104.36    node2   <none>           <none>

 此时在pod里创建一个文件夹,然后把pod删除,再创建的pod只要绑定在原有的pvc上,那么这个文件夹还在pod里。

删除pv

删除一个 Pod 通常不会直接影响绑定到它的 PVC。PVC 和 Pod 的生命周期是分开的,当删除一个 Pod 时,PVC 仍然会保留在 Kubernetes 集群中,以及它所绑定的 PV 也不会受到影响。这样设计的目的是为了数据的持久性,即使应用被重新部署或删除,数据也能保持不变。

删除pvc,可以看到直接删除是无效的,pvc会处于terminating状态,这是一个保护机制,因此需要改变pvc的finalizers标签,这个标签可以保护pvc不被删除。

[root@master volume]# kubectl get pvc
NAME     STATUS        VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
my-pvc   Bound         v3       1Gi        RWX                           19h
pvc1     Terminating   v2       2Gi        RWX                           27m
[root@master volume]# kubectl delete pvc pvc1
persistentvolumeclaim "pvc1" deleted
^C
[root@master volume]# kubectl get pvc
NAME     STATUS        VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
my-pvc   Bound         v3       1Gi        RWX                           19h
pvc1     Terminating   v2       2Gi        RWX                           27m
[root@master volume]# kubectl patch pvc pvc1 -p '{"metadata":{"finalizers": []}}' --type=merge
persistentvolumeclaim/pvc1 patched
[root@master volume]# kubectl get pvc
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
my-pvc   Bound    v3       1Gi        RWX                           19h

删除pvc后,根据不同的回收策略,会对绑定的pv进行处理:

  • Retain:PV 会保持存在并转为 "Released" 状态,但不会被自动回收。管理员需要手动处理这些 PV。
  • Delete:PV 和底层存储将会被自动删除。
  • Recycle(不推荐使用,已被废弃在许多 Kubernetes 版本):PV 会被清理并准备好重新使用,但这个选项依赖于底层存储系统的支持。

删除pv也是同理,如果删除一个没有被绑定的pv,那么直接删除,否则需要更改pv的filanlizer。

storageClass存储类
创建nfs供应商

存储类最关键的功能之一是支持动态卷供应。在没有存储类的情况下,管理员必须手动预先创建和配置持久卷(PV),然后这些卷才能被持久卷声明(PVC)使用。存储类允许用户通过 PVC 请求存储时,自动创建卷。这样,用户就不需要提前知道具体的卷如何和在哪里被创建。

用户提交一个pvc到kubernetes,然后kubernetes会检查pvc中是否指定了storageClass,如果指定了,kubernetes将使用这个storageClass,否则会使用集群默认的storageClass。storage查看provisioner字段,查看哪个存储插件应该被使用来创建卷,然后创建一个pv。

创建一个service Account用来和kubernetesAPI交互,这个account用来为nfs-provisioner提供权限和身份验证,以便在k8s集群内部提供操作权限和管理资源。这个简单的yaml文件只是定义了name,从而可以和nfs-provisioner绑定。

apiVersion: v1
kind: ServiceAccount
metadata: 
  name: nfs-provisioner

授权,将一个clusterRole(这里是cluster-admin)关联到上面的serviceAccount里面。

kubectl create clusterrolebinding nfs-provisioner-clusterrolebinding --clusterrole=cluster-admin --serviceaccount=default:nfs-provisioner

nfs的存储插件的deployment文件:其中image就是nfs的插件的镜像。将该pod与服务相连,通过spec里面的serviceAccount字段

其中环境变量中的provisioner_name为example.com/nfs

[root@master nfs]# cat nfs-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-provisioner
  strategy: 
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-provisioner
    spec:
      serviceAccount: nfs-provisioner
      containers:
      - name: nfs-provisioner
        image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: nfs-client-root
          mountPath: /persistentVolumes
        env:
        - name: PROVISIONER_NAME
          value: example.com/nfs
        - name: NFS_SERVER
          value: 100.64.252.90
        - name: NFS_PATH
          value: /data/nfs_pro
      volumes:
      - name: nfs-client-root
        nfs:
          path: /data/nfs_pro
          server: 100.64.252.90

第一次配置的时候写的container name为aa,但是发现如果这样写后面pvc会挂载失败,不知道为什么,后面改成和pod name一样就正常了。 

然后将上面yaml文件里定义的挂载目录挂载到nfs服务器上

[root@master ~]# cat /etc/exports
/data/volumes *(rw,no_root_squash)
/data/volume_test/v1 *(rw,no_root_squash)
/data/volume_test/v2 *(rw,no_root_squash)
/data/nfs_pro *(rw,no_root_squash)
[root@master ~]# exportfs -var
exporting *:/data/nfs_pro
exporting *:/data/volume_test/v2
exporting *:/data/volume_test/v1
exporting *:/data/volumes
创建存储类

创建一个存储类,规定nfs-provisioner字段

[root@master nfs]# cat nfs-storageclass.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs
provisioner: example.com/nfs
[root@master nfs]# kubectl get storageclass
NAME   PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs    example.com/nfs   Delete          Immediate           false                  13s

可以看到因为没有规定其他字段,所以它的回收策略是delete,也就是绑定的pvc删除后,pv也删除,而volumebindingmode是立即绑定,还有另一种方法:WaitForFirstConsumer:延迟绑定模式,PV 的创建和绑定会等到有 Pod 需要时才进行,以确保 PV 与 Pod 在同一区域。

另一个字段是是否允许在线扩容,默认为false。

创建pvc

创建一个pvc,发现直接与nfs绑定,这是因为在pvc的yaml文件中定义了storageClassName的字段为nfs。

[root@master nfs]# cat claim.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-claim
spec:
  accessModes: ["ReadWriteMany"]
  storageClassName: nfs
  resources:
    requests:
      storage: 1Gi
[root@master nfs]# kubectl get pvc
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-claim   Bound    pvc-b921af0c-5e6d-4920-9607-472217483910   1Gi        RWX            nfs            6s

然后创建pod,和pvc绑定

[root@master nfs]# cat pod_claim.yaml 
kind: Pod 
apiVersion: v1 
metadata: 
 name: read-pod 
spec: 
 containers: 
 - name: read-pod 
   image: nginx 
   imagePullPolicy: IfNotPresent 
   volumeMounts: 
   - name: nfs-pvc 
     mountPath: /usr/share/nginx/html 
 restartPolicy: "Never" 
 volumes: 
 - name: nfs-pvc 
   persistentVolumeClaim: 
     claimName: test-claim

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值