kubernetes笔记—卷和存储
临时卷 | Kubernetes
持久卷 | Kubernetes

问题随记

1、各个目录的含义
/var/lib/docker/containers /容器ID:容器数据
/var/lib/docker/overlay2
/var/lib/kubelet/pods/uid :pod中的数据,如临时卷、开启日志采集的日志(本质还是临时卷)等

持久卷存储位置:NFS主机/挂载目录/命名空间-PVC名称-PV名称

存储卷

image.png
image.png
除了可以让一个Pod里的多个容器共享文件、让容器的数据写到宿主机的磁盘上或者写文件到网络存储
中,Kubernetes的Volume还扩展出了一种非常有实用价值的功能,即容器配置文件集中化定义与管理,这是
通过ConfigMap这种新的资源对象来实现的

Volume类型

EmptyDir

一个emptyDir Volume是在Pod分配到Node时创建的。
它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为这是Kubernetes自动分配的一个目录
当Pod从Node上移除时,emptyDir中的数据也会被永久删除。

emptyDir的一些用途如下。
临时空间,例如用于某些应用程序运行时所需的临时目录,且无须永久保留
◎ 长时间任务的中间过程CheckPoint的临时保存目录。
◎ 一个容器需要从另一个容器中获取数据的目录(多容器共享目录)。
image.png

参考:
《Kubernetes中容器到容器通信》
https://mp.weixin.qq.com/s/P-xKd6HeOGxyt-YXCnZjmQ

hostPath

hostPath为在Pod上挂载宿主机上的文件或目录,它通常可以用于以下几方面。
◎ 容器应用程序生成的日志文件需要永久保存时,可以使用宿主机的高速文件系统进行存储。
◎ 需要访问宿主机上Docker引擎内部数据结构的容器应用时,可以通过定义hostPath为宿主
机/var/lib/docker目录,使容器内部应用可以直接访问Docker的文件系统。

通常用于单节点情况 (集群状态下,pod容易被删除,而新pod可能会被调度到其他主机上)

NFS

安装

  1. #关闭防火墙
  2. $ systemctl stop firewalld.service
  3. $ systemctl disable firewalld.service
  4. #安装配置 nfs
  5. $ yum -y install nfs-utils rpcbind
  6. #共享目录设置权限
  7. $ mkdir -p /data/k8s/
  8. $ chmod 755 /data/k8s/
  9. #配置 nfs,nfs 的默认配置文件在 /etc/exports 文件下,在该文件中添加下面的配置信息
  10. $ vi /etc/exports
  11. /data/k8s *(rw,sync,no_root_squash)
  12. #/data/k8s:是共享的数据目录
  13. #*:表示任何人都有权限连接,当然也可以是一个网段,一个 IP,也可以是域名
  14. #rw:读写的权限
  15. #sync:表示文件同时写入硬盘和内存
  16. #no_root_squash:当登录 NFS 主机使用共享目录的使用者是 root 时,
  17. #其权限将被转换成为匿名使用者,通常它的 UID 与 GID,都会变成 nobody 身份

启动

  1. #启动 rpcbind
  2. $ systemctl start rpcbind.service
  3. $ systemctl enable rpcbind
  4. $ systemctl status rpcbind
  5. #启动NFS服务
  6. $ systemctl start nfs.service
  7. $ systemctl enable nfs
  8. $ systemctl status nfs
  9. #验证
  10. $ rpcinfo -p|grep nfs
  11. $ cat /var/lib/nfs/etab

安装 nfs 的客户端

  1. $ systemctl stop firewalld.service
  2. $ systemctl disable firewalld.service
  3. $ yum -y install nfs-utils rpcbind
  4. $ systemctl start rpcbind.service
  5. $ systemctl enable rpcbind.service
  6. $ systemctl start nfs.service
  7. $ systemctl enable nfs.service

在客户端验证

  1. $ showmount -e <nfs_server_ip>
  2. #新建一个目录
  3. $ mkdir -p /root/course/kubeadm/data
  4. #挂载
  5. $ mount -t nfs <nfs_server_ip>:/data/k8s /root/course/kubeadm/data
  6. 在客户端新建一个文件
  7. $ touch /root/course/kubeadm/data/test.txt

在服务端查看是否有文件:

  1. $ ls -ls /data/k8s/

PV和PVC

PV(持久卷):描述一个具体的Volume属性,比如Volume的类型、挂载目录、远程存储服务器地址等
PV可以被理解成Kubernetes集群中的某个网络存储对应的一块存储,它与Volume类似,但有以下区
别。
◎ PV只能是网络存储,不属于任何Node,但可以在每个Node上访问
◎ PV并不是被定义在Pod上的,而是独立于Pod之外定义的。

PV 描述的,是持久化存储数据卷。这个 API 对象主要定义的是一个持久化存储在宿主机上的目录,比如一个 NFS 的挂载目录。
通常情况下,PV 对象是由运维人员事先创建在 Kubernetes 集群里待用的

  1. apiVersion: v1
  2. kind: PersistentVolume
  3. metadata:
  4. name: nfs
  5. spec:
  6. storageClassName: manual
  7. capacity:
  8. storage: 1Gi
  9. accessModes:
  10. - ReadWriteMany
  11. nfs:
  12. server: 10.244.1.4
  13. path: "/"

PVC(持久卷声明):描述 Pod想要使用的持久化属性,比如存储大小、读写权限等
PVC 对象通常由开发人员创建;或者以 PVC 模板的方式成为 StatefulSet 的一部分,然后由 StatefulSet 控制器负责创建带编号的 PVC。

创建PVC:

  1. apiVersion: v1
  2. kind: PersistentVolumeClaim
  3. metadata:
  4. name: nfs
  5. spec:
  6. accessModes:
  7. - ReadWriteMany
  8. storageClassName: manual
  9. resources:
  10. requests:
  11. storage: 1Gi

使用PVC
用户创建的 PVC 要真正被容器使用起来,就必须先和某个符合条件的 PV 进行绑定。(满足存储大小、storageClassName等条件)

绑定后,即可使用:

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. labels:
  5. role: web-frontend
  6. spec:
  7. containers:
  8. - name: web
  9. image: nginx
  10. ports:
  11. - name: web
  12. containerPort: 80
  13. volumeMounts:
  14. - name: nfs
  15. mountPath: "/usr/share/nginx/html"
  16. volumes:
  17. - name: nfs
  18. persistentVolumeClaim:
  19. claimName: nfs

image.png

StorageClass

一个大规模的 Kubernetes 集群里很可能有成千上万个 PVC,这就意味着运维人员必须得事先创建出成千上万个 PV。在实际操作中,这几乎没办法靠人工做到。
Kubernetes 为我们提供了一套可以自动创建 PV 的机制,即:Dynamic Provisioning。
Dynamic Provisioning 机制工作的核心,在于一个名叫 StorageClass 的 API 对象

StorageClass 对象的作用,其实就是创建 PV 的模板。具体地说,StorageClass 对象会定义如下两个部分内容:
第一,PV 的属性。比如,存储类型、Volume 的大小等等。
第二,创建这种 PV 需要用到的存储插件。比如,Ceph 等等。

StorageClass作为对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端存储的细节,一方面减少了
用户对于存储资源细节的关注,另一方面减轻了管理员手工管理PV的工作,由系统自动完成PV的创建和绑
定,实现了动态的资源供应。基于StorageClass的动态资源供应模式将逐步成为云平台的标准存储配置模
式。
StorageClass的定义主要包括名称、后端存储的提供者(provisioner)和后端存储的相关参数配置。

image.png

从图中我们可以看到,在这个体系中:

  • PVC 描述的,是 Pod 想要使用的持久化存储的属性,比如存储的大小、读写权限等。
  • PV 描述的,则是一个具体的 Volume 的属性,比如 Volume 的类型、挂载目录、远程存储服务器地址等。
  • 而 StorageClass 的作用,则是充当 PV 的模板。并且,只有同属于一个 StorageClass 的 PV 和 PVC,才可以绑定在一起。


    配置卷


    Projected Volume

在 Kubernetes 中,有几种特殊的 Volume,它们存在的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。这些特殊 Volume 的作用,是为容器提供预先定义好的数据。所以,从容器的角度来看,这些 Volume 里的信息就是仿佛是被 Kubernetes“投射”(Project)进入容器当中的。这正是 Projected Volume 的含义。

到目前为止,Kubernetes 支持的 Projected Volume 一共有四种:
Secret;
ConfigMap;
Downward API;
ServiceAccountToken。

Secret

从文件夹创建

  1. #首先创建目录secret-test,创建两个文件,写入
  2. [root@zm secret-test]# cat user
  3. test
  4. [root@zm secret-test]# cat pass
  5. test
  6. [root@zm secret-test]# kubectl -n cka create secret generic my-secret --from-file=.
  7. secret/my-secret created
  8. #查看
  9. [root@zm secret-test]# kubectl -n cka get secrets my-secret -o yaml
  10. apiVersion: v1
  11. data:
  12. pass: dGVzdAo=
  13. user: dGVzdAo=
  14. kind: Secret
  15. metadata:
  16. creationTimestamp: "2022-04-20T03:16:57Z"
  17. name: my-secret
  18. namespace: cka
  19. resourceVersion: "568020"
  20. uid: f4dffc10-0a9e-405f-8ed8-f78544060f7c
  21. type: Opaque

从YAML文件创建

  1. apiVersion: v1
  2. kind: Secret
  3. metadata:
  4. name: mysecret
  5. type: Opaque
  6. data:
  7. user: YWRtaW4=
  8. pass: MWYyZDFlMmU2N2Rm

前提是需要先转码

  1. #加密
  2. [root@zm ~]# echo test|base64
  3. dGVzdAo=
  4. #解密
  5. [root@zm ~]# echo dGVzdAo= |base64 -d
  6. test

这里需要注意的是,像这样创建的 Secret 对象,它里面的内容仅仅是经过了转码,而并没有被加密。在真正的生产环境中,你需要在 Kubernetes 中开启 Secret 的加密插件,增强数据的安全性

ConfigMap

应用部署的一个最佳实践是将应用所需的配置信息与程序进行分离,这样可以使应用程序被更好地复
用,通过不同的配置也能实现更灵活的功能。从Kubernetes 1.2开始提供了一种统一的应用配置管理方案—ConfigMap

创建:与Secret类似

从文件/文件夹创建

文件名为key,文件内容为value

kubectl -n cka create cm my-cm --from-file=.

从YAML文件创建

使用场景:
1、环境变量;
2、配置文件

使用方式之-环境变量

与使用场景相对应,容器应用对ConfigMap的使用有以下两种方式。
(1)通过环境变量获取ConfigMap中的内容。

image.png

使用方式之-挂载到容器

(2)通过Volume挂载的方式将ConfigMap中的内容挂载为容器内部的文件或目录。
image.png

使用ConfigMap的限制条件
ConfigMap必须在Pod之前创建
◎ ConfigMap受Namespace限制,只有处于相同Namespace中的Pod才可以引用它。
◎ ConfigMap中的配额管理还未能实现。
◎ kubelet只支持可以被API Server管理的Pod使用ConfigMap。kubelet在本Node上通过 —manifest-url
或—config自动创建的静态Pod将无法引用ConfigMap。
◎ 在Pod对ConfigMap进行挂载(volumeMount)操作时,在容器内部只能挂载为“目录”,无法挂载为“文件”。

  • 容器以 subPath 卷挂载方式使用 ConfigMap 时,将无法接收 ConfigMap 的更新。

采用环境变量的方式使用ConfigMap:ConfigMap内存放键值对;无需挂载,需要在部署时定义环境变量去引用ConfigMap。适合于,应用内没有一个特定文件存放配置信息。
采用Volume挂载方式使用ConfigMap:ConfigMap内存放文件名和文件内容。适合于,应用内有特定文件来存放配置信息,或文件内容有特定格式要求。

Downward API

作用:让 Pod 里的容器能够直接获取到这个 Pod API 对象本身的信息。

例子:

定义了一个简单的容器,声明了一个 projected 类型的 Volume。只不过这次 Volume 的数据来源,变成了 Downward API。而这个 Downward API Volume,则声明了要暴露 Pod 的 metadata.labels 信息给容器。

通过这样的声明方式,当前 Pod 的 Labels 字段的值,就会被 Kubernetes 自动挂载成为容器里的 /etc/podinfo/labels 文件。

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: test-downwardapi-volume
  5. labels:
  6. zone: us-est-coast
  7. cluster: test-cluster1
  8. rack: rack-22
  9. spec:
  10. containers:
  11. - name: client-container
  12. image: k8s.gcr.io/busybox
  13. command: ["sh", "-c"]
  14. args:
  15. - while true; do
  16. if [[ -e /etc/podinfo/labels ]]; then
  17. echo -en '\n\n'; cat /etc/podinfo/labels; fi;
  18. sleep 5;
  19. done;
  20. volumeMounts:
  21. - name: podinfo
  22. mountPath: /etc/podinfo
  23. readOnly: false
  24. volumes:
  25. - name: podinfo
  26. projected:
  27. sources:
  28. - downwardAPI:
  29. items:
  30. - path: "labels"
  31. fieldRef:
  32. fieldPath: metadata.labels
  1. 1. 使用fieldRef可以声明使用:
  2. spec.nodeName - 宿主机名字
  3. status.hostIP - 宿主机IP
  4. metadata.name - Pod的名字
  5. metadata.namespace - PodNamespace
  6. status.podIP - PodIP
  7. spec.serviceAccountName - PodService Account的名字
  8. metadata.uid - PodUID
  9. metadata.labels['<KEY>'] - 指定<KEY>的Label
  10. metadata.annotations['<KEY>'] - 指定<KEY>的Annotation
  11. metadata.labels - Pod的所有Label
  12. metadata.annotations - Pod的所有Annotation
  13. 2. 使用resourceFieldRef可以声明使用:
  14. 容器的CPU limit
  15. 容器的CPU request
  16. 容器的memory limit
  17. 容器的memory request

需要注意的是,Downward API 能够获取到的信息,一定是 Pod 里的容器进程启动之前就能够确定下来的信息。而如果你想要获取 Pod 容器运行后才会出现的信息,比如,容器进程的 PID,那就肯定不能使用 Downward API 了,而应该考虑在 Pod 里定义一个 sidecar 容器。

ServiceAccountToken

一种特殊的 Secret

Service Account 对象的作用,就是 Kubernetes 系统内置的一种“服务账户”,它是 Kubernetes 进行权限分配的对象。比如,Service Account A,可以只被允许对 Kubernetes API 进行 GET 操作,而 Service Account B,则可以有 Kubernetes API 的所有操作权限。

像这样的 Service Account 的授权信息和文件,实际上保存在它所绑定的一个特殊的 Secret 对象里的。这个特殊的 Secret 对象,就叫作 ServiceAccountToken。

如果你查看一下任意一个运行在 Kubernetes 集群里的 Pod,就会发现,每一个 Pod,都已经自动声明一个类型是 Secret、名为 default-token-xxxx 的 Volume,然后 自动挂载在每个容器的一个固定目录上

  1. $ kubectl describe pod nginx-deployment-5c678cfb6d-lg9lw
  2. Containers:
  3. ...
  4. Mounts:
  5. /var/run/secrets/kubernetes.io/serviceaccount from default-token-s8rbq (ro)
  6. Volumes:
  7. default-token-s8rbq:
  8. Type: Secret (a volume populated by a Secret)
  9. SecretName: default-token-s8rbq
  10. Optional: false

高级

一文理解 Kubernetes 的存储系统机制
https://mp.weixin.qq.com/s/XLe6pnGNCeM5ilTRiJfwKA

《Kubernetes 存储原理解析》
https://mp.weixin.qq.com/s/bkpZMbmKa6lBKg8Fc3Lkzw

Kubernetes存储架构原理深度剖析(上、下)
https://mp.weixin.qq.com/s/juKJWg7dXtOSBFOSu84kjQ
https://mp.weixin.qq.com/s/FFt_Y1Kt6tNtNGe50QpQUQ