第五课:尚硅谷K8s学习-存储机制

tags:

  • golang
  • 2019尚硅谷

categories:

  • K8s
  • configMap
  • Secret
  • volume
  • PV
  • PVC

第一节 存储机制-configMap

  1. k8s中的存储类型有以下四种
    • configMap: k8s中存储配置文件
    • Secret: 需要加密的信息比如:秘钥,用户密码
    • volume: 给Pod提供共享存储卷的能力
    • Persistent Volume(简称PV): 服务持久卷的构建

1.1 configMap介绍和创建

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

  2. ConfigMap 的创建方式

    • 使用目录创建
    • 使用文件创建
    • 使用字面值创建
  3. configMap使用目录创建

mkdir configmap
cd configmap
vim 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

vim ui.properties
# 测试配置如下
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice

# —from-file指定在目录下的所有文件都会被用在 ConfigMap里面创建一个键值对,键的名字就是文件名,值就是文件的内容
kubectl create configmap game-config --from-file=configmap

# 查看创建成功后的配置
kubectl get cm game-config
# 以yaml的格式输出
kubectl get cm game-config -o yaml
  1. configMap使用文件创建: 这里直接把上面文件夹变成指定的文件就可以。使用两次分别指定上个实例中的那两个配置文件,效果就跟指定整个目录是一样的(上面是文件夹下所有配置文件运行)

kubectl create configmap game-config-2 --from-file=/configmap/game.properties

  1. configMap使用字面值创建

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

1.2 Pod中configMap的使用

  1. 使用 ConfigMap 来替代环境变量。这里已经通过字面量创建方式创建完成。
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
  1. 配置文件env.yaml创建configMap。 kubectl apply -f env.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
  namespace: default
data:
  log_level: INFO
  1. 注入上面俩个configMap的变量到Pod中。pod-test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
  - name: test-container
    image: hub.qnhyn.com/library/myapp
    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
  1. 实验查看基本操作
# 查看configMap中详细信息
kubectl describe cm env-config 
# 创建测试pod-test
kubectl create -f pod-test.yaml
# 查看日志, 确认导入环境变量成功
kubectl logs dapi-test-pod

1.3 用ConfigMap设置命令行参数

  1. 使用 ConfigMap 来替代环境变量。这里已经通过字面量创建方式创建完成。
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
  1. pod-test2.yaml配置文件
apiVersion: v1
kind: Pod
metadata:
  name: pod-test2
spec:
  containers:
  - name: test-container
    image: hub.qnhyn.com/library/myapp
    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
  1. 实验查看基本操作
# 创建测试pod-test
kubectl create -f pod-test2.yaml
# 查看日志, 确认导入环境变量成功 输出结果为(very charm)
kubectl logs pod-test2

1.4 通过数据卷插件使用ConfigMap

  1. 使用 ConfigMap 来替代环境变量。这里已经通过字面量创建方式创建完成。
apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm
  1. 在数据卷里面使用这个 ConfigMap,有不同的选项。最基本的就是将文件填入数据卷,在这个文件中,键就是文件名,键值就是文件内容。
apiVersion: v1
kind: Pod
metadata:
  name: test-pod3
spec:
  containers:
  - name: test-container
    image: hub.qnhyn.com/library/myapp
    command: ["/bin/sh","-c","sleep 600s"]
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: special-config
  restartPolicy: Never
  1. 实验查看基本操作
# 创建测试ptest-pod3
kubectl create -f test-pod3.yaml
# 交互到test-pod3容器中 容器中有储存的配置
kubectl exec test-pod3 -it -- /bin/sh
cd /etc/config
cat special.how

1.5 ConfigMap 的热更新

  1. 建立configMap和pod。
apiVersion: v1
kind: ConfigMap
metadata:
  name: log-config
  namespace: default
data:
  log_level: INFO
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-deploy
  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      containers:
      - name: nginx-deployment
        image: hub.qnhyn.com/library/myapp
        env:
        - name: GET_HOSTS_FROM
          value: dns
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config-volume
          mountPath: /etc/config
      volumes:
      - name: config-volume
        configMap:
          name: log-config
  1. 实验查看基本操作
# 进入pod中容器查看configMap信息 
kubectl exec nginx-568bdc484c-vwzmv -it -- /bin/sh
cd /etc/config
# 热更新修改 ConfigMap
kubectl edit configmap log-config
# 修改log_level的值为DEBUG等待大概 10 秒钟时间,再次查看环境变量的值
kubectl exec nginx-568bdc484c-vwzmv -it cat /etc/config/log_level
  1. ConfigMap 更新后滚动更新 Pod
    • 更新 ConfigMap 目前并不会触发相关 Pod 的滚动更新,可以通过修改 pod annotations 的方式强制触发滚动更新

kubectl patch deployment my-nginx --patch’{“spec”: {“template”: {“metadata”: {“annotations”:{“version/config”: “20190411” }}}}}’

  1. 这个例子里我们在.spec.template.metadata.annotations中添加version/config,每次通过修该version/config来触发滚动更新
    • !!!更新 ConfigMap 后:
    • 使用该 ConfigMap 挂载的 Env 不会同步更新
    • 使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新

第二节 存储机制-Secret

2.1 secret的介绍

  1. Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 ssh key。敏感信息放在 secret 中比放在 Pod 的定义或者容器镜像中来说更加安全和灵活。
  2. Secret的类型:
    • Service Account:用来访问Kubernetes API, 由Kubernetes 自动创建。对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中
    • Opaque:base64编码格式的Secret,用来存储密码、密钥等。使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱
    • kubernetes.io/dockerconfigjson: 用于存储docker registry的认证信息。

2.2 Secret的类型-Service Account

  1. Service Account 创建时 Kubernetes 会默认创建对应的 secret。对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。
  2. 实验过程。这种实际应用中用的比较少。( 每个namespace下有一个名为default的默认的ServiceAccount对象 )
kubectl get sa
# 挑选一个可以访问Kubernetes API的pod,这里选kube-proxy-799ln
kubectl get pod -n kube-system
# 进去查看有三个文件 接口通过HTTPS双向认证
kubectl exec kube-proxy-799ln -n kube-system -it -- /bin/sh
cd  /run/secrets/kubernetes.io/serviceaccount

2.3 Secret的类型-Opaque

  1. Opaque类型的数据是一个map类型,要求value是base64编码格式:
  2. 它实际上是表面上加密,很容易破解。
# 加密
echo -n "admin" | base64
echo -n "123456" | base64
# 解密
echo -n "YWRtaW4=" | base64 -d
  1. 创建一个Opaque类型的Secret: kubectl create -f So.yaml

kubectl get secret

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MTIzNDU2
  1. 将Secret挂载到Volume中
apiVersion: v1 
kind: Pod 
metadata:
  labels:
    name: secret-test 
  name: secret-test 
spec:
  volumes:
  - name: secrets 
    secret:
      secretName: mysecret 
  containers:
  - image: hub.qnhyn.com/library/myapp 
    name: db 
    volumeMounts:
    - name: secrets 
      mountPath: "/etc/secrets"
      readOnly: true
kubectl create -f secret-test.yaml
kubectl exec secret-test -it -- /bin/sh
cd /etc/secrets
  1. 将Secret设置为环境变量
apiVersion: v1
kind: Pod
metadata:
  name: secret-env
spec:
  containers:
  - name: nginx
    image: hub.qnhyn.com/library/myapp
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password
kubectl get pod
# 查看环境变量
kubectl exec secret-env -- env

2.4 Secret的类型-kubernetes.io/dockerconfigjson

  1. harbor仓库中创建一个私有仓库并提镜像上去。对于私有仓库的拉取,需要登录认证否则无法成功拉取,登录认证信息存放在主机上(.docker/config.json)有安全隐患。
    • docker logout hub.qnhyn.com
    • 因为不是公有再次拉取报验证错误,docker pull hub.qnhyn.com/test/myapp
  2. 使用kubectl创建docker registry认证的secret

kubectl create secret docker-registry myregistrykey --docker-server=hub.qnhyn.com --docker-username=admin --docker-password=123456 --docker-email=""

  1. 在创建Pod的时候,通过imagePullSecrets来引用刚创建的myregistrykey
apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: foo
      image: hub.qnhyn.com/test/myapp
  imagePullSecrets:
    - name: myregistrykey

第三节 存储机制-Volume

3.1 Volume介绍

  1. 容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失,容器以干净的状态 (镜像最初的状态)重新启动。其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的Volume抽象就很好的解决了这些问题
  2. Kubernetes中的卷有明确的寿命,与封装它的Pod相同。所f以,卷的生命比Pod中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当Pod不再存在时,卷也将不复存在。也许更重要的是,Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷
  3. Kubernetes支持多种类型的卷
    • awsElasticBlockStore、azureDisk、azureFile、cephfs、csi、downwgrdAPI、 emptyDir
    • fc、flocker、 gcePersistentDisk、gitRepo、glusterfs、hostPath、iscsi、local、nfs
    • persistentVolumeClaim、projected、 portworxVolume、quobyte、rbd、scaleI0 、secret
    • storageos、vsphereVolume

3.2 emptyDir卷

  1. 当Pod被分配给节点时,首先创建emptyDir卷,并且只要该Pod在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod中的容器可以读取和写入emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除Pod时,emptyDir中的数据将被永久删除
  2. emptyDir的用法有:
    • 暂存空间,例如用于基于磁盘的合井排序
    • 用作长时间计算前溃恢复时的检查点
    • Web服务器容器提供数据时,保存内容管理器容器提取的文件
  3. 下面声明了一个名字叫cache-volume的volumes类型是emptyDir,把容器test-container中的/cache挂载在上面。em.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: hub.qnhyn.com/library/myapp
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  - image: busybox
    name: test-busybox
    command: ["/bin/sh","-c","sleep 6000s"]
    volumeMounts:
    - mountPath: /test
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}
  1. 到容器中查看,是否/cache下是一个空目录。
kubectl create -f em.yaml
# -c指定Pod中的容器
kubectl exec test-pd -c test-container  -it -- /bin/sh
# 在容器test-container的cache目录下
cd cache
date > index.html
exit
# 在容器test-busybox的test的目录下查看index.html文件
kubectl exec test-pd -c test-busybox  -it -- /bin/sh
cd test
exit

3.3 hostPath卷

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

  2. hostPath 的用途如下:

    • 运行需要访问Docker内部的容器;使用 /var/lib/docker 的 hostPath
    • 在容器中运行 cAdvisor;使用 /dev/cgroups 的 hostPath
  3. 这种方法非常灵活。只要存储服务能被挂载到node所在的节点,我们就可以用hostPath方案让Pod使用
    在这里插入图片描述

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

行为
空字符串 (默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查。
DirectoryOrCreate如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为0755,与Kubelet 具有相同的组和所有权。
Directory给定的路径下必须存在目录
FileOrCreate如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为0644,与Kubelet具有相同的组和所有权。
File给定的路径下必须存在文件
Socket给定的路径下必须存在UNIX套接字
CharDevice定的路径下必须存在字符设备
BlockDevice定的路径下必须存在块设备
  1. 使用这种卷类型是请注意,因为:
    • 由于每个节点上的文件都不同,具有相同配置(例如从podTemplate创建的)的pod在不同节点上的行为可能会有所不同(没有你去挂能挂上吗?逗逼)
    • 当Kubernetes 按照计划添加资源感知调度时,将无法考虑 hostPath 使用的资源(hostpath资源不归k8s管)
    • 在底层主机上创建的文件或目录只能由 root写入。您需要在特权容器中以 root身份运行进程,或修改主机上的文件权限以便写入 hostPath 卷(没权限,去改)
apiVersion: v1 
kind: Pod 
metadata:
  name: test-pd 
spec:
  containers:
  - image: hub.qnhyn.com/library/myapp
    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
  1. 实验
# 查看运行权限
ps aux | grep kubelete
# 创建文件夹 这里需要三个节点都创建文件夹哈 防止pod创建不成功
mkdir /data
kubectl create -f pod1.yaml
# 容器挂载目录下写入文件
kubectl exec test-pd -it -- /bin/sh
cd /test-pd
date > hello.txt
# 到对应节点下的/data下查看
cd /data

第四节 存储机制-持久卷PV和PVC

4.1 持久卷PV和PVC概念

在这里插入图片描述

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

4.2 PV访问模式(spec.accessModes)

  1. PersistentVolume可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV的访问模式都将被设置为该卷支持的特定模式。例如,NFS可以支持多个读/写客户端,但特定的NFS PV可能以只读方式导出到服务器上。每个PV都有一套自己的用来描述特定功能的访问模式
    • ReadWriteOnce: 该卷可以被单个节点以读/写模式挂载
    • ReadOnlyMany: 该卷可以被多个节点以只读模式挂载
    • ReadWriteMany: 该卷可以被多个节点以读/写模式挂载
  2. 命令行cli中,三种访问模式可以简写为:
    • RWO - ReadWriteOnce
    • ROX - ReadOnlyMany
    • RWX - ReadWriteMany
  3. 但不是所有的类型的底层存储都支持以上三种,每种底层存储类型支持的都不一样。各种底层存储具体支持的访问模式如下:
Volume PluginReadWriteOnceReadOnlyManyReadWriteMany
AWSElasticBlockStore××
AzureFile
AzureDisk××
CephFS
Cinder××
FC×
FlexVolume×
Flocker××
GCEPersistentDisk×
Glusterfs
HostPath××
iSCSI×
PhotonPersistentDisk××
Quobyte
NFS
RBD×
VsphereVolume××
PortworxVolume×
ScaleIO×

4.3 PV的回收策略(spec.persistentVolumeReclaimPolicy)

  1. 回收策略的三种策略
    • Retain(保留): pv被删除后会保留内存,手动回收
    • Recycle(回收): 删除卷下的所有内容(rm-rf /thevolume/*)
    • Delete(删除): 关联的存储资产(例如AWS EBS、GCE PD、Azure Disk 和OpenStack Cinder卷)将被删除。即直接把卷给删除了
  2. 回收策略注意事项
    • 当前,只有NFS和HostPath支持Recycle回收策略。 但是最新版本中的Recycle已被废弃,截图如下
    • 附:具体官网文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes
      在这里插入图片描述

4.3 PV的状态

  1. PV可以处于以下的某种状态:
    • Available(可用): 块空闲资源还没有被任何声明绑定
    • Bound(已绑定): 卷已经被声明绑定, 注意:但是不一定不能继续被绑定,看accessModes而定
    • Released(已释放): 声明被删除,但是资源还未被集群重新声明
    • Failed(失败): 该卷的自动回收失败
  2. 命令行会显示绑定到PV的PVC的名称

第五节 实验-持久化演示说明-NFS

5.1 安装NFS服务器

  1. 在hub仓库机器上创建NFS服务器
yum install -y nfs-common nfs-utils rpcbind 
mkdir /nfsdata
mkdir /nfsdata{1..3}
chmod 777 /nfsdata /nfsdata1 /nfsdata2 /nfsdata3
chown nfsnobody /nfsdata /nfsdata1 /nfsdata2 /nfsdata3
# 一下创建四个挂载目录
vim /etc/exports
	/nfsdata *(rw,no_root_squash,no_all_squash,sync)
	/nfsdata1 *(rw,no_root_squash,no_all_squash,sync)
	/nfsdata2 *(rw,no_root_squash,no_all_squash,sync)
	/nfsdata3 *(rw,no_root_squash,no_all_squash,sync)
systemctl start rpcbind 
systemctl start nfs
# 如果修改配置 重启生效
systemctl restart rpcbind
systemctl restart nfs
# 其他k8s节点安装客户端
yum install -y nfs-utils rpcbind

# 在任意节点测试是否能挂载成功
mkdir /test
# 查看共享目录
showmount -e 192.168.1.100
mount -t nfs 192.168.1.100:/nfsdata /test/
cd /test/
ls
vim index.html
# 解除挂载
cd -
umount /test/
rm -rf /test

5.2 部署PV

  1. 部署PV, 创建kubectl create -f pv.yaml.这里一下创建四个pv
    • 查看创建的pv: kubectl get pv
apiVersion: v1 
kind: PersistentVolume 
metadata:
  name: nfspv1 
spec:
  capacity:
    storage: 10Gi 
  accessModes:
    - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
   path: /nfsdata
   server: 192.168.1.100
---
apiVersion: v1 
kind: PersistentVolume 
metadata:
  name: nfspv2 
spec:
  capacity:
    storage: 5Gi 
  accessModes:
    - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
   path: /nfsdata1
   server: 192.168.1.100
---
apiVersion: v1 
kind: PersistentVolume 
metadata:
  name: nfspv3
spec:
  capacity:
    storage: 5Gi 
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: slow
  nfs:
   path: /nfsdata2
   server: 192.168.1.100
---
apiVersion: v1 
kind: PersistentVolume 
metadata:
  name: nfspv4
spec:
  capacity:
    storage: 1Gi 
  accessModes:
    - ReadWriteOnce 
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
   path: /nfsdata3
   server: 192.168.1.100

5.3 创建服务并使用PVC

  1. 一般我们不会直接用PV,而是用PVC的方案去调度。创建服务并使用PVC。kubectl create -f pod.yaml
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 # 要使用StatefulSet控制器,必须建立一个无头服务
metadata:
  name: web 
spec:
  selector:
    matchLabels:
      app: nginx 
  serviceName: "nginx" # 无头服务名称
  replicas: 3 
  template:
    metadata:
      labels:
        app: nginx 
    spec:
      containers:
      - name: nginx 
        image: hub.qnhyn.com/library/myapp
        ports:
        - containerPort: 80 
          name: web 
        volumeMounts: # 挂载下面声明的PVC
        - name: www 
          mountPath: /usr/share/nginx/html  # nginx的共享目录
  volumeClaimTemplates: # 声明一个PVC名称为www
  - metadata:
      name: www 
    spec:
      accessModes: [ "ReadWriteOnce" ] 
      storageClassName: "nfs"
      resources:
        requests:
          storage: 1Gi # 大小
  1. 上面创建pod时候会不成功。报错:没有匹配的volume,原因如下:
    • 既满足accessModes: [ “ReadWriteOnce” ]和 storageClassName: "nfs"的只有第一个PV
    • 而我们需要三个副本数。所以创建第二个时就卡住了。
    • 更改下PV的创建文件。重新创建PV即可。

5.4 关于 Statefulset

  1. StatefulSet为每个Pod副本创建了一个DNS域名,这个域名的格式为:S(podname).(headless servername),也就意味着服务间是通过Pod域名来通信而非PodIP,因为当Pod所在Node发生故障时,Pod会被飘移到其它 Node上,PodIP会发生变化,但是Pod域名不会有变化
  2. StatefulSet使用Headless服务来控制Pod的域名,这个域名的FQDN为:S(servicename).$(namespace).svc.cluster.local。其中,“cluster.local”指的是集群的域名
  3. 根据volumeClaimTemplates,为每个Pod 创建一个pvc,pvc的命名规则匹配模式:(volumeClaimTemplates.name)-(pod_name)
    • 比如上面的 volumeMounts.name=www,Podname-web-[0-2],因此创建出来的PVC是 www-web-0、www-web-1、 www-web-2
    • 在其他pod中可以直接访问:curl www-web-0 安装: yum install -y bind-utils
    • kubectl get pod -o wide -n kube-system 查看coredns的pod的ip为:10.244.0.11
    • dig -t A nginx.default.svc.cluster.local. @10.244.0.11 查看路由路径
  4. 删除 Pod 不会删除其pvc,手动删除pvc将自动释放pv
  5. Statefulset的启停顺序:
  • 有序部署:部罢Statefulset时,如果有多个Pod副本,它们会被顺序地创建**(从0到N-1)**并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。
  • 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。kubectl delete -f pod.yaml然后手动删除pv。
  • 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态
  1. Statefulset使用场景:
  • 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC 来实现。
  • 稳定的网络标识符,即Pod 重新调度后其iPodName 和 HostName不变。
  • 有序部署,有序扩展,基于init containers 来实现。
  • 有序收缩。
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐