• k8s集群安装学习笔记五——存储部分


    简介:

    Kubernetes - 存储部分
    ConfigMap 的创建
    Pod 中使用 ConfigMap
    通过数据卷插件使用ConfigMap
    Secret
    Kubernetes-volume
    hostPath:主机节点的文件系统中的文件或目录挂载到(容器)集群中
    PersistentVolume (PV)
    PersistentVolumeClaim (PVC)

    Kubernetes - 存储部分

    configMap 描述信息
    ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配
    置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也
    可以用来保存整个配置文件或者 JSON 二进制大对象
     
    ConfigMap 的创建
    Ⅰ、使用目录创建
    $ ls docs/user-guide/configmap/kubectl/ 
    game.properties 
    ui.properties 
    
    $ cat docs/user-guide/configmap/kubectl/game.properties 
    enemies=aliens lives=3 enemies.cheat=true enemies.cheat.level=noGoodRotten secret.code.passphrase=UUDDLRLRBABAS secret.code.allowed=true secret.code.lives=30 $ cat docs/user-guide/configmap/kubectl/ui.properties color.good=purple color.bad=yellow allow.textmode=true how.nice.to.look=fairlyNice $ kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl 
    --from-file 指定在目录下的所有文件都会被用在 ConfigMap 里面创建一个键值对,键的名字就是文件名,值就是文件的内容。


    查看创建信息
    kubectl get cm
    
    
    kubectl get cm game-config -o yaml
    Ⅱ、使用文件创建
    只要指定为一个文件就可以从单个文件中创建 ConfigMap
    $ kubectl create configmap game-config-2 --from-file=docs/user-guide/configmap/kubectl/game.properties 
    $ kubectl get configmaps game-config-2 -o yaml
    --from-file 这个参数可以使用多次,你可以使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的。

     

     
    Ⅲ、使用字面值创建
    使用文字值创建,利用--from-literal 参数传递配置信息,该参数可以使用多次,格式如下:
    $ kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm 
    $ kubectl get configmaps special-config -o yaml

    Pod 中使用 ConfigMap
     
    Ⅰ、使用 ConfigMap 来替代环境变量
    $ mkdir env
    $ cd env
    $ vim env.yaml
    apiVersion: v1 
    kind: ConfigMap 
    metadata: 
      name: special-config #configmap名称
      namespace: default 
    data: #值
      special.how: very   #key
      special.type: charm  #value

    ---
    apiVersion: v1 
    kind: ConfigMap 
    metadata: 
      name: env-config 
      namespace: default 
    data: 
      log_level: INFO
    kubectl apply -f env.yaml

    将上面的环境变量注入到pod中

    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  #cm名称
                key: special.how  #导入的key名,将这个key的值赋给上面的SPECIAL_LEVEL_KEY
          - name: SPECIAL_TYPE_KEY 
            valueFrom: 
              configMapKeyRef: 
                name: special-config 
                key: special.type  #导入的key名,将这个key的值赋给上面的SPECIAL_TYPE_KEY
        envFrom:  #导入上面env-config的环境变量
          - configMapRef: 
            name: env-config 
    restartPolicy: Never

    创建pod

    查看运行结果(日志)

    kubectl log dapi-test-pod

     可以看到3个环境变量已修改

    Ⅱ、用 ConfigMap 设置命令行参数
    apiVersion: v1 
    kind: ConfigMap 
    metadata: 
      name: special-config 
      namespace: default 
    data: 
      special.how: very 
      special.type: charm
    $ vim pod1.yaml
    apiVersion: v1 kind: Pod metadata: name: dapi
    -test-pod66 spec: containers: - name: test-container image: hub.atguigu.com/library/myapp:v1 command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ] 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 restartPolicy: Never

    $ kubectl create -f pod1.yaml

     

    查看日志

    Ⅲ、通过数据卷插件使用ConfigMap
    apiVersion: v1 
    kind: ConfigMap 
    metadata: 
      name: special-config 
      namespace: default 
    data: 
      special.how: very 
      special.type: charm
    在数据卷里面使用这个 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", "cat /etc/config/special.how" ]  #键就是文件名,键值就是文件内容
          volumeMounts: 
          - name: config-volume  #挂载下面的vm
            mountPath: /etc/config  #挂载路径,会将下面vm中cm的key值挂载为文件名,键值就会成为文件内容
      volumes: 
        - name: config-volume  #vm名称
          configMap:  #cm名称
            name: special-config 
      restartPolicy: Never
    ConfigMap 的热更新--数据卷的方式(演示)
    $ vim 111.yaml
    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 #把log-config挂载到这个目录中 volumes: - name: config-volume configMap: name: log-config
    $ kubectl exec pod名称 -it -- cat /etc/config/log_level 
    INFO

     

    热更新: 
    修改 ConfigMap
    $ kubectl edit configmap log-config
     
    修改 log_level 的值为 DEBUG 等待大概 10 秒钟时间,再次查看环境变量的值
    $ kubectl exec pod名称 -it -- cat /etc/config/log_level
    DEBUG
    $ kubectl exec `kubectl get pods -l run=my-nginx -o=name|cut -d "/" -f2` cat /tmp/log_level 
    DEBUG
     

     

     可以看出:只要修改configmap文件,pod里面文件内容就会自动更新键值

     特别注意:configMap如果以ENV的方式挂载至容器,修改configMap并不会实现热更新!!!
     
     
    ConfigMap 更新后滚动更新 Pod
    更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新
    $ kubectl patch deployment my-nginx --patch '{"spec": {"template": {"metadata": {"annotations": {"version/config": "20190411" }}}}}'
    这个例子里我们在 .spec.template.metadata.annotations 中添加 version/config ,每次通过修改version/config 来触发滚动更新。
     
    !!! 更新 ConfigMap 后:
     使用该 ConfigMap 挂载的 Env 不会同步更新
     使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新
     
     

    Secret

    Secret 存在意义
    Secret 解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec中。
    Secret 可以以 Volume 或者环境变量的方式使用。
     
    Secret 有三种类型:
    1.Service Account :用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod 的/run/secrets/kubernetes.io/serviceaccount 目录中。
    2.Opaque :base64编码格式的Secret,用来存储密码、密钥等。
    3.kubernetes.io/dockerconfifigjson :用来存储私有 docker registry 的认证信息。
     
     
    Service Account(不怎么常用)
    Service Account 用来访问 Kubernetes API,由 Kubernetes 自动创建,并且会自动挂载到 Pod的/run/secrets/kubernetes.io/serviceaccount 目录中。
     
    $ kubectl run nginx --image nginx 
    deployment "nginx" created $ kubectl get pods NAME READY STATUS RESTARTS AGE nginx-3137573019-md1u2 1/1 Running 0 13s $ kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount ca.crt namespace token
    Opaque Secret(常用)
    Ⅰ、创建说明
    Opaque 类型的数据是一个 map 类型,要求 value 是 base64 编码格式:
    先加密
    $ echo -n "admin" | base64 
    YWRtaW4= 
    $ echo -n "1f2d1e2e67df" | base64 
    MWYyZDFlMmU2N2Rm
    再保存到secrets.yml
    apiVersion: v1 
    kind: Secret 
    metadata: 
      name: mysecret 
    type: Opaque 
    data: 
      password: MWYyZDFlMmU2N2Rm 
      username: YWRtaW4=

    $ kubectl apply -f secrets.yaml

     解密特别简单

    echo -n "YWRtaW4=" |base64 -d
    Ⅱ、使用方式
    1、将 Secret 挂载到 Volume 中(方式一)
    apiVersion: v1 
    kind: Pod 
    metadata: 
      labels: 
        name: seret-test 
      name: seret-test 
    spec: 
      volumes: # 创建卷
      - name: secrets  #卷名
        secret: 
          secretName: mysecret  #上面创建的secret名
      containers: 
      - image: hub.atguigu.com/library/myapp:v1 
        name: db 
        volumeMounts: 
        - name: secrets  #挂载上面声明的secrets卷名
          mountPath: "/etc/secrets"  #挂载路径 
          readOnly: true
     

    注意:虽然保存的时候是加密的,但是它在使用时会自动解密,上面/etc/secrets目录下的就是解密后文件

    2、将 Secret 导出到环境变量中(方式二)
    apiVersion: extensions/v1beta1 
    kind: Deployment 
    metadata: 
      name: pod-deployment 
    spec: 
      replicas: 2 
      template: 
        metadata: 
          labels: 
            app: pod-deployment 
        spec: 
          containers: 
          - name: pod-1 
            image: hub.atguigu.com/library/myapp:v1 
            ports:
            - containerPort: 80 
            env: 
            - name: TEST_USER 
              valueFrom: 
                secretKeyRef: 
                  name: mysecret 
                  key: username  #会将这个username的值赋给上面的TEST_USER
            - name: TEST_PASSWORD 
              valueFrom: 
                secretKeyRef: 
                  name: mysecret 
                  key: password  #会将这个password的值赋给上面的TEST_PASSWORD

    kubernetes.io/dockerconfigjson(例:harbor私有仓库)

    准备实验镜像,推送到私有仓库(直接推送失败,需要登录)

    登录后推送镜像(成功)

     

     好了,镜像准备完成

    开始实验

    退出harbor登录

    没认证前--测试拉取私有仓库镜像(拉取失败)

    使用 Kuberctl 创建 docker registry 认证的 secret  

    ##创建类型:docker-registry 名称:myregistrykey
    $ kubectl create secret docker-registry myregistrykey
    --docker-server=DOCKER_REGISTRY_SERVER #docker私有仓库地址即harbor仓库地址
    --docker-username=DOCKER_USER #用户名
    --docker-password=DOCKER_PASSWORD #密码
    --docker-email=DOCKER_EMAIL #邮箱

    secret "myregistrykey" created.
    在创建 Pod 的时候,通过 imagePullSecrets 来引用刚创建的 `myregistrykey`
    $ vim pod.yaml
    apiVersion: v1 kind: Pod metadata: name: foo spec: containers:
    - name: foo image: hub.atguigu.com/test/myapp:v2 #私有仓库镜像 imagePullSecrets: #认证 - name: myregistrykey

     

    pod状态是Running说明pod镜像下载成功! 

    Kubernetes-volume

    容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。
    首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。
    其次,在Pod 中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的Volume 抽象就很好的解决了这些问题。
     
    背景
    Kubernetes 中的卷有明确的寿命 -- 与封装它的 Pod 相同。所以,卷的生命比 Pod 中的所有容器都长,
    当这个容器重启时数据仍然得以保存。当然,当 Pod 不再存在时,卷也将不复存在。也许更重要的是,
    Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷。
     
    卷的类型
    Kubernetes 支持以下类型的卷:
     awsElasticBlockStore azureDisk azureFile cephfs csi downwardAPI emptyDir
     fc flocker gcePersistentDisk gitRepo glusterfs hostPath iscsi local nfs
     persistentVolumeClaim projected portworxVolume quobyte rbd scaleIO secret
     storageos vsphereVolume
     
    emptyDir
    当 Pod 被分配给节点时,首先创建emptyDir卷,并且只要该 Pod 在该节点上运行,该卷就会存在。
    正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入 emptyDir 卷中的相同文件,
    尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir 中的数据将被永久删除。
     
    注意:容器崩溃不会从节点移除pod,因此‘emptyDir’中的数据在容器崩溃时是安全的。
     
     
    emptyDir 的用法有:
    1.暂存空间,例如用于基于磁盘的合并排序
    2.用作长时间计算崩溃恢复时的检查点
    3.Web服务器容器提供数据时,保存内容管理器容器提取的文件
     
    $ vim em.yaml
    apiVersion: v1 kind: Pod metadata: name: test
    -pd1 spec: containers: - image: wangyanglinux/myapp:v2 name: test-container volumeMounts: - mountPath: /cache #挂载目录,将下面的卷挂载到本容器此目录下 name: cache-volume #挂载的卷名
    - name: liveness-exec-cntainer #第二个容器 image: busybx imagePullPolicy:IfNotPresent command: ["/bin/sh","-c","sleep 6000s"] volumeMounts: - mountPath: /test #挂载目录,将下面的卷挂载到本容器此目录下 name: cache-volume #挂载的卷名 volumes: - name: cache-volume emptyDir: {} #空卷

    $ kubectl create -f em.yaml

    进入第一个容器挂载目录并编辑

    进入第二个容器挂载目录并编辑

    回到第一个容器查看

    可得出结论:两个容器不同路径挂载目录也是可以共享一个卷目录的。

    hostPath

    hostPath卷将主机节点的文件系统中的文件或目录挂载到(容器)集群中。
     
    hostPath的用途如下:
    1.运行需要访问 Docker 内部的容器;使用 /var/lib/docker 的 hostPath
    2.在容器中运行 cAdvisor;使用 /dev/cgroups 的 hostPath
    3.允许 pod 指定给定的 hostPath 是否应该在 pod 运行之前存在,是否应该创建,以及它应该以什么形式存在。
     
    除了所需的path 属性之外,用户还可以为 hostPath 卷指定 type。
     
    使用这种卷类型时请注意,因为:
    1.由于每个节点上的文件都不同,具有相同配置(例如从 podTemplate 创建的)的 pod 在不同节点上的行为可能会有所不同。
    2.当 Kubernetes 按照计划添加资源感知调度时,将无法考虑 hostPath 使用的资源。
    3.在底层主机上创建的文件或目录只能由 root 写入。您需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限以便写入 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: 
          # 主机上的目录
          path: /data 
          # this field is optional 
          type: Directory  #给定的路径下必须存在目录,否则报错

     在本机创建目录 /data

    进入挂载容器并编辑

    在本地data目录查看并编辑

    再进入容器查看

     

    可以看到本地目录文件和容器挂载卷实现了资源共享

     Kubernetes-PersistentVolume

    PersistentVolume(PV)
    是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。
    PV 是Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统。
     
    PersistentVolumeClaim (PVC)
    是用户存储的请求。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。
    声明可以请求特定的大小和访问模式(例如,可以以读/写一次或 只读多次模式挂载)。
     
    静态 pv
    集群管理员创建一些 PV。它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API 中,可用于消费。
     
    动态
    当管理员创建的静态 PV 都不匹配用户的PersistentVolumeClaim时,集群可能会尝试动态地为 PVC 创建卷。
    此配置基于 StorageClasses :PVC 必须请求 [存储类],并且管理员必须创建并配置该类才能进行动态创建。
    声明该类为 "" 可以有效地禁用其动态配置要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的 DefaultStorageClass [准入控制器]。
    例如,通过确保 DefaultStorageClass位于 API server 组件的 --admission-control 标志,使用逗号分隔的有序值列表中,可以完成此操作。
     
    绑定
    master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态调配 PV,则该环路将始终将该 PV 绑定到 PVC。
    否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦 PV 和 PVC 绑定后, PersistentVolumeClaim绑定是排他性的,不管它们是如何绑定的。
    PVC 跟PV 绑定是一对一的映射
     
    持久化卷声明的保护
    PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失。
    当启用PVC 保护 alpha 功能时,如果用户删除了一个 pod 正在使用的 PVC,则该 PVC 不会被立即删除。
    PVC 的删除将被推迟,直到 PVC 不再被任何 pod 使用。
     
     
    持久化卷类型
    PersistentVolume 类型以插件形式实现。Kubernetes 目前支持以下插件类型:
    1.GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC (Fibre Channel)
    2.FlexVolume Flocker NFS iSCSI RBD (Ceph Block Device) CephFS
    3.Cinder (OpenStack block storage) Glusterfs VsphereVolume Quobyte Volumes
    4.HostPath VMware Photon Portworx Volumes ScaleIO Volumes StorageOS
     
    持久卷演示代码:(封装一个PV的示例方案)
    apiVersion: v1 
    kind: PersistentVolume 
    metadata: 
      name: pv0003 
    spec: 
      capacity: 
        storage: 5Gi 存储大小
      volumeMode: Filesystem  #文件类型
      accessModes:  #访问策略
        - ReadWriteOnce  #只能同时一个人读写
      persistentVolumeReclaimPolicy: Recycle #回收策略
      storageClassName: slow  #存储类的名称,划分存储类的非常重要的一个指标
      mountOptions: 
        - hard 
        - nfsvers=4.1 
      nfs:
        path: /tmp #挂载目录
        server: 172.17.0.2   #挂载服务器IP
    PV 访问模式
    PersistentVolume 可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV 的访问模式都将被设置为该卷支持的特定模式。
    例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能以只读方式导出到服务器上。每个 PV 都有一套自己的用来描述特定功能的访问模式。
     ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
     ReadOnlyMany——该卷可以被多个节点以只读模式挂载
     ReadWriteMany——该卷可以被多个节点以读/写模式挂载
    在命令行中,访问模式缩写为:
     RWO - ReadWriteOnce
     ROX - ReadOnlyMany
     RWX - ReadWriteMany

    回收策略

      Retain(保留)——手动回收
      Recycle(回收)——基本擦除( rm -rf /thevolume/* )
      Delete(删除)——关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷)将被删除。
     当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略。
     
    状态
    卷可以处于以下的某种状态:
      Available(可用)——一块空闲资源还没有被任何声明绑定
      Bound(已绑定)——卷已经被声明绑定
      Released(已释放)——声明被删除,但是资源还未被集群重新声明
      Failed(失败)——该卷的自动回收失败
    命令行会显示绑定到 PV 的 PVC 的名称
     
     

    持久化演示实验 - NFS

    Ⅰ、安装 NFS 服务器
    yum install -y nfs-common nfs-utils rpcbind 
    mkdir /nfs 
    mkdir /nfs{1..3}
    chmod 666 /nfs* chown nfsnobody /nfs* cat /etc/exports /nfs *(rw,no_root_squash,no_all_squash,sync) /nfs1 *(rw,no_root_squash,no_all_squash,sync) /nfs2 *(rw,no_root_squash,no_all_squash,sync) /nfs3 *(rw,no_root_squash,no_all_squash,sync) systemctl start rpcbind systemctl start nfs

     其他节点安装nfs客户端

    yum -y install nfs-utils rpcbind
    mkdir /test
    #测试挂载服务端nfs共享目录
    mount -t nfs 192.168.66.100:/nfs /test
    cd /test
    vim 111.txt
    #测试完后卸载
    umount /test
    rm -rf /test

    #上面操作是为了测试nfs能否正常使用
    Ⅱ、部署 PV
    $ vim pv.yaml (部署多个pv,可以看出pv和pvc之间的关系)
    
    apiVersion: v1 
    kind: PersistentVolume 
    metadata: 
      name: nfspv1 
    spec: 
      capacity: 
        storage: 10Gi 
      accessModes: 
        - ReadWriteOnce 
      persistentVolumeReclaimPolicy: Retain #回收策略 
      storageClassName: nfs 
      nfs:
        path: /nfs
        server: 192.168.66.100
    
    ---
    apiVersion: v1 
    kind: PersistentVolume 
    metadata: 
      name: nfspv2 
    spec: 
      capacity: 
        storage: 5Gi 
      accessModes: 
        - ReadOnlyMany 
      persistentVolumeReclaimPolicy: Retain #回收策略 
      storageClassName: nfs 
      nfs:
        path: /nfs1
        server: 192.168.66.100
    
    ---
    apiVersion: v1 
    kind: PersistentVolume 
    metadata: 
      name: nfspv3 
    spec: 
      capacity: 
        storage: 5Gi 
      accessModes: 
        - ReadWriteMany 
      persistentVolumeReclaimPolicy: Retain #回收策略 
      storageClassName: slow
      nfs:
        path: /nfs2
        server: 192.168.66.100
    
    ---
    apiVersion: v1 
    kind: PersistentVolume 
    metadata: 
      name: nfspv4 
    spec: 
      capacity: 
        storage: 1Gi 
      accessModes: 
        - ReadOnlyMany 
      persistentVolumeReclaimPolicy: Retain #回收策略 
      storageClassName: nfs 
      nfs:
        path: /nfs3
        server: 192.168.66.100
    
    $ kubectl create -f pv.yaml
    $ kubectl get pv

     

    Ⅲ、创建服务并使用 PVC(正常情况下PV都是通过PVC调用使用的)
    $ vim pod.yaml

    apiVersion: v1 kind: Service #svc metadata: name: nginx labels: app: nginx spec: ports:
    - port: 80 name: web clusterIP: None #svc无头服务,不需要链接到对应的IP/端口 selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet #注意:如果要建立一个StatefulSet控制器的话,必须先建立一个无头服务,StatefulSet的svc一定是无头服务才行 metadata: name: web spec: selector: matchLabels: #匹配标签,当app=nginx时匹配 app: nginx serviceName: "nginx" #指定上面的svc无头服务名称 replicas: 3 template: metadata: labels: #标签信息 app: nginx #app=nginx (key=value) spec: containers: - name: nginx image: k8s.gcr.io/nginx-slim:0.8 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 #卷大小满足条件

    $ kubectl create -f pod.yaml

     

    PVC挂载条件1.访问模式为:ReadWriteOnce   2.存储对象名为:nfs  3.卷大小>=1GB,如果前两个匹配,优先选择满足条件容量小的匹配

    重新修改PV

    删除旧的PV

    kubectl delete pv nfspv3
    kubectl delete pv nfspv4
    apiVersion: v1 
    kind: PersistentVolume 
    metadata: 
      name: nfspv3 
    spec: 
      capacity: 
        storage: 5Gi 
      accessModes: 
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Retain #回收策略 
      storageClassName: nfs
      nfs:
        path: /nfs2
        server: 192.168.66.100
    
    ---
    apiVersion: v1 
    kind: PersistentVolume 
    metadata: 
      name: nfspv4 
    spec: 
      capacity: 
        storage: 50Gi 
      accessModes: 
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Retain #回收策略 
      storageClassName: nfs 
      nfs:
        path: /nfs3
        server: 192.168.66.100

      

     

     

    可以看到都完成了绑定,每个pod都有一个请求模板,会创建一个PVC,PVC会去跟PV进行匹配,匹配成功后就会与之绑定

     测试一:

    查看第一个PVC绑定的PV详细信息

    kubectl describe pv nfspv1

    进入相应的nfs服务器(192.168.66.100)

    cd /nfs
    vim index.html
    aaaaaaaa
    chmod 777 index.html

    进入其他节点服务器

     测试二:

    查看第二个PVC绑定的PV详细信息

    kubectl describe pv nfspv3

     进入相应的nfs服务器(192.168.66.100)

    cd /nfs2
    vim index.html
    bbbbbbbbbbbbbbbbb
    chmod 777 index.html

    进入其他节点服务器访问

    第三个同理略 ,可以发现三个都完成了绑定关系,且数据一致了

    测试删除pod后,数据的持久化

    删除pod(可以看到重新生成了一个同名pod,且IP地址也变了(但是访问名称一致不会变))

    再次访问查看数据(数据一致,数据不会丢失,这就是StatefulSet的一些特性)

    关于 StatefulSet

      1.匹配 Pod name ( 网络标识 ) 的模式为:$(statefulset名称)-$(序号),比如上面的示例:web-0,web-1,web-2。
      2.StatefulSet 为每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为: $(podname).(headless servername),------>pod_name.svc_name
        也就意味着服务间是通过Pod域名来通信而非 Pod IP,因为当Pod所在Node发生故障时, Pod 会被飘移到其它 Node 上,Pod IP 会发生变化,但是 Pod 域名不会有变化。(通过FQDN调用而非IP)
      3.StatefulSet 使用 Headless 服务来控制 Pod 的域名,这个域名的 FQDN 为:$(service name).$(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。
     
    Statefulset的启停顺序:
      1.有序部署:部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。
      2.有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。
      3.有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。
     
    StatefulSet使用场景:
      1.稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现。
      2.稳定的网络标识符,即 Pod 重新调度后其 PodName 和 HostName 不变。
      3.有序部署,有序扩展,基于 init containers 来实现。
      4.有序收缩。
     

    StatefulSet、pod、pvc、pv和nfs之间的关系概述

    StatefulSet控制器里面有pvc的模板,会创建相应的pvc和pod,pvc会与pod相关联,然后与pv进行匹配,使pod与pv绑定,而pv又和nfs之间进行挂载实现数据持久化。
    pvc简单来说:就是pod和pv进行匹配的一些准则。
     大概关系图如下:
    好记性不如烂笔头,最难不过坚持
  • 相关阅读:
    基于AngularJS的前端云组件最佳实践
    光裁员有什么用,商业变现才是王道
    迄今为止最完整的推送说明书
    个推技术实现原理介绍
    安卓推送——个推服务端api使用误区
    Gerrit代码Review入门实战
    iOS AFNetworking HTTPS 认证
    iOS开发零碎知识点
    Xcode 如何删除过期的Provisioning Profile文件
    一个section刷新 一个cell刷新
  • 原文地址:https://www.cnblogs.com/dannylinux/p/15304895.html
Copyright © 2020-2023  润新知