配置 Kubernetes 以将容器存储在单独的文件系统上

在运行和操作 Kubernetes 集群时,常见的一个问题就是磁盘空间不足。当节点被配置时,你应该确保为容器镜像和运行中的容器分配足够的存储空间。容器运行时通常会写入 /var 目录。这个目录可以作为一个单独的分区,也可以位于根文件系统上。默认情况下,CRI-O 会将其容器和镜像写入 /var/lib/containers,而 containerd 会将其容器和镜像写入 /var/lib/containerd

Kubernetes 有持久数据和临时数据。kubelet 和本地 Kubernetes 特定存储的基本路径是可配置的,通常为 /var/lib/kubelet。在 Kubernetes 文档中,这个路径有时被称为根文件系统或节点文件系统。这些数据的大部分可以分为以下几类:

  • ephemeral storage(临时数据)
  • logs
  • container runtime(运行时数据)

这与大多数 POSIX 系统不同,因为在大多数 POSIX 系统中,根文件系统或节点文件系统是 /,而在 Kubernetes 中,指的是/var/lib/kubelet所在的磁盘。

ephemeral storage(临时数据)

Pods 和容器在其运行过程中可能需要临时或短暂的本地存储。临时存储的生命周期不会超过单个 Pod 的生命周期,并且不能在不同的 Pod 之间共享。

logs

默认情况下,Kubernetes 将每个运行中的容器的日志存储在 /var/log 目录下的文件中。这些日志是临时的,并且由 kubelet 监控,以确保它们在 Pod 运行期间不会变得过大。

您可以自定义每个节点的日志轮转设置来管理这些日志的大小,并配置日志传输(使用第三方解决方案)以避免依赖于节点本地存储。

container runtime(运行时数据)

容器运行时有两个不同的存储区域,用于存储容器和镜像。

  • 只读层:镜像通常被视为只读层,因为它们在容器运行时不会被修改。只读层可以由多个层组合而成,形成一个单一的只读层。在容器上有一层薄薄的临时存储层,用于容器写入文件系统的情况。
  • 可写层:根据您的容器运行时,本地写入可能实现为分层写机制(例如,在 Linux 上的 overlayfs 或在 Windows 上的 CimFS)。这被称为可写层。本地写入也可能使用一个初始化为容器镜像完整克隆的可写文件系统;这用于基于虚拟化的某些运行时。

容器运行时文件系统包含只读层和可写层。在 Kubernetes 文档中,这被称为 imagefs

Container runtime configurations

CRI-O

CRI-O 使用一个 TOML 格式的存储配置文件,允许您控制容器运行时如何存储持久数据和临时数据。CRI-O 利用了存储库(storage library)。

一些 Linux 发行版提供了一个关于存储的手册(man 5 containers-storage.conf)。存储的主要配置文件位于 /etc/containers/storage.conf,您可以在此控制临时数据和根目录的位置。

根目录是 CRI-O 存储持久数据的地方。

[storage]
# Default storage driver
driver = "overlay"
# Temporary storage location
runroot = "/var/run/containers/storage"
# Primary read/write location of container storage 
graphroot = "/var/lib/containers/storage"
  • graphroot
    从容器运行时存储的持久数据(如果启用了 SELinux,这个路径必须匹配 /var/lib/containers/storage)。
  • runroot
    容器的临时读写访问(建议将此配置在临时文件系统上)。

这里有一个快速的方法来重新标记您的 graphroot 目录,以匹配 /var/lib/containers/storage:

semanage fcontext -a -e /var/lib/containers/storage <YOUR-STORAGE-PATH>
restorecon -R -v <YOUR-STORAGE-PATH>

containerd

containerd 运行时使用一个 TOML 配置文件来控制持久数据和临时数据的存储位置。配置文件的默认路径位于 /etc/containerd/config.toml

与 containerd 存储相关的字段是rootstate

  • root
    containerd 元数据的根目录。默认值为 /var/lib/containerd。如果您的操作系统需要,根目录也需要 SELinux 标签。
  • state
    containerd 的临时数据。默认值为 /run/containerd

Kubernetes 节点压力驱逐

Kubernetes 会自动检测容器文件系统是否与节点文件系统分离。当文件系统分离时,Kubernetes 负责监控节点文件系统和容器运行时文件系统。Kubernetes 文档中将节点文件系统和容器运行时文件系统分别称为 nodefsimagefs。如果 nodefsimagefs 中的任何一个磁盘空间不足,那么整个节点将被认为存在磁盘压力。在这种情况下,Kubernetes 会首先通过删除未使用的容器和镜像来回收空间,然后才会考虑驱逐 Pod。在一个具有 nodefsimagefs的节点上,kubelet 会在 imagefs 上垃圾回收未使用的容器镜像,并从 nodefs 中移除已死亡的 Pod 及其容器。如果只有 nodefs,那么 Kubernetes 的垃圾回收将包括已死亡的容器、已死亡的 Pod 和未使用的镜像。

Kubernetes 允许更多配置来确定磁盘是否已满
kubelet 内的驱逐管理器有一些配置设置,可以让您控制相关的阈值。对于文件系统,相关的测量指标包括 nodefs.availablenodefs.inodesfreeimagefs.availableimagefs.inodesfree。如果容器运行时没有专用磁盘,则忽略 imagefs

用户可以使用现有的默认值:

  • memory.available < 100MiB

  • nodefs.available < 10%

  • imagefs.available < 15%

  • nodefs.inodesFree < 5%(仅限 Linux 节点)
    Kubernetes 允许您在 kubelet 配置文件中设置用户定义的值,这些值可以在 EvictionHard EvictionSoft 中定义。

  • EvictionHard
    定义了限制;一旦这些限制被超过,Pod 将在没有任何宽限期的情况下被驱逐。

  • EvictionSoft
    定义了限制;一旦这些限制被超过,Pod 将在设定的宽限期内被驱逐,宽限期可以按信号设置。
    如果您指定了 EvictionHard 的值,它将替换默认值。这意味着在配置中设置所有信号非常重要。

例如,以下 kubelet 配置可用于设置驱逐信号和宽限期选项:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
address: "192.168.0.8"
port: 20250
serializeImagePulls: false
evictionHard:
    memory.available:  "100Mi"
    nodefs.available:  "10%"
    nodefs.inodesFree: "5%"
    imagefs.available: "15%"
    imagefs.inodesFree: "5%"
evictionSoft:
    memory.available:  "100Mi"
    nodefs.available:  "10%"
    nodefs.inodesFree: "5%"
    imagefs.available: "15%"
    imagefs.inodesFree: "5%"
evictionSoftGracePeriod:
    memory.available:  "1m30s"
    nodefs.available:  "2m"
    nodefs.inodesFree: "2m"
    imagefs.available: "2m"
    imagefs.inodesFree: "2m"
evictionMaxPodGracePeriod: 60s

注意

Kubernetes 项目建议您要么使用默认的驱逐设置,要么设置所有的驱逐字段。您可以使用默认设置,也可以指定自己的 evictionHard 设置。如果您遗漏了某个信号,Kubernetes 将不会监控该资源。管理员或用户常见的一个错误配置是在 /var/lib/containers/storage/var/lib/containerd 挂载一个新的文件系统。Kubernetes 会检测到这是一个独立的文件系统,因此如果您进行了这样的操作,需要确保 imagefs.inodesfreeimagefs.available 符合您的需求。

另一个容易混淆的领域是,即使您为节点定义了一个镜像文件系统,临时存储报告也不会改变。镜像文件系统(imagefs)用于存储容器镜像层;如果容器写入其自身的根文件系统,这种本地写入不会计入容器镜像的大小。容器运行时存储这些本地修改的位置是运行时定义的,但通常也是镜像文件系统。如果Pod中的容器写入一个基于文件系统的 emptyDir 卷,这将占用 nodefs 文件系统的空间。kubelet 始终基于 nodefs 文件系统报告临时存储容量和分配,这在临时写入实际上发生在镜像文件系统时可能会引起混淆。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葡萄皮Apple

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值