7-1、存储卷
存储卷 SAN:iSCSI, NAS:nfs,cifs,http 分布式存储:glusterfs,rbd(ceph),cephfs 云存储:EBS,Azure Disk, 储存方式:emptyDir,hostPath Volumes:卷 Persistent Volumes:持久卷(pvc) Volume Snapshots CSI Volume Cloning Storage Classes:存储类 存储卷常用类型 非持久性存储 emptyDir hostPath 网络连接性存储 SAN:iSCSI NFS:nfs,cfs 分布式存储 glusterfs、rbd、cephfs 云端存储 EBS、Azure Disk、阿里云、gitRepo https://www.cnblogs.com/caibao666/p/11268826.html 1 emptyDir 在节点上运行pod实例时才会创建emptyDir volume。它首先是节点上的一个空目录,pod中的任何容器都可以用volume的形式挂载使用它。如果容器因为某种原因被删除并重新启动,创建的emptyDir不会删除也不会被清空。当pod实例离开节点调度到其它节点或因为缩容被删除时,emptyDir被删除,相当于pod还在但数据丢了 常用于作为临时目录、或缓存使用。 medium:此目录所在的存储介质的类型,可取值为default或Memory,默认default,表示使用节点的默认存储介质;Memory表示使用基于ram的临时文件系统 tmpfs:空间受限于内存,但性能非常好,通常用于为容器中的应用提供缓存空间。 sizeLimit:当前存储卷的空间限额,默认值为nil,表示不限制;在medium字段值为Memory时,建议务必定义此限额。 # kubectl explain pods.spec.volumes # vi pod-volumes-demo.yaml apiVsersion: v1 kind: Pod metadata: name: pod-volumes namespace: default labels: app: myapp tier: frontend annotations: cluster.com/created-by: "cluster domain" spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 - name: https containerPort: 443 volumeMounts: - name: html mountPath: /data/web/html - name: busybox image: busybox:latest imagePolicy: IfNotPresent volumeMounts: - name: html mountPath: /data command: - "/bin/bash" - "-C" - "echo $(data) >> /data/index.htnl" volumes: - name: html emptyDir: {} # kubectl exec -it pod-demo {myapp,busybox} -- /bin/sh #都可以看到index.html ------------ # vi pod-volumes-demo.yaml apiVsersion: v1 kind: Pod metadata: name: pod-volumes namespace: default labels: app: myapp tier: frontend annotations: cluster.com/created-by: "cluster domain" spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 - name: https containerPort: 443 volumeMounts: - name: html mountPath: /data/web/html volumes: - name: html emptyDir: {} 2 使用hostPath https://kubernetes.io/docs/concepts/storage/volumes/#hostpath 这种类型的卷将文件或目录从宿主机节点的文件系统挂载到您的Pod中,当pod删除时,本地仍然保留文件 type: 值为空:空字符串(默认)用于向后兼容,这意味着在安装hostPath卷之前不会执行任何检查。 DirectoryOrCreate: 如果给定路径中不存在任何内容,则将根据需要创建一个空目录,权限设置为0755,与Kubelet具有相同的组和所有权。 Directory: 目录必须存在于给定路径中 FileOrCreate:如果给定路径中不存在任何内容,则会根据需要创建一个空文件,权限设置为0644,与Kubelet具有相同的组和所有权。 File:文件必须存在于给定路径中 Socket:UNIX套接字必须存在于给定路径中 CharDevice:字符设备必须存在于给定路径中 BlockDevice:块设备必须存在于给定路径中 # vi pod-hostpath-volumes.yaml apiVersion: v1 kind: Pod metadata: name: pod-volumes-hostpath namespace: default spec: containers: - name: myapp image: ikuebernetes/myapp:v1 voloumesMounts: - name: html mountPath: /usr/share/nginx/html/ volumes: - name: html hostPath: path: /data/pod/volumes type: DirectoryOrCreate # mkdir /data/pod/volumes # kubectl apply -f pod-hostpath-volumes.yaml 3 使用共享存储:nfs: NFS 是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。Pod被删除时,Volume被卸载,内容被保留。这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递。 有nfs存储,各节点挂载nfs # yum -y install nfs-utils # vi /etc/exports /data/volumes 172.20.0.0/16(rw,no_root_squash) # systemctl start nfs # showmount -e nfs-机器ip 节点上挂载: # mount -t nfs stor01.cluster.com:/data/volumes /data/volumes # vi pod-volumes-nfs.yaml apiVsersion: v1 kind: Pod metadata: name: pod-volumes-nfs namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /data/web/html volumes: - name: html nfs: path: /data/volumes server: stor01.cluster.com readOnly: false server:nfs服务器的IP地址或主机名,必选字段 path:nfs服务器共享的文件系统路径,必选字段 readOnly:是否以只读方式挂载,默认为false 4、Persistent Volume(PV)和Persistent Volume Claim(PVC) pv:持久卷,是底层的共享存储的一种抽象 pvc:持久卷声明,是对于存储需求的一种声明,就是向k8s系统发出的一种资源需求申请 PV的访问模型: accessModes: ReadWriteOnce【简写:RWO】: 单路读写,即仅能有一个节点挂载读写 ReadOnlyMany【ROX】: 多路只读 ReadWriteMany【RWX】:多路读写 创建持久卷pv: cat local-pv.yaml kind: PersistentVolume apiVersion: v1 metadata: name: pv0001 labels: type: local spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce hostPath: path: "/tmp/data01" kind:PersistentVolume → 我们已将种类定义为PersistentVolume,它告诉kubernetes使用的yaml文件是用于创建持久卷的。 name:pv0001 → 我们正在创建的PersistentVolume的名称。 capacity: → 此规格将定义我们尝试创建的PV的容量。 storage:10Gi → 这告诉底层基础结构我们正在尝试在定义的路径上声明10Gi空间。 ReadWriteOnce → 这将告诉我们正在创建的卷的访问权限。 path: "/tmp/data01" → 此定义告诉计算机我们正在尝试在基础结构的该路径下创建卷。 persistentVolumeReclaimPolicy:指定当PV的回收策略为Recycle, 支持的策略有: Retain – 需要管理员手工回收。 Recycle – 清除PV中的数据,效果相当于执行rm -rf /thevolume/*。 Delete – 删除Storage Provider上的对应存储资源,例如AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume等。 storageClassName:指定PV的class为nfs。相当于为PV设置了一个分类,PVC可以指定 class申请相应class的 PV。 RWX:为ReadWriteMany的简写 Retain:是回收策略 。Retain表示需要不使用了需要手动回收 # kubectl apply -f local-pv.yaml # kubectl get pv # kubectl describe pv pv0001 创建pvc: cat myclaim-1.yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: myclaim-1 spec: accessModes: - ReadWriteOnce resources: requests: storage: 3Gi kind:PersistentVolumeClaim → 它指示基础结构我们正在尝试声明指定的空间量。 name:myclaim-1 → 我们尝试创建的声明的名称。 ReadWriteOnce → 这将指定我们尝试创建的声明的模式。 storage:3Gi → 这将告诉kubernetes我们正在尝试声明的空间量。 # kubectl apply -f myclaim-1.yaml # kubectl get pvc 在POD中使用pv和pvc cat pod-pv.yaml kind: Pod apiVersion: v1 metadata: name: mypod labels: name: frontendhttp spec: containers: - name: myfrontend image: nginx ports: - containerPort: 80 name: "http-server" volumeMounts: - mountPath: "/usr/share/tomcat/html" name: mypd volumes: - name: mypd persistentVolumeClaim: claimName: myclaim-1 volumeMounts: →这是容器中将要进行安装的路径。 volumes: →此定义定义了我们要声明的体积定义。 persistentVolumeClaim: →在此之下,我们定义将在定义的pod中使用的卷名。 5、local 与emptyDir相似,它也占用节点的存储空间。不同点是它是kubernetes中的一种对象类型,用户可以像管理普通对象一样管理它。emptyDir在pod实例开时运行时分配,当pod离节点时删除。local类型的volume则由用户创建,系统在合适的节点上为其分配资源,调度到这个节点上的pod可以挂载它,pod离开时它也不会消失,除非用户删除。示例: 示例: apiVersion: v1 kind: PersistentVolume metadata: name: example-pv spec: capacity: storage: 100Gi # volumeMode field requires BlockVolume Alpha feature gate to be enabled. volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: local-storage local: path: /mnt/disks/ssd1 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - example-node 6、存储的动态供给 什么是动态供给? 每次使用存储要先创建pv, 再创建pvc,真累! 所以我们可以实现使用存储的动态供给特性。 静态存储需要用户申请PVC时保证容量和读写类型与预置PV的容量及读写类型完全匹配, 而动态存储则无需如此. 管理员无需预先创建大量的PV作为存储资源 Kubernetes从1.4版起引入了一个新的资源对象StorageClass,可用于将存储资源定义为具有显著特性的类(Class)而不是具体的PV。用户通过PVC直接向意向的类别发出申请,匹配由管理员事先创建的PV,或者由其按需为用户动态创建PV,这样就免去 了需要先创建PV的过程。 PV对存储系统的支持可通过其插件来实现,目前,Kubernetes支持如下类 型的插件。 官方地址:https://kubernetes.io/docs/concepts/storage/storage-classes/ 官方插件是不支持NFS动态供给的,但是我们可以用第三方的插件来实现 第三方插件地址: https://github.com/kubernetes-retired/external-storage storageclass底层可以是glusterfs,cephfs等不同的集群。 https://blog.51cto.com/u_13760351/2639942 1、下载并创建storageclass mv class.yaml storageclass-nfs.yml cat storageclass-nfs.yml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage provisioner: k8s-sigs.io/nfs-subdir-external-provisioner parameters: archiveOnDelete: "false" # kubectl apply -f storageclass-nfs.yml # kubectl get storageclass 2.下载并创建rbac 因为storage自动创建pv需要经过kube-apiserver,所以需要授权。 mv rbac.yaml storageclass-nfs-rbac.yaml cat storageclass-nfs-rbac.yaml apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner namespace: default --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner namespace: default subjects: - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io # kubectl apply -f storageclass-nfs-rbac.yaml 3.创建动态供给的deployment 需要一个deployment来专门实现pv与pvc的自动创建 vim deploy-nfs-client-provisioner.yml apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner namespace: default spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image:registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: k8s-sigs.io/nfs-subdir-external-provisioner - name: NFS_SERVER value: 192.168.0.137 - name: NFS_PATH value: /data volumes: - name: nfs-client-root nfs: server: 192.168.0.137 path: /data # kubectl apply -f deploy-nfs-client-provisioner.yml # kubectl get pods |grep nfs-client-provisioner 7、configmap configmap和secret是两种特殊的存储卷,它们不是给pod提供存储空间用的,而是给我们的管理员或者用户提供了从外部向pod内部注入信息的方式。 configmap:把配置文件放在配置中心上,然后多个pod读取配置中心的配置文件。不过,configmap中的配置信息都是明文的,所以不安全。 secret:功能和configmap一样,只不过配置中心存储的配置文件不是明文的。 configmap和secret也是专属于某个名称空间的。 用户首先创建configMap并创建数据保存其中,此时数据保存在kubernetes的etcd数据库中,volume还不存在。当用户在pod中引用创建的configMap时,系统首先在节点上创建volume并将数据保存其中,这个volume占用的是节占的存储空间。此后就可以像使用普通volume一样使用它。 configMap是kubernetes中的一种对象类型,核心本质是以volume的方式将单独管理的配置信息传递给pod中的容器,并非用来存储持久化数据 http://blog.itpub.net/28916011/viewspace-2214804/ configmap内容: server { server_name myapp.zhixin.com; listen 80; root /data/web/html; } # kubectl describe cm nginx-www Name: nginx-www Namespace: default Labels: <none> Annotations: <none> Data ==== : ---- server { server_name myapp.xx.com; listen 80; root /data/web/html; } (1)用ENV方式来把configmap注入到pod中去: cat pod-configmap.yaml apiVersion: v1 kind: Pod metadata: name: pod-cm-1 namespace: default labels: app: myapp #kv格式的,也可以用花括号表示 tier: frontend #定义所属的层次 annotations: chenzx.com/created-by: "cluster-admin" #这是注解的键值对 spec: containers: - name: myapp #前面的-号表示这是一个列表格式的,也可以用中括号表示 image: tomcat ports: - name: http containerPort: 80 env: #这是一个容器的属性 - name: NGINX_SERVER_PORT valueFrom: #kubectl explain pods.spec.containers.env.valueFrom configMapKeyRef: #表示我们要引用一个configmap来获取数据 name: nginx-config #这是configmap的名字,也就是通过kubectl get cm获取的名字 key: nginx_port #通过kubectl describe cm nginx-config的键 #下面开始引用第二个环境变量 - name: NGINX_SERVER_NAME valueFrom: configMapKeyRef: name: nginx-config key: server_name # kubectl apply -f pod-configmap.yaml (2)用配置mount存储卷的方法把configmap注入到pod中。 # cat pod-configmap2.ymal apiVersion: v1 kind: Pod metadata: name: pod-cm-2 namespace: default labels: app: myapp #kv格式的,也可以用花括号表示 tier: frontend #定义所属的层次 annotations: chenzx.com/created-by: "cluster-admin" #这是注解的键值对 spec: containers: - name: myapp #前面的-号表示这是一个列表格式的,也可以用中括号表示 image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 volumeMounts: - name: nginxconf mountPath: /etc/nginx/conf.d/ readOnly: true volumes: - name: nginxconf configMap: name: nginx-config # kubectl apply -f pod-configmap2.ymal 登录容器后:执行命令printenv结果: NGINX_SERVER_PORT=80 NGINX_SERVER_NAME=myapp.xx.com (3)下面我们再把前面创建的文件注入到POD中: # cat pod-configmap3.yaml apiVersion: v1 kind: Pod metadata: name: pod-cm-3 namespace: default labels: app: myapp #kv格式的,也可以用花括号表示 tier: frontend #定义所属的层次 annotations: chenzx.com/created-by: "cluster-admin" #这是注解的键值对 spec: containers: - name: myapp #前面的-号表示这是一个列表格式的,也可以用中括号表示 image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 volumeMounts: - name: nginxconf mountPath: /etc/nginx/conf.d/ readOnly: true volumes: - name: nginxconf configMap: name: nginx-www # kubectl apply -f pod-configmap3.yaml 登录容器后:cd /etc/nginx/conf.d/ ;cat nginx.conf
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」