K8s 数据存储之Volume

作者: AlienPaul | 来源:发表于2020-02-06 15:42 被阅读0次

    Volume的作用

    一切container和它之中的数据都是临时的。如果container重启,这些数据会丢失。Volume用于container保存需要持久化的数据。这些数据也可以用于container共享。

    Volume的概念

    Docker中有volume的概念。在Docker中,volume是container中的一个目录。Volume没有生命周期的概念,volume中的数据只有储存在本地磁盘这一种形式。

    Kubernetes的volume具有明确的生命空间。Volume生命周期比pod中运行的container长。Container重启之后,volume的数据仍会保留。但是,当Pod销毁之时,该pod关联的volume也会同时销毁。

    使用volume的方法:在spec.volumes处声明volume,在spec.containers[*].volumeMount中挂载volume到container。

    Volume的类型

    ConfigMap

    可以将ConfigMap的值注入到volume中。这样可以在pod中使用config map。同时,Volume中的值会随着ConfigMap的修改而自动更新。

    在Volume中使用ConfigMap的用法如下:

    apiVersion: v1
    kind: Pod
    metadata:
      name: configmap-pod
    spec:
      containers:
        - name: test
          image: busybox
          volumeMounts:
            - name: config-vol
              mountPath: /etc/config
      volumes:
        - name: config-vol
          configMap:
            name: log-config
            items:
              - key: log_level
                path: log_level
    

    这里例子将名字为log-config的config map中key为log_level的值,作为文件log_level的内容,放入config-vol的根目录。然后把config-vol挂载到/etc/config,目录。也就是container中/etc/config/log_level文件的内容为log-config中log_level的值。

    downwardAPI

    可以使用DownWard API的方式,将k8s资源的spec信息作为文件内容放入到volume中。

    例子如下:

    apiVersion: v1
    kind: Pod
    metadata:
      name: kubernetes-downwardapi-volume-example
      labels:
        zone: us-est-coast
        cluster: test-cluster1
        rack: rack-22
      annotations:
        build: two
        builder: john-doe
    spec:
      containers:
        - name: client-container
          image: k8s.gcr.io/busybox
          command: ["sh", "-c"]
          args:
          - while true; do
              if [[ -e /etc/podinfo/labels ]]; then
                echo -en '\n\n'; cat /etc/podinfo/labels; fi;
              if [[ -e /etc/podinfo/annotations ]]; then
                echo -en '\n\n'; cat /etc/podinfo/annotations; fi;
              sleep 5;
            done;
          volumeMounts:
            - name: podinfo
              mountPath: /etc/podinfo
      volumes:
        - name: podinfo
          downwardAPI:
            items:
              - path: "labels"
                fieldRef:
                  fieldPath: metadata.labels
              - path: "annotations"
                fieldRef:
                  fieldPath: metadata.annotations
    

    此处volume使用了downwardAPI。volume中labels文件的内容为pod metadata的labels配置项内容,即:

    zone: us-est-coast
    cluster: test-cluster1
    rack: rack-22
    

    annotation文件的内容为为pod metadata的annotations配置项内容,即:

    build: two
    builder: john-doe
    

    emptyDir

    生命周期和pod一样。emptyDir的初始状态为一个没有任何内容的volume。如果Pod从集群节点上移除,那么emptyDir类型的volume中的内容会被清除。

    Container遇到崩溃或重启,这时候Pod本身不会受任何影响,这种情况下emptyDir volume中的数据会保留。Container重启之后数据仍然可见。

    emptyDir volume具有的这种特性适合如下场景使用:

    • 存放临时文件
    • 存放检查点,供container崩溃后恢复用

    默认来说emptyDir类型volume的物理存储在硬盘,SSD或网络设备上。可以设置emptyDir.mediumMemory,这时候k8s会使用tempfs(基于内存的文件系统)。此时volume的容量限制收到container的内存配额的制约。

    配置样例为:

    apiVersion: v1
    kind: Pod
    metadata:
        name: fortune
    spec:
        containers:
        - image: luksa/fortune
          name: html-generator
          volumeMounts:
          - name: html
            mountPath: /var/htdocs
        - image: nginx:alpine
          name: web-server
          volumeMounts:
          - name: html
            mountPath: /usr/share/nginx/html
            readOnly: true
          ports:
            - containerPort: 80
              protocol: TCP
        volumes:
        - name: html
          emptyDir: {}
    

    使用tempfs(内存)的emptyDir volume的配置样例如下;

    volumes:
        - name: html
            emptyDir:
                medium: Memory
    

    gitRepo(已废弃)

    gitRepo比较简单:先准备一个emptyDir类型的volume,再clone一个git repo到volume,然后把volume mount到container。

    apiVersion: v1
    kind: Pod
    metadata:
        name: gitrepo-volume-pod
    spec:
        containers:
        - image: nginx:alpine
          name: web-server
          volumeMounts:
          - name: html
            mountPath: /usr/share/nginx/html
            readOnly: true
          ports:
          - containerPort: 80
            protocol: TCP
        volumes:
        - name: html
          gitRepo:
            repository: https://github.com/luksa/kubia-website-example.git
            revision: master
            directory: .
    

    hostPath

    此模式挂载pod宿主机文件系统中的文件或目录到pod。

    hostPath必须指定一个path参与,用于指定使用宿主机哪个目录。

    除此之外还有一个可选的type参数,有如下值可供配置:

    • (空,什么都不写):不进行任何检查
    • DirectoryOrCreate:如果path对应的目录不存在,自动创建一个目录,权限为0755,所属用户和用户组于kubelet相同。
    • Directory:path对应的目录必须存在。
    • FileOrCreate:如果path对应的文件不存在,自动创建一个空文件,权限为0644,所属用户和用户组于kubelet相同。
    • File:path对应的文件必须存在。
    • Socket:path必须对应一个unix socket。
    • CharDevice:path必须对应一个character device。
    • BlockDevice:path必须对应一个block device。

    需要注意的是由于hostPath类型volume的数据和宿主机强绑定,如果pod停止后被schedule到其他节点,pod读取到的数据会有变化。

    使用hostPath的例子:

    apiVersion: v1
    kind: Pod
    metadata:
      name: test-pd
    spec:
      containers:
      - image: k8s.gcr.io/test-webserver
        name: test-container
        volumeMounts:
        - mountPath: /test-pd
          name: test-volume
      volumes:
      - name: test-volume
        hostPath:
          # directory location on host
          path: /data
          # this field is optional
          type: Directory
    

    local

    local模式支持使用磁盘,分区或者是目录。local还支持使用静态创建的PersistentVolume,不支持Dynamic provisioning(使用PVC的方式)。

    与hostPath不同的是,local模式无需手动配置将pod调度到固定的node上。local模式系统通过volume的node affinity配置来感知volume的node限制(volume只能生成在特定的node上)。

    使用例子:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: example-pv
    spec:
      capacity:
        storage: 100Gi
      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
    

    nodeAffinity必须配置。这个例子创建出的PersistentVolume必须创建在hostname包含example-node的节点上。

    VolumeMode默认值为Filesystem。可以配置为Block,将volume作为块设备使用。

    使用local模式的时候建议配套的StorageClass的volumeBindingMode设置为WaitForFirstConsumer。如下所示:

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: local-storage
    provisioner: kubernetes.io/no-provisioner
    volumeBindingMode: WaitForFirstConsumer
    

    延迟volume绑定可以允许在volume绑定的时候考虑到pod中配置的一些限制,例如node资源限制,node选择器和pod affinity以及pod anti-affinity。

    persistentVolumeClaim

    使用PVC声明式的创建所需的PersistentVolume。这个稍后在PersistentVolume中介绍。

    projected

    映射多个类型的配置(数据源)到volume中。相当于多种volume合并使用。

    可以映射的volume类型为:

    • secret
    • downwardAPI
    • configMap
    • serviceAccountToken

    所有的volume数据源要求必须和使用它的pod在同一个namespace之下。

    一个使用例子如下:

    apiVersion: v1
    kind: Pod
    metadata:
      name: volume-test
    spec:
      containers:
      - name: container-test
        image: busybox
        volumeMounts:
        - name: all-in-one
          mountPath: "/projected-volume"
          readOnly: true
      volumes:
      - name: all-in-one
        projected:
          sources:
          - secret:
              name: mysecret
              items:
                - key: username
                  path: my-group/my-username
          - downwardAPI:
              items:
                - path: "labels"
                  fieldRef:
                    fieldPath: metadata.labels
                - path: "cpu_limit"
                  resourceFieldRef:
                    containerName: container-test
                    resource: limits.cpu
          - configMap:
              name: myconfigmap
              items:
                - key: config
                  path: my-group/my-config
    

    使用subPath

    通常我们绑定volume时,映射的是volume的根目录。我们可以通过指定subPath参数,将volume中的其他目录挂载到container中。对于一个pod多个container,且多处使用同一个volume的场景最为适用。

    例子如下:

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-lamp-site
    spec:
        containers:
        - name: mysql
          image: mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: "rootpasswd"
          volumeMounts:
          - mountPath: /var/lib/mysql
            name: site-data
            subPath: mysql
        - name: php
          image: php:7.0-apache
          volumeMounts:
          - mountPath: /var/www/html
            name: site-data
            subPath: html
        volumes:
        - name: site-data
          persistentVolumeClaim:
            claimName: my-lamp-site-data
    

    这个例子中mysql和php两个container使用同一个volume site-data。Volume的mysql目录映射到了mysql container的/var/lib/mysql。Volume的html目录映射到了php container的/var/www/html

    资源使用

    emptyDir使用磁盘时的限制取决于kubelet所在的文件系统(/var/lib/kubelet)。emptyDir或者hostPath占用多大磁盘空间是没有限制的。

    相关文章

      网友评论

        本文标题:K8s 数据存储之Volume

        本文链接:https://www.haomeiwen.com/subject/muhuxhtx.html