emptyDir 到底存在哪?容器重启后文件还在吗?medium: Memory 占的是谁的内存?sizeLimit 是配额吗?这篇在真集群里读节点上的目录、/proc/mounts 和 cgroup 的 memory.stat,把这些问题都实际验证一遍。
Pod life 在 worker2 上;节点上的目录 /var/lib/kubelet/pods/<uid>/volumes/kubernetes.io~empty-dir/v 里:['log', 'seen'] 第一个容器写完文件后自己 exit 1,kubelet 重启了它(restartCount=1);重启后 /v 里的文件:['log', 'seen'];/v/log 的内容:['第一次运行', '容器重启后又运行'](emptyDir 里的文件跨容器重启保留) 同一个目录还在节点上:是 删除 Pod 之后节点上的目录:消失了(等了 2.9 秒) 同名 Pod 重新创建(同一个节点)后 /v/log:['新 Pod 写入'](是一个新的空目录)
节点上 emptyDir 的目录在 /var/lib/kubelet/pods/<uid>/volumes/kubernetes.io~empty-dir/<卷名>。容器自己 exit 1 被 kubelet 重启后,/v 里的 log 和 seen 都还在,日志里能看到“第一次运行”和“容器重启后又运行”两行——emptyDir 的文件跨容器重启保留。
删除 Pod 后 2.3 秒内节点上的目录消失;同名 Pod 重建后拿到的是一个空目录。它的生命周期跟 Pod(uid)绑定,不跟容器,也不跟名字。
disk:/proc/mounts 里 /v 这一行:/dev/vda1 /v ext4 rw,relatime,discard 0 0
df /v:/dev/vda1 474095688 15002816 434936664 3% /v
mem:/proc/mounts 里 /v 这一行:tmpfs /v tmpfs rw,relatime,size=8124516k,noswap 0 0
df /v:tmpfs 8124516 0 8124516 0% /v
节点内存 MemTotal=8124516 KiB(没写 sizeLimit 时 tmpfs 的大小就是整个节点内存)
往 disk 的 /v 写 50 MiB:容器 cgroup 的 memory.current 340 KiB → 54292 KiB(增加 52 MiB);文件系统占用 51204 KiB
memory.stat:anon=132 KiB;file(页缓存)=52556 KiB;shmem(tmpfs 页)=0 KiB;file_dirty=0 KiB
往 mem 的 /v 写 50 MiB:容器 cgroup 的 memory.current 1744 KiB → 53068 KiB(增加 50 MiB);文件系统占用 51200 KiB
memory.stat:anon=128 KiB;file(页缓存)=52616 KiB;shmem(tmpfs 页)=51200 KiB;file_dirty=0 KiB默认的 emptyDir 是节点磁盘上的目录(/proc/mounts 里是 ext4,df 看到的是整块盘);medium: Memory 是 tmpfs,没写 sizeLimit 时大小是 8124516k,正好等于节点的 MemTotal。
各写 50 MiB:两个容器的 memory.current 都涨了约 50 MiB,区别在 memory.stat:Memory 卷的 shmem 是 51200 KiB,磁盘卷的 shmem 是 0,只是可回收的页缓存(file)。tmpfs 的页是共享内存,没有 swap 时不能直接丢掉,所以它是真正占着的内存。
limit 64Mi、往 Memory 卷写 100 MiB:容器状态(相对时间秒, 状态, restartCount)依次是 [(0.0, 'running', 0), (7.0, 'terminated:OOMKilled', 0), (8.0, 'waiting:RunContainerError', 1), (20.4, 'waiting:CrashLoopBackOff', 1), (21.0, 'waiting:RunContainerError', 2)] 45 秒后 restartCount=2;state.waiting.reason=RunContainerError;lastState.terminated.reason=StartError;message=…: unable to start container process: container init was OOM-killed (memory limit too low?) 这时 tmpfs 里的数据还在吗:Pod 级内存 memory.current=62 MiB(容器重启了,tmpfs 的页还留在 Pod 的 cgroup 里)
容器 memory limit 64Mi,往 Memory 卷写 100 MiB:约 7 秒时容器 OOMKilled;重启后新容器在 init 阶段就被 OOM 杀,RunContainerError,message 是 container init was OOM-killed (memory limit too low?),接着 CrashLoopBackOff。此时 Pod 级 memory.current 还有 62 MiB,tmpfs 里的数据没有随旧容器一起消失,新容器一启动就背着这些内存。
所以 Memory 卷要和容器的 memory limit 一起算,而且最好设 sizeLimit。
Memory 卷 sizeLimit 20Mi:df tmpfs 20480 0 20480 0% /v
写 30 MiB:["dd: error writing '/v/big': No space left on device", '21+0 records in', '20+0 records out']
之后 Pod 状态:Running,du 20480 KiB
磁盘卷 sizeLimit 20Mi:df /dev/vda1 474095688 15015296 434924184 3% /v(df 看到的仍是整块磁盘,sizeLimit 不是文件系统配额)
写 30 MiB:31457280 bytes (30.0MB) copied, 0.041791 seconds, 717.9MB/s
写完之后 24 秒:phase=Failed reason=Evicted;message=Usage of EmptyDir volume "v" exceeds the limit "20Mi".
事件:['Evicted: Usage of EmptyDir volume "v" exceeds the limit "20Mi". ', 'Killing: Stopping container c']Memory 卷设 sizeLimit: 20Mi,tmpfs 的大小就是 20480 KiB,写 30 MiB 立刻 No space left on device,Pod 仍是 Running。磁盘卷的 sizeLimit 不是文件系统配额:df 仍是整块盘,写 30 MiB 毫无阻碍,要等 kubelet 下一轮检查才发现超限,24 秒后 Pod 变成 Failed、reason Evicted,message 是 Usage of EmptyDir volume "v" exceeds the limit "20Mi"。
这个检查周期不固定——多次运行里是 24~45 秒——不要依赖它做实时限制。