如果不用volume

不用volume,pod的文件默认用docker的overlay2存储,pod删除后里面存储的内容就没了
举例说明 查看pod在docker里的存储目录
先查看pod的docker id

  1. kubectl describe pods -n kube-system kube-controller-manager-iz8vb91u3c0d2ijj2osl5wz

image.png

根据docker id查找pod所在的目录

  1. docker ps -q | xargs docker inspect --format '{{.State.Pid}}, {{.Id}}, {{.Name}}, {{.GraphDriver.Data.WorkDir}}' | grep d20802c90a2a6818c6d13bcd1bfd

image.png

image.png

可用的卷

有多种卷类型可供选择。其中一些是通用的,而另一些则相对于当前常用的存储技术有较大差别。如果从来没有听说过这些技术,也别太担心一一其中至少一半我也没有昕说过。你有可能只会用到那些自己熟悉和曾经用过的卷技术。以下是
几种可用卷类型的列表:
• emptyDir一一用于存储临时数据的简单空目录。
• hostPath -一用于将目录从工作节点的文件系统挂载到pod 中。
• gitRepo一一通过检出Git 仓库的内容来初始化的卷。
• nfs一一挂载到pod 中的NFS 共享卷。
• gcePersistentDisk (Google 高效能型存储磁盘卷)、awsElastic、BlockStore (AmazonWeb 服务弹性块存储卷)、azureDisk (Microso负Azure 磁盘卷)一一用于挂载云服务商提供的特定存储类型。
• cindr 、cephfs 、iscsi 、flocker 、glusterfs 、quobyte 、rbd 、flexVolume 、vsphere -Volume 、photoPersistentDisk 、scaleIO用于挂载其他类型的网络存储。
• configMap 、secret 、downwardAPI 一一用于将Kubemetes 部分资源和集
群信息公开给pod 的特殊类型的卷。
• persistentVolume一一一种使用预置或者动态配置的持久存储类型

emptyDir

最简单的卷类型是emp tyDir 卷,所以作为第一个例子让我们看看如何在pod中定义卷。顾名思义,卷从一个空目录开始,运行在pod 内的应用程序可以写入它需要的任何文件。因为卷的生存周期与pod 的生存周期相关联,所以当删除pod 时,卷的内容就会丢失。

使用 emptyDir

  1. cat > myapp-empty.yaml << EOF
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. name: myapp-empty
  6. namespace: default
  7. labels:
  8. app: myapp
  9. type: pod
  10. spec:
  11. containers:
  12. - name: myapp
  13. image: ikubernetes/myapp:v1
  14. ports:
  15. - name: http
  16. containerPort: 80
  17. volumeMounts:
  18. - name: html
  19. mountPath: /usr/share/nginx/html/
  20. - name: busybox
  21. image: busybox:latest
  22. imagePullPolicy: IfNotPresent
  23. command:
  24. - "/bin/sh"
  25. - "-c"
  26. - "echo 'this is test' > /data/test.html;sleep 3600"
  27. volumeMounts:
  28. - name: html
  29. mountPath: /data/
  30. volumes:
  31. - name: html
  32. emptyDir: {}
  33. EOF

image.png

image.png

指定用于emptyDir 的介质

作为卷来使用的emptyDir ,是在承载pod 的工作节点的实际磁盘上创建的,因此其性能取决于节点的磁盘类型。但我们可以通知Kubemetes 在tmfs 文件系统( 存在内存而非硬盘) 上创建emptyDir 。因此,将emptyDir 的medium 设置为Memory
image.png

image.png

指定emptyDir 的大小

image.png

image.png

gitRepo

gitRepo volume可以理解为是emptyDir volume的一种实际应用,使用该volume的Pod可以在挂载目录访问指定的代码仓库。
image.png

使用gitRepo

  1. cat > gitRepo.yaml << EOF
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. name: vol-gitrepo-pod
  6. spec:
  7. containers:
  8. - name: nginx
  9. image: nginx:1.12-alpine
  10. volumeMounts:
  11. - name: html
  12. mountPath: /usr/share/nginx/
  13. volumes:
  14. - name: html
  15. gitRepo:
  16. repository: "https://github.com/tangwei0928/html.git"
  17. revision: "master"
  18. EOF

image.png

hostPath

大多数 pod 应该忽略它们的主机节点,因此它们不应该出问节点文件系统上的任何文件。 但是某些系统级别的 pod(切记,这些通常由 DaemonSet 管理)确实需要读取节点的文件或使用节点文件系统来访问节点设备。 Kubemetes 通过 hostPath 卷实现了这一点。
hostPath 卷指向节点文件系统上的特定文件或目录。在同一 个节点上运行并在其 hostPath 卷中使用相同路径的 pod 可以看到相同的文件。
image.png

hostPath 卷是我们介绍的第一种类型的持久性存储,因为 gitRepo 和 emptyDir 卷的内容都会在 pod 被删除时被删除,而 hostPath 卷的内容则不会被删除。如果删除了一个 pod,并且下一个 pod 使用了指向主机上相同路径的 hostPath 卷,则新 pod 将会发现上一个 pod 留下的数据,但前提是必须将其调度到与第一个 pod 相同的节点上。 如果你正在考虑使用 hostPath 卷作为存储数据库数据的目录,请重新考虑。 因为卷的内容存储在特定节点的文件系统中,所以当数据库 pod 被重新安排在另一 个节点时,会找不到数据。 这解释了为什么对常规 pod 使用 hostPath 卷不是一个好主意,因为这会使 pod 对预定规划的节点很敏感。

使用hostPath

  1. cat > myapp-hostpath.yaml << EOF
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. name: myapp-hostpath
  6. namespace: default
  7. labels:
  8. app: myapp
  9. type: pod
  10. spec:
  11. containers:
  12. - name: myapp
  13. image: ikubernetes/myapp:v1
  14. ports:
  15. - name: http
  16. containerPort: 80
  17. volumeMounts:
  18. - name: html
  19. mountPath: /usr/share/nginx/html/
  20. volumes:
  21. - name: html
  22. hostPath:
  23. path: /data/pod/
  24. type: DirectoryOrCreate
  25. EOF

image.png

在pod节点hostpath目录下添加内容
image.png

NFS

如果集群是运行在自有的一组服务器上,那么就有大量其他可移植的选项用于在卷内挂载外部存储。 例如,要挂载一个简单的 NFS 共享,只需指定 NFS 服务器和共享路径。

使用NFS

  1. cat > myapp-nfs.yaml << EOF
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. name: myapp-nfs
  6. namespace: default
  7. labels:
  8. app: myapp
  9. type: pod
  10. spec:
  11. containers:
  12. - name: myapp
  13. image: ikubernetes/myapp:v1
  14. ports:
  15. - name: http
  16. containerPort: 80
  17. volumeMounts:
  18. - name: html
  19. mountPath: /usr/share/nginx/html/
  20. volumes:
  21. - name: html
  22. nfs:
  23. path: /data/volumes
  24. server: 192.168.33.101
  25. EOF

image.png

在nfs服务器上添加内容
image.png

image.png

PV

在 pod 中使用 PersistentVolume (持久卷,简称 PV) 要比使用常规的 pod 卷复杂一些。 研发人员无须向他们的 pod 中添加特定技术的卷,而是由集群管理员设置底层存储,然后通过 Kubernetes API 服务器创建持久卷并注册。 在创建持久卷时,管理员可以指定其大小和所支持的访问模式。 当集群用户需要在其 pod 中使用持久化存储时,他们首先创建持久卷声明 ( PersistentVolumeClaim, 简称 PVC)清单,指定所需要的最低容量要求和访问模式, 然后用户将持久卷声明清单提交给 Kubernetes API 服务器, Kubernetes 将找到可匹 配的持久卷并将其绑定到持久卷声明 。 持久卷声明可以当作 pod 中的一个卷来使用,其他用户不能使用相同的持久卷, 除非先通过删除障久卷声明绑定来释放。
image.png

pv参数

capacity

一般来说,一个 PV 对象都要指定一个存储能力,通过 PV 的 capacity属性来设置的,目前只支持存储空间的设置,就是我们这里的 storage=1Gi,不过未来可能会加入 IOPS、吞吐量等指标的配置。

accessModes

AccessModes 是用来对 PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

  • ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
  • ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
  • ReadWriteMany(RWX):读写权限,可以被多个节点挂载

13.Volumes - 图19

persistentVolumeReclaimPolicy

我这里指定的 PV 的回收策略为 Recycle,目前 PV 支持的策略有三种:

  • Retain(保留)- 保留数据,需要管理员手工清理数据
  • Recycle(回收)- 清除 PV 中的数据,效果相当于执行 rm -rf
  • Delete(删除)- 与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务,比如 ASW EBS。

不过需要注意的是,目前只有 NFS 和 HostPath 两种类型支持回收策略。当然一般来说还是设置为 Retain 这种策略保险一点。

使用nfs做pv

  1. cat > myapp-pv.yaml << EOF
  2. apiVersion: v1
  3. kind: PersistentVolume
  4. metadata:
  5. name: pv01
  6. labels:
  7. name: pv01
  8. type: pv
  9. spec:
  10. nfs:
  11. path: /data/volumes/v1
  12. server: 192.168.33.101
  13. accessModes: ["ReadWriteMany"]
  14. capacity:
  15. storage: 5Gi
  16. ---
  17. apiVersion: v1
  18. kind: PersistentVolumeClaim
  19. metadata:
  20. name: myapp-pvc
  21. namespace: default
  22. labels:
  23. app: myapp
  24. type: pvc
  25. spec:
  26. accessModes: ["ReadWriteMany"]
  27. resources:
  28. requests:
  29. storage: 1Gi
  30. ---
  31. apiVersion: v1
  32. kind: Pod
  33. metadata:
  34. name: myapp-nfs-pvc
  35. namespace: default
  36. labels:
  37. app: myapp
  38. type: pod
  39. spec:
  40. containers:
  41. - name: myapp
  42. image: ikubernetes/myapp:v1
  43. ports:
  44. - name: http
  45. containerPort: 80
  46. volumeMounts:
  47. - name: html
  48. mountPath: /usr/share/nginx/html/
  49. volumes:
  50. - name: html
  51. persistentVolumeClaim:
  52. claimName: myapp-pvc
  53. EOF

image.png

image.png

在nfs目录添加内容
image.png

使用local pv

local pv前提条件

  • 节点上需要打上调度需要的label
  • 节点上手动创建目录

image.png

  1. cat > local-pv.yaml << EOF
  2. kind: StorageClass
  3. apiVersion: storage.k8s.io/v1
  4. metadata:
  5. name: local-storage
  6. namespace: default
  7. provisioner: kubernetes.io/no-provisioner
  8. ---
  9. apiVersion: v1
  10. kind: PersistentVolume
  11. metadata:
  12. name: local-pv
  13. namespace: default
  14. spec:
  15. capacity:
  16. storage: 1Gi
  17. accessModes:
  18. - ReadWriteOnce
  19. persistentVolumeReclaimPolicy: Retain
  20. storageClassName: local-storage
  21. local:
  22. path: /data/localpv
  23. nodeAffinity:
  24. required:
  25. nodeSelectorTerms:
  26. - matchExpressions:
  27. - key: local-pv
  28. operator: In
  29. values:
  30. - node01
  31. ---
  32. kind: PersistentVolumeClaim
  33. apiVersion: v1
  34. metadata:
  35. name: local-pvc
  36. namespace: default
  37. spec:
  38. accessModes:
  39. - ReadWriteOnce
  40. resources:
  41. requests:
  42. storage: 1Gi
  43. storageClassName: local-storage
  44. ---
  45. apiVersion: v1
  46. kind: Pod
  47. metadata:
  48. name: myapp-local-pvc
  49. namespace: default
  50. labels:
  51. app: myapp
  52. type: pod
  53. spec:
  54. containers:
  55. - name: myapp
  56. image: ikubernetes/myapp:v1
  57. ports:
  58. - name: http
  59. containerPort: 80
  60. volumeMounts:
  61. - name: html
  62. mountPath: /usr/share/nginx/html/
  63. volumes:
  64. - name: html
  65. persistentVolumeClaim:
  66. claimName: local-pvc
  67. EOF

image.png

image.png

在local pv的目录里添加内容
image.png

Storageclass

学习了 PV 和 PVC 的使用方法,但是前面的 PV 都是静态的,什么意思?就是我要使用的一个 PVC 的话就必须手动去创建一个 PV,我们也说过这种方式在很大程度上并不能满足我们的需求,比如我们有一个应用需要对存储的并发度要求比较高,而另外一个应用对读写速度又要求比较高,特别是对于 StatefulSet 类型的应用简单的来使用静态的 PV 就很不合适了,这种情况下我们就需要用到动态 PV,也就是我们今天要讲解的 StorageClass。

要使用 StorageClass,我们就得安装对应的自动配置程序,比如我们这里存储后端使用的是 nfs,那么我们就需要使用到一个 nfs-client 的自动配置程序,我们也叫它 Provisioner,这个程序使用我们已经配置好的 nfs 服务器,来自动创建持久卷,也就是自动帮我们创建 PV。
image.png

使用nfs Storageclass

cat > myapp-sc.yaml << EOF
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: nfs-provisioner
            - name: NFS_SERVER
              value: 192.168.33.101
            - name: NFS_PATH
              value: /data/volumes
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.33.101
            path: /data/volumes
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
---
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", "create"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch", "create"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: k8s-nfs-storage
provisioner: nfs-provisioner
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nfs-web
spec:
  serviceName: "nginx"
  replicas: 1
  selector:
    matchLabels:
      app: nfs-web
  template:
    metadata:
      labels:
        app: nfs-web
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: ikubernetes/myapp:v1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
      annotations:
        volume.beta.kubernetes.io/storage-class: k8s-nfs-storage
    spec:
      accessModes: [ "ReadWriteMany" ]
      resources:
        requests:
          storage: 1Gi
EOF

实际工作中,使用 StorageClass 更多的是 StatefulSet 类型的服务,StatefulSet 类型的服务我们也可以通过一个 volumeClaimTemplates 属性来直接使用 StorageClass
image.png

image.png
在nfs目录里添加内容
image.png

image.png

local-volume-provisioner

在Kubernetes系统中使用本地盘可以通过HostPath、LocalVolume等类型的PV使用:

HostPath: 卷本身不带有调度信息,如果想对每个pod固定在某个节点上,就需要对pod配置nodeSelector等调度信息; LocalVolume: 卷本身包含了调度信息,使用这个卷的pod会被固定在特定的节点上,这样可以很好的保证数据的连续性。

通过local-volume-provisioner自动创建LocalVolume,PV附带所属的节点信息;
然后创建pvc, 使用这个pvc的pod都会调度到pv所指定的节点;

13.Volumes - 图32

监听宿主机上的某一个路径下面是不是有已经mount的好的文件夹,一旦看到有新的文件夹创建,那么它就会创建一个新的PV.
官方网站:https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner

查看pod

kubectl get pods -n acs-system

image.png

查看pv

kubectl get pv

image.png

查看监控的目录

kubectl get cm -n acs-system  local-provisioner-config  -o yaml

image.png

kubectl get  daemonsets.apps -n acs-system local-volume-provisioner -o yaml

image.png

挂载目录

在node01节点做测试

lsblk

image.png

mkdir /data/vol1
mkdir /data/vol2

mount /dev/sdc1 /data/vol1
mount /dev/sdc2 /data/vol2

image.png

挂载目录后

自动生成pv

kubectl get pv

image.png

测试pod

创建pvc pod,查看是否成功

vim local-volume.yaml
##创建pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
  namespace: acs-system
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: fast-disks

---
##创建pod
kind: Pod
apiVersion: v1
metadata:
  name: mypod
  namespace: acs-system
spec:
  containers:
    - name: myfrontend
      image: nginx:1.16
      volumeMounts:
      - mountPath: "/data"
        name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: myclaim

image.png