当前位置: 首页 > news >正文

一文掌握Kubernetes的Empty存储类型实践

在这里插入图片描述

📚 博客主页: StevenZeng学堂

🎉 本文专栏:

  • 一文读懂Kubernetes
  • 一文读懂Harbor
  • 云原生安全实战指南
  • 云原生存储实践指南


❤️ 摘要: 上文讲解了Kubernetes的持久化存储-PV和PVC, 本文将讨论Kubernetes中的一种重要的存储类型:emptyDir 。通过实验演示它们在实际场景中的应用。本文适合具备一定Kubernetes基础的读者,并且对云原生容器存储和日志处理感兴趣的技术人员。


💯 本文关联好文:

  • 《一文读懂K8S的PV和PVC以及实践攻略》
  • 《一文掌握Cephadm部署Ceph存储集群》

目录

  • 1 概念
    • 1.1 什么是emptyDir
    • 1.2 什么是Sidecar容器
      • 1.2.1 Sidecar的生命周期
  • 2 实验:emptyDir存储实际应用
    • 2.1 实验一:Sidecar容器使用`emptyDir`临时存储实现日志抓取
      • 2.1.1 日志收集方案介绍
      • 2.1.2 部署测试Deployment
      • 2.1.3 验证SideCar容器是否运作
    • 2.2 实验二:Redis使用`emptyDir`实现内存数据处理
      • 应用背景
      • 2.2.2 部署测试Redis Pods
  • 3 总结
  • 4 参考资料


1 概念

1.1 什么是emptyDir

emptyDir 是一种临时存储卷,生命周期与Pod相同。当Pod被创建时,emptyDir会自动创建一个空目录,存储会挂载到Pod的某个路径上。一旦Pod被删除,emptyDir的内容也会随之清空。

常用场景:

  • 数据缓存: 实时数据处理系统,如Redis通常需要快速访问临时存储以处理内存中的数据,从而最大限度地减少延迟并最大限度地提高吞吐量。
  • 日志的共享存储(多容器间)emptyDir 卷可以充当集中式日志目录,Pod 中的应用程序在其中写入其日志。然后,同一 Pod 中的单独容器可以处理这些日志、执行实时分析或将其转发到集中式日志记录服务。

关键特性

  • 数据存在于节点的临时存储中。
  • Pod重启不影响存储,但删除Pod时数据丢失。

1.2 什么是Sidecar容器

Sidecar 容器是和主应用容器一起运行在同一个 Pod 里的辅助容器。它的作用是为主应用提供额外的功能,比如日志收集、监控、安全管理等,而不用修改主应用的代码。
想象一下,主应用容器是主角,Sidecar 容器就像它的助手,帮助完成一些额外的任务。例如,假设你有一个 Web 应用程序需要本地的 Web 服务器支持,那么 Web 服务器可以作为 Sidecar 容器,而 Web 应用自身则是主应用容器。

1.2.1 Sidecar的生命周期

Kubernetes 将 Sidecar 容器作为一种特殊类型的容器,与 init 容器相似,但有一个显著不同点:init 容器只在 Pod 启动期间运行,而 Sidecar 容器会在 Pod 启动后保持运行。

但它和主应用容器是独立的,可以单独启动、停止或重启,而不会影响主应用的运行。这种设计使得你可以灵活地为应用添加新功能,而不需要改变主应用本身。

❔ 说明:在 1.29 版本及之后,Kubernetes 集群启用了 SidecarContainers 功能(默认启用),你可以为 Pod 中的 initContainers 字段中定义的容器指定 restartPolicy:Always。如果指定了这个字段,标志着 sidecar 容器独立于其他 init 容器。


2 实验:emptyDir存储实际应用

我们设计了二个实验来实践emptyDir存储类型:

2.1 实验一:Sidecar容器使用emptyDir临时存储实现日志抓取

2.1.1 日志收集方案介绍

Kubernetes 本身并未提供集群日志收集方案,但Kubernetes官方文档给了三种日志收集的建议方案:

  • 在每个节点上运行节点级的日志代理。
  • 在应用程序的 pod 中包含专门记录日志 sidecar 容器。
  • 应用程序直接将日志传输到日志平台(增加系统耦合性,不推荐

2.1.2 部署测试Deployment

编辑deployment配置,定义emptyDir卷并挂载到两个容器的相同路径。

apiVersion: apps/v1
kind: Deployment
metadata:name: log-shared-app
spec:replicas: 1selector:matchLabels:app: logtemplate:metadata:labels:app: logspec:containers:- name: appimage: harbor.zx/hcie/alpine:latestcommand: ["/bin/sh", "-c", "while true; do echo $(date) >> /var/log/app.log; sleep 5; done"]volumeMounts:- name: varlogmountPath: /var/loginitContainers:- name: logshipperimage: harbor.zx/hcie/alpine:latestrestartPolicy: Alwayscommand: ['sh', '-c', 'tail -F /var/log/app.log']volumeMounts:- name: varlogmountPath: /var/logrestartPolicy: Alwaysvolumes:- name: varlogemptyDir: {}

❔说明: 创建一个Pod定义,包含两个容器

  • app:主应用容器,负责生成日志。
  • logshipper:作为日志收集器sidecar容器,负责读取日志并发送到日志系统。
  • 使用empty临时共享映射到/var/log目录

2.1.3 验证SideCar容器是否运作

检查日志抓取和转发

查看app生成的日志,执行以下命令:

kubectl exec -it  log-shared-app-7fb8dc59f6-vgw5x app -- tail /var/log/app.log

输出如下:

Defaulted container "app" out of: app, logshipper (init)
Wed Oct 23 03:00:40 UTC 2024
Wed Oct 23 03:00:45 UTC 2024
Wed Oct 23 03:00:50 UTC 2024
Wed Oct 23 03:00:55 UTC 2024
Wed Oct 23 03:01:00 UTC 2024
Wed Oct 23 03:01:05 UTC 2024
Wed Oct 23 03:01:10 UTC 2024
Wed Oct 23 03:01:15 UTC 2024
Wed Oct 23 03:01:20 UTC 2024
Wed Oct 23 03:01:25 UTC 2024

查看logshipper的日志输出,验证日志是否正确抓取。

kubectl logs log-shared-app-7fb8dc59f6-vgw5x logshipper

输出如下:

tail: /var/log/app.log has appeared; following end of new file
Wed Oct 23 02:59:40 UTC 2024
Wed Oct 23 02:59:45 UTC 2024
Wed Oct 23 02:59:50 UTC 2024
Wed Oct 23 02:59:55 UTC 2024
Wed Oct 23 03:00:00 UTC 2024
Wed Oct 23 03:00:05 UTC 2024
Wed Oct 23 03:00:10 UTC 2024
Wed Oct 23 03:00:15 UTC 2024
Wed Oct 23 03:00:20 UTC 2024
Wed Oct 23 03:00:25 UTC 2024
  • logshipper可以读取app输出的日志并转发给指定的日志系统,说明两个容器成功通过emptyDir实现了日志共享。
  • 在实际业务中,sidecar还可以运行日志采集如filebeat,网络代理istio-proxy, 实现更丰富的功能。

查看empty临时卷

❔ 说明: 在 Kubernetes 中,emptyDir 卷通常会挂载在节点的 /var/lib/kubelet/pods/<pod-id>/volumes/kubernetes.io~empty-dir/ 目录下。

首先,找到 Pod 所在的节点和Pod的uid, 执行以下命令:

kubectl get pod log-shared-app-7fb8dc59f6-vgw5x -o=jsonpath="{.metadata.uid}{\"\t\"}{.spec.nodeName}{\"\n\"}"

输出如下:

f8df0dc5-9826-43a5-a0e1-9bd938427d23    k8s-worker2

登录到k8s-worker2节点, 查看 /var/lib/kubelet/pods/f8df0dc5-9826-43a5-a0e1-9bd938427d23/目录:

tree /var/lib/kubelet/pods/f8df0dc5-9826-43a5-a0e1-9bd938427d23/

输出如下:

/var/lib/kubelet/pods/f8df0dc5-9826-43a5-a0e1-9bd938427d23/
├── containers        # 这个目录用于存放 Pod 中所有容器的相关数据。
│   ├── app
│   │   └── 69f967b1
│   └── logshipper
│       └── 9ebf48e7
├── etc-hosts         # 这个文件在每个 Pod 内都会挂载,确保容器能正确解析集群内的服务和主机名。
├── plugins           # 该目录存放 Pod 中使用的存储插件或卷插件的相关信息。
│   └── kubernetes.io~empty-dir            # 表示 emptyDir 类型的卷插件。
│       ├── varlog
│       │   └── ready                      # 标记这个卷准备就绪。
│       └── wrapped_kube-api-access-47n7p  # 与 Kubernetes API 访问相关的 projected 卷
│           └── ready
└── volumes           # 该目录存储与 Pod 中容器挂载的卷相关的数据。├── kubernetes.io~empty-dir            # 这是 emptyDir 卷类型。│   └── varlog│       └── app.log└── kubernetes.io~projected            # 这是 projected 卷类型,通常用于提供 Pod 的认证信息。└── kube-api-access-47n7p├── ca.crt -> ..data/ca.crt├── namespace -> ..data/namespace└── token -> ..data/token12 directories, 9 files

2.2 实验二:Redis使用emptyDir实现内存数据处理

应用背景

高性能计算(HPC)应用程序或实时数据处理系统通常需要快速访问临时存储,以便在内存中处理数据,减少延迟并最大化吞吐量。这类应用对数据的读写速度要求非常高,传统的磁盘存储无法满足其需求,因此内存中的存储成为一种理想的解决方案。


2.2.2 部署测试Redis Pods

接下来,部署一个 Redis 实例,使用 emptyDir 并设置为内存类型, 配置文件如下:redis-memory.yaml

apiVersion: apps/v1
kind: Deployment
metadata:name: in-memory-data-processing
spec:replicas: 1selector:matchLabels:app: in-memory-data-processingtemplate:metadata:labels:app: in-memory-data-processingspec:containers:- name: data-producerimage: harbor.zx/hcie/redis:6.2.6command: ["redis-server", "--save", ""] volumeMounts:- name: redis-cachemountPath: /data           # 挂载到Redis数据目录- name: data-consumerimage: harbor.zx/hcie/redis:6.2.6command: ["redis-cli", "monitor"]volumeMounts:- name: data-volumemountPath: /datavolumes:- name: data-volumeemptyDir:medium: "Memory"           # 使用内存作为存储介质sizeLimit: "1Gi"           # 限制内存卷的大小为1GB

❔ 说明:如果你将 emptyDir.medium 字段设置为 “Memory”,Kubernetes 会为你挂载一个 tmpfs(RAM 支持的文件系统),tmpfs 可以为应用提供很高的IO读写性能。

⚠️ 注意:

  • 如果您没有为 emptyDir 卷指定 sizeLimit,则会按该 Pod 的内存限制进行限制 ( Pod.spec.containers[].resources.limits.memory )。
  • 如果也没设置内存限制,则 Pod 的内存消耗没有上限,并且可以耗尽节点上的所有可用内存。
  • 当节点内存耗尽时,操作系统会启动 “Out-Of-Memory (OOM)” 处理,强制终止一些进程以释放内存。这可能导致服务中断或宕机。
  • 在一个 Pod 中创建任意数量的 emptyDir 卷,而如果没有设置内存大小限制,这些卷都可能共同消耗大量内存,增加节点发生 OOM 的风险。

部署 Redis 实例:

kubectl apply -f in-memory-data-processing.yaml

查看 Redis Pod 的状态,确保它们已经运行:

kubectl get pods

输出如下:

NAME                        READY   STATUS    RESTARTS   AGE
in-memory-data-processing   1/1     Running   0          12s

查看日志

kubectl logs in-memory-data-processing-67c6f4966c-cn64t

输出如下:

Defaulted container "data-producer" out of: data-producer, data-consumer
1:C 23 Oct 2024 07:16:31.963 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 23 Oct 2024 07:16:31.963 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 23 Oct 2024 07:16:31.963 # Configuration loaded
1:M 23 Oct 2024 07:16:31.964 * monotonic clock: POSIX clock_gettime
1:M 23 Oct 2024 07:16:31.965 * Running mode=standalone, port=6379.
1:M 23 Oct 2024 07:16:31.965 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 23 Oct 2024 07:16:31.965 # Server initialized
1:M 23 Oct 2024 07:16:31.966 * Ready to accept connections

通过data-consumer观察redis状态:

kubectl logs in-memory-data-processing-67c6f4966c-cn64t data-consumer

输出如下:

OK
1729667910.481336 [0 127.0.0.1:47102] "COMMAND"
1729667918.895365 [0 127.0.0.1:47102] "set" "test" "12345"
  • 在上述部署中,data-producerdata-consumer容器都挂载了设置为使用 medium: MemoryemptyDir 卷。此设置可用于data-producer生成数据的时候,数据也通过data-consumer快速访问或处理。
  • 又例如视频处理图像处理应用场景,它们通常需要在处理过程中生成大量的中间文件或缓存数据。这些中间文件不需要持久化,并且频繁读写磁盘可能会成为瓶颈,因此将其存储在内存中能够显著提升处理速度。

3 总结

本文介绍了Kubernetes中的常用存储卷类型:emptyDir,并通过两个实验展示了它们在业务场景的实际应用。emptyDir在容器之间共享数据时十分有用,尤其适合Sidecar模式下的日志收集。同时也可以充分利用节点的闲置资源,实现pod应用的缓存加速作用。通过这些实践,您应该能够更好地理解emptyDir存储类型的工作原理,并在合适的场景中应用它们。


4 参考资料

[1] Kubernetes官方文档 — Sidecar Containers

[2] Kubernetes官方文档 — Volumes

[3] Kubernetes官方文档 — memory-backed-emptyDir


http://www.mrgr.cn/news/57047.html

相关文章:

  • git区分大小写吗?如果不区分,那要如何设置?
  • 数学之美——程序员的专属浪漫
  • redis 第155节答疑 源码分析Hash类型ziplist结构和zlentry实体解析
  • Android中的MVP模式
  • 成都跃享未来教育咨询有限公司抖音小店新生态
  • electron-vite_10electron-updater软件更新
  • TikTok限流困局:如何解决TikTok账号限流零播问题?
  • 「C++」初识模板
  • vue3可组合函数和hook的用法和使用场景区别
  • C4D.python的标签代码,标签名称,常量名互查工具
  • print_hex_dump调试内核,嘎嘎香
  • c++工程,各个模块间的通信机制设计
  • 进程控制:地址空间、fork与进程异常结束
  • Python日志配置
  • 技术总结(十一)
  • Rust中的Sync特征:确保多线程间安全共享数据
  • 几何算法系列:空间实体体积计算公式推导
  • 不同分辨率的大致带宽
  • 树莓集团:人工智能赋能,共创智慧未来
  • sql数据库的命令行操作(DDL修改表)
  • 餐饮点餐系统小程序源码
  • LeetCode-3185 构成整天的下标对数目Ⅱ
  • 利士策分享,给成功抛个媚眼,学习能否成为“丘比特”?
  • 解除123云盘1G下载限制油猴脚本方法
  • 冒泡,选择,插入,快速,归并排序(JavaScript)代码实现
  • 【面试题】什么是SpringBoot以及SpringBoot的优缺点