K8s 里如何优雅地使用 /dev/shm 实现容器间共享内存

2023年 12月 26日 75.0k 0

本文经胡说云原生授权转载。

1. 从 docker run 的 --shm-size 参数聊起

今天无意见看到算法同学写的一个 docker run 命令用到了 --shm-size 参数。没错,接着他想将这些容器跑到 K8s 里,于是我就得开始思考 --shm-size 在 K8s 里对应的特性是什么了。

我猜 K8s 里会有优雅的方式来实现一样的目的,最终我也找到了那个优雅的方法。不过这个过程还是稍稍坎坷,我在在网上看一圈,找到的前2种方案都有点“丑陋”,但是给人一种“只能这样”的错觉。最后看到第三条路的时候,我不禁拍了一下大腿:“我X!太帅了!”。于是乎,我想让你们也拍一下大腿,然后就有了此文。行,且往下看。

2. Linux 里的 /dev/shm

Linux 里有一个 /dev/shm 目录,shm 代表共享内存(Shared Memory)。如果这是你第一次听说 shm,可能会有点疑惑:“这东西到底是内存还是磁盘”。其实 /dev/shm 是一个临时文件系统,让你用操作磁盘中的文件一样的方式来将读写内存。换言之,你可以用文件读写的语法来操作“/dev/shm/a.txt”,但是这个文件本质是存在内存里的,所以读写速度会非常快。

有了 /dev/shm,你就可以让一个进程非常高效地存取一些临时文件,或者让多个进程非常高效的“共享内存”。这种“进程间快速共享内存”的能力对于很多机器学习框架来说非常有用。

顺口提一下,可能大伙平时接触最多的进程间通信(IPC)方式是 Socket 和 RPC,这类走网络通信的方式可以实现跨主机的 IPC,应用场景更广。不过上帝给你开了一扇门,就不会多给你开一堆窗,Socket 和 RPC 的通信效率肯定就没有“共享内存”来得快了。(可能你心里在想 http 协议,没错,http 用的更多,但是一般 http 不被归入进程间通信方式。)

3. Docker 对共享内存的支持

在 Linux 系统中,/dev/shm 的大小一般为物理内存的一半。Docker 在启动容器的时候,默认给容器设置的 /dev/shm 大小是 64M。(你品,你细品,是不是自定义容器内 shm 大小的需求就产生了?)

Docker 在 shm 大小的配置上提供了两种支持:

  • docker run 支持通过 --shm-size=1g 这种方式指定一个容器的 shm 大小;
  • Docker 配置 daemon.json 中可以通过 "shared-memory-size": "1G" 配置指定容器启动的默认 shm 大小。
  • 不难猜到,--shm-size 参数的优先级会比 shared-memory-size 配置高。

    4. K8s 里如何设置 /dev/shm 大小

    K8s 里没有原生提供啥直观的 shm 配置方式。但是为了让应用能够尝到“共享内存”的滋味,YAML 工程师还是得给出方案。

    4.1 方案一:修改节点的 Docker 配置

    Sao 操作来了,因为 Docker 支持 shared-memory-size 配置,所以直接修改节点的 daemon.json 配置,那不就让所有 Pod 都能够用起来更大的 share memory 了?

    我就不演示了。反正基本满足需求,但是冥冥之中又让你觉得哪里不太对劲,总之吧,不优雅。

    4.2 方案二:通过 Volume 挂载一个大目录到 Pod 的 /dev/shm

    不就是让 Pod 内的 /dev/shm 大一点嘛,那就挂卷呀:

    apiVersion:v1
    kind:Pod
    metadata:
      name:shared-memory-pod
    spec:
      containers:
        -name:mycontainer
          image:your_image_name
          volumeMounts:
            -name:shared-memory-volume
              mountPath:/dev/shm
      volumes:
        -name:shared-memory-volume
          emptyDir:{}

    如果用 PVC 的方式,后端存储系统支持限定卷大小的话,这里就能精准分配 shm 的大小了。总之,业务能跑起来。(你是不是已经忍不住要开喷了?忍忍。我知道,这种方式通过磁盘上的文件来实现“共享内存”,功能走通了,性能不达标。)

    到这一步,我以为“方案一”挺合理的,改改 Docker 的启动参数,似乎影响不大,没啥大坏处,妥。

    不过更进一步,K8s 真的不支持配置 shm?这个需求听起来合理呀,为什么没有被实现呢?继续搜一搜,我在 stackoverflow 上看到了第三种玩法。

    4.3 方案三:用 K8s 的方式共享内存

    且看这段配置:

    apiVersion:v1
    kind:Pod
    metadata:
      name:shared-memory-pod
    spec:
      volumes:
        -name:dshm
          emptyDir:
            medium:Memory
            sizeLimit:"1Gi"
      containers:
        -name:mycontainer
          image:your_image_name
          volumeMounts:
            -name:dshm
              mountPath:/dev/shm

    行吧,破案了。之前我也不知道 emptyDir 可以配置 medium: Memory。

    5. 总结

    散了吧,总结啥。大周五的,早点回家。

    相关文章

    服务器端口转发,带你了解服务器端口转发
    服务器开放端口,服务器开放端口的步骤
    产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
    如何使用 WinGet 下载 Microsoft Store 应用
    百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
    百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

    发布评论