k8s学习(七)-- 存储

学习目标:掌握多种存储类型的特点,并且能够在不同的环境中选择合适的存储方案

一、ConfigMap

  A、ConfigMap功能在kubernetes1.2版本中引入的,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API给我们提供了向容器注入配置信息的机制,ConfigMap可以被用来保存单个属性,也可以被用来保存整个配置文件或者JSON二进制大对象。

  B、ConfigMap创建

    1. 使用目录创建

      a. ls /docs/user-guide/configmap/kubectl/

        game.properties

        ui.properties

      b. cat /docs/user-guide/configmap/kubectl/game.properties

        enemies=aliens

        lives=3

        enemies.cheat=true

        enemies.cheat.level=noGoodRotten

      c. cat /docs/user-guide/configmap/kubectl/ui.properties

        color.good=purple

        color.bad=yellow

        allow.textmode=true

      d. kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl

        --from-file指定在目录下的所有文件都会被用在ConfigMap里创建一个键值对,键的名字就是文件名,值就是文件的内容。

    2. 使用文件创建:和使用目录创建一样,只不过指定的是文件而不是目录

    3.使用字面值创建:

      a. 使用字面值创建,利用-from-literal参数传递配置信息,该参数可以使用多次,格式如下

        kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm 

  C、ConfigMap的使用

    1. 使用configmap来代替环境变量

      apiVersion: v1
      kind: Pod
      metadata:
        name: dapi-test-pod
      spec:
        containers:
          - name: test-container
            image: hub.atguigu.com/library/myapp:v1
            command: ["/bin/sh","-c","env"]
            env:
            - name: SPECIAL_LEVEL_KEY
              valueFrom:
              configMapKeyRef:
                name: special-config
                key: special.how
            - name: SPECIAL_TYPE_KEY
              valueFrom:
              configMapKeyRef:
                name: special-config
                key: special.type
            envFrom:
            - configMapRef:
              name: env-config
            restartPolicy: Never

    2. 用ConfigMap设置命令行参数(和第一种导入方式一样,只是使用思想不一样)

    3. 通过数据卷插件使用configmap

      a. 在数据卷里使用这个ConfigMap,有不同的选项。最基本就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容。

    4. configmap的热更新

      a. 

        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: log-config
          namespace: default
        data:
          log_level: INFO
        ---
        apiVersion: extensions/v1beta1
        kind: Deployment
        metadata:
          name: my-nginx
        spec:
          replicas: 1
          template:
            metadata:
              labels:
                run: my-nginx
            spec:
              containers:
                - name: my-nginx
                  image: hub.atguigu.com/library/myapp:v1
                  ports:
                  - containerPort: 80
                  volumeMounts:
                  - name: config-volume
                    mountPath: /etc/config
              volumes:
                - name: config-volume
                  configMap:
                  name: log-config

      b. 更改配置

        kubectl edit configmap log-config

      c. 就自动热更新了

      d. ConfigMap更新后滚动更新pod

        更新ConfigMap目前不会触发相关pod的滚动更新,可以通过修改pod annotation的方式强行触发滚动更新

        kubectl patch deployment my-nginx --patch '{"spec":{"template":{"metadata:{"annotation":{"version/config":"20190411"}}"}}}'

        这个例子里我们在.spec.template.metadata.annotations中添加version/config,每次通过修改version/config来触发滚动更新

二、secret

  A、secret解决了密码、token、秘钥等敏感数据配置问题,而不需要把这些敏感数据暴露到镜像或者pod spec中。secret可以以volume或者环境变量的方式使用。

  B、secret有三种类型:

    1. Service Account:用来访问Kubernetes API,由kubernetes自动创建,并且会自动挂载到pod的 /run/secrets/kubernetes.io/serviceaccount目录中

    2. Opaque:base64编码格式的Secret,用来存储密码、秘钥等

      a. Opaque类型的数据是一个map类型,要求value是一个base64编码格式。

      b. 例子      

        [root@k8s-master01 ~]# echo -n "admin" | base64
        YWRtaW4=

        [root@k8s-master01 ~]# echo -n "123456" | base64
        MTIzNDU2

        apiVersion: v1
        kind: Secret
        metadata:
          name: mysecret
        type: Opaque
        data:
          username: YWRtaW4=
          password: MTIzNDU2

      c. 使用方式

        1)将secret挂载到volume中

          apiVersion: v1
          kind: Pod
          metadata:
            name: use-secret-volume
          spec:
            volumes:
              - name: secrets
                secret:
                secretName: mysecret
            containers:
              - name: use-secret-volume-container
                image: hub.atguigu.com/library/myapp:v1
                volumeMounts:
                - name: secrets
                  mountPath: "/etc/secrets"
                  readOnly: true

        2)将secret导出到环境变量中

          apiVersion: extensions/v1beta1
          kind: Deployment
          metadata:
            name: use-secret-env-deployment
          spec:
            replicas: 2
            template:
              metadata:
                labels:
                  app: use-secret-env-pod
              spec:
                containers:
                  - name: use-secret-env-container1
                    image: hub.atguigu.com/library/myapp:v1
                    imagePullPolicy: IfNotPresent
                    ports:
                    - containerPort: 80
                    env:
                    - name: TEST_USER
                      valueFrom:
                      secretKeyRef:
                        name: mysecret
                        key: username
                    - name: TEST_PASSWORD
                      valueFrom:
                      secretKeyRef:
                        name: mysecret
                        key: password

          

    3. kubernetes.io/dockerconfigjson:用来存储私有的docker registry的认证信息。

      a. 使用kubectl创建docker registry认证的secret

        kubectl create docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL

      b. 在创建pod的时候,通过imagePullSecrets来引用刚创建的`myregistrykey`

        apiVersion: v1
        kind: Pod
        metadata:
          name: foo
        spec:
          containers:
            - name: foo-container
              image: hub.atguigu.com/library/myapp:v1
          imagePullSecrets:
            - name: myregistrykey

三、volume

  A、容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先当容器崩溃时,kubelet会重启它,但是容器中的文件将丢失--容器以干净状态(镜像最初状态)重新启动。其次,在Pod中同时运行多个容器,这些容器之间通常需要共享文件。kubernetes中的volume抽象就很好的解决了这些问题

  B、 kubernetes中的卷有明确的寿命--与封装它的pod相同。所以,卷的生命比pod中所有的容器都长,当这个容器重启时,数据仍然得到保存。当然,当pod不再存在时,卷也将不复存在。也许更重要的是,kubernetes支持多种类型的卷,pod可以同时使用任意数量的卷。

  C、卷的类型:

    1. awsElasticBlockStore、azureDisk、azureFile、cephfs、csi、downwardAPI、emptyDir

    2. fc、flocker、gcePersistentDisk、gitRepo、glusterfs、hostpath、iscsi、local、nfs

    3. persistentVolumeClaim、projected、portworxVolume、quobyte、rbd、scaleIO、secret

    4. storageos、vsphereVolume

  D、emptyDir类型

    1. 当Pod被分配给节点时,首先创建emptyDir卷,并且只要该pod在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod中的容器可以读取写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当处于任何原因从节点中删除pod时,emptyDir中的数据将被永久删除。

      注意:容器崩溃不会从节点中移除pod,因此emptyDir卷中的数据在容器崩溃时是安全的

    2. emptyDir用法

      a. 暂存空间,例如用于基于磁盘的合并排列

      b. 用作长时间计算崩溃恢复的检查点

      c. web服务器容器提供数据时,保存内容管理器容器提取的文件

    3. 例子

      apiVersion: v1
      kind: Pod
      metadata:
        name: empty-dir-pod
      spec:
        volumes:
          - name: cache-volume
            emptyDir: {}
      containers:
        - name: empty-dir-container
          image: hub.atguigu.com/library/myapp:v1
          imagePullPolicy: IfNotPresent
          volumeMounts:
          - mountPath: /cache
            name: cache-volume
        - name: emyty-dir-busybox-container
          image: busybox
          imagePullPolicy: IfNotPresent
          command: ["/bin/sh","-c","sleep 6000s"]
          volumeMounts:
          - mountPath: /test
            name: cache-volume

  E、hostPath

    1.  hostPath卷将主机节点的文件系统中的文件或目录挂载到集群中

    2. hostPath的用途如下:

      a. 运行需要访问docker内部的容器;使用/var/lib/docker的hostPath

      b. 在容器中运行cAdvisor;使用/dev/cgroups的hostPath

    3. 除了所需的path属性之外,用户还可以为hostpath卷指定type

      a. 空:空字符串(默认)用于向后兼容,这意味着在挂载hostPath卷之前不会有任何检查

      b. DirectoryOrCreate: 如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置成0755,与kubelet具有相同的组和所有权。

      c. Directory:给定的路径下必须存在目录

      d. FileOrCreate:如果在给定的路径下没有任何东西存在,那么会根据需要创建一个空文件,权限设置成0644,与kubelet具有相同的组和所有权

      e. File:给定的路径下必须存在文件

      f.  Socket:给定的路径下必须存在UNIX套接字

      g. CharDevice:给定的路径下必须存在字符设备

      h. BlockDevice:给定的路径下必须存在块设备

    4. 注意:

      a. 由于每个节点的文件都不同,具有相同配置(例如从podTemplate创建)的pod在不同节点的行为可能不同

      b. 当kubernetes按照计划添加资源感知调度时,将无法考虑hostPath使用的资源

      c. 在底层主机上创建的文件或目录只能由root写入。您需要在特权容器中以root身份运行进程,或修改主机上的文件权限以便写入hostPath卷。

    5. 例子

      apiVersion: v1
      kind: Pod
      metadata:
        name: hostpath-pod
      spec:
        volumes:
          - name: hostpath-volume
            hostPath:
            path: /data
            type: Directory
        containers:
          - name: hostpath-container
            image: wangyanglinux/myapp:v2
            volumeMounts:
            - mountPath: /test-pod
              name: hostpath-volume

  F、PV、PVC

    1. PV(persistentVolume)

      a. 是由管理员设置的存储,它是集群的一部分。就像节点是集群中的资源一样,PV也是集群中的资源。PV是Volume之类卷插件但具有独立于使用PV的pod的生命周期。此API对象包含存储实现的细节,即NFS、iSCSI或特定云供应商的存储系统。

    2. PVC(persistentVolumeClaim)

      a. 是用户存储的请求。它与pod类似。Pod消耗节点资源,PVC消耗PV资源。Pod可以请求特定级别的资源(CPU和内存)。声明可以请求特定大小和访问模式(例如,可以读/写一次或只读多次模式挂载)

    3. 静态pv

      a. 集群管理员创建一些PV。它们带有可供集群用户使用的实际存储的细节。它们存在于Kubernetes API中,可用于消费

    4. 动态pv

      a. 当管理员创建的静态pv都不匹配用户的PersistentVolumeClaim时,集群可能会尝试动态地为PVC创建卷。此配置基于StorageClasses: PVC必须请求(存储类),并且管理员必须创建并配置该类才可以进行动态创建。声明该类为“”可以有效地禁用其动态配置。

        要启用基于存储级别的动态存储配置,集群管理员只需要启用API Server上的DefaultStorageClass[准入控制器]。例如,通过确保DefaultStorageClass位于API Server组件的--admission-control标志,使用逗号分隔的有序值列表中,可以完成操作。

    5. 绑定

      a. master中的控制环路监视新的PVC,寻找匹配的PV(如果可能)并将它们绑定在一起。如果为新的PVC动态调配PV,则该环路将始终将该PV绑定到PVC。否则,用户总会得到它们所请求的存储,但可能容量超出要求的数量。一旦PV和PVC绑定后,PersistentVolumeClaim绑定是排他性地,不管它们是如何绑定的,PVC和PV绑定是一对一的映射。

    6. 持久化声明(PVC)的保护

      a. PVC保护的目的是确保由pod正在使用的PVC不会从系统中移除,因为如果被移除的话可能会导致数据丢失。

        1)注意:当pod为pending并且pod已经分配给节点或pod为running状态时,PVC处于活动状态

      b. 当启用PVC保护alpha功能时,如果用户删除了一个pod正在使用的pvc,则该pvc不会立即被删除。pvc的删除将被推迟,知道pvc不再被任何pod所使用。

    7. 持久化卷(PV)类型

      a. GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC(Fiber Channel)

      b. FlexVolume Flocker NFS iSCSI CBD(Ceph Block Device) CephFS

      c. Cinder(OpenStack block storage) Glusterfs VsphereVolume Quobyte Volumes

      d. HostPath VMware Photon Portworx Volumes ScaleIO Volumes StorageOS

    8. 例子

      apiVersion: v1

      kind: PersistentVolume

      metadata:

        name: pv0003

      spec:

        capacity:

          storage: 5Gi

        volumeMode: Filesystem

        accessModes:

          - ReadWriteOnce

        persistentVolumeReclaimPolicy: Recycle

        storageClassName: slow

        mountOptions:

          - hard

          - nfserves=4.1

        nfs:

          path: /tmp

          server: 172.17.0.2

    9. PV的访问模式

      a. PersistentVolume可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV的访问模式都将被设置为该卷支持的特定模式。例如,NFS可以支持多个读/写客户端,但特定的NFS PV可能以只读方式导入到服务器上。每个PV都有一套自己的用来描述特定功能的访问模式。

        1) ReadWriteOnce(RWO)---------该卷可以被单个节点以读/写模式挂载

        2) ReadWriteMany(RWX)----------该卷可以被多个节点以读/写模式挂载

        2) ReadOnlyMany(ROX)-----------该卷可以被多个节点以只读模式挂载

      b. 注意:一个卷一次只能使用一种访问模式挂载,即使它支持多种访问模式。

      c. 各volume插件支持模式

      

    10. 回收策略

      a. Retain(保留)---------手动回收

      b. Recycle(回收)-------基本擦除(rm -rf /thevolume/*)(新版本废除)

      c. Delete(删除) ---------关联的资产将被删除

      注意:当前只有NFS、HostPath支持回收策略。AWS EBS、GCE PD、Azure Disk、Cinder卷支持删除策略。

    11. 状态

      a. Available(可用)------一块空闲资源还没有被任何声明绑定

      b. Bound(已绑定)-------卷已经被声明绑定

      c. Released(已释放)----声明被删除,但是资源还未被集群重新声明  

      d. Failed(失败)--------该卷自动回收失败

    12. 实验

      a. 文件节点(此处是harbor节点)安装nfs服务

        1) yum -y install nfs-common nfs-utils rpcbind

        2)  mkdir /nfs

        3) chmod 777 /nfs/

        4) chown nfsnobody /nfs/

        5) vim /etc/exports

          /nfs  *(rw,no_root_squash,no_all_squash,sync)

        6) systemctl start rpcbind

        7) systemctl start nfs

      b. 其它节点安装nfs客户端

        1) yum -y install nfs-utils rpcbind

      c. 测试其它节点挂载

        1) mkdir /test

        2) showmount -e 192.168.66.40

        3) mount -t nfs 192.168.66.40:/nfs /test/

        4) cd /test && vim 1.html

        5) umount /test/

        6) rm -rf /test/

      d. 部署PV

        apiVersion: v1
        kind: PersistentVolume
        metadata:
          name: nfspv1
        spec:
          capacity:
            storage: 10Gi
          accessModes:
            - ReadWriteOnce
          persistentVolumeReclaimPolicy: Retain
          storageClassName: nfs
          nfs:
            path: /nfs
            server: 192.168.66.40

      e. 创建服务并使用pvc

        apiVersion: v1
        kind: Service
        metadata:
          name: nginx
          labels:
            app: nginx
        spec:
          ports:
            - port: 80
              name: web
          clusterIP: None
          selector:
            app: nginx
        ---
        apiVersion: apps/v1
        kind: StatefulSet
        metadata:
        name: web
        spec:
          selector:
            matchLabels:
              app: nginx
          serviceName: "nginx"
          replicas: 3
          template:
            metadata:
              labels:
                app: nginx
            spec:
              containers:
                - name: nginx
                  image: hub.atguigu.com/library/myapp:v1
                  imagePullPolicy: IfNotPresent
                  ports:
                  - containerPort: 80
                    name: web
                  volumeMounts:
                  - name: www
                    mountPath: /usr/share/nginx/html
              volumeClaimTemplates:
                - metadata:
                  name: www
                  spec:
                  accessModes: ["ReadWriteOnce"]
                  storageClassName: "nfs"
                  resources:
                    requests:
                      storage: 1Gi

      e. 关于statefulSet

        1) 匹配Pod Name(网络标识)的模式为:(statefulset名称)-(序号),比如上面示例web-0、web-1、web-2

        2) statefulSet为每个pod副本创建了一个DNS域名,这个域名格式为:$(podname).(headless server name),也就意味着服务间是通过pod域名来通信而非pod ip,因为当pod所在的node发生故障后,pod会飘到其它Node上,pod ip会发生变化,但是pod域名不会

        3) statefulSet使用headless server来控制pod的域名,这个域名的FQDN为:(servicename).(namespace).svc.cluster.local,其中cluster.local指集群的域名。

        4)根据volumeClaimTemplates,为每个pod创建一个pvc,pvc的命名规则匹配模式:(volumeClaimTemplates.name)-(pod_name),比如上面的volumeMounts.name=www,Pod.name=web-[0-2],因此创建出来的PVC是www.web-0,www.web-1,www.web-2

        5) 删除pod不会删除其pvc,手动删除pvc将释放pv

      f. statefulSet的启停顺序

        1) 有序部署

        2)有序删除

        3)有序扩展

      g. statefulSet使用场景

        1) 稳定的持久化存储,即pod重新调度后还是能访问到相同的持久化数据,基于pvc实现。

        2)稳定的网络标识,即pod重新调度后PodName和HostName不变

        3)有序部署,有序扩展,基于init containers来实现

        4)有序收缩

      6. 释放statefulSet资源,pv资源

        1)kubectl delete -f xxx.yaml

        2) kubectl delete pvc xxx

        3) kubectl edit pv xxx

          删除包括spec.claimRef及以下所有配置

        

        

原文地址:https://www.cnblogs.com/DjanFey/p/11933692.html