bigywater.tech
Docker · 77

docker top 与 ps:同一个进程在宿主机和容器里的两个视图

docker top 看到的 PID 为什么和容器里 ps 不一样?它怎么知道用户名?容器里没有 ps 怎么办?这篇逐项对比 docker top、docker exec ps 和 /proc 里的 NSpid。

53711 对 1
同一个容器主进程:docker top 的 PID 与容器里的 PID
daemon 对 bin
容器里 uid 1 叫 bin,docker top 显示虚拟机里的名字 daemon
127 对 正常
没有 ps 的 scratch 镜像:docker exec ps 失败,docker top 正常

两套 PID

实测 · 本机执行输出
  docker top(默认列):
    UID PID PPID C STIME TTY TIME CMD
    root 53711 53687 0 13:42 ? 00:00:00 sh -c sleep 300 & sleep 301 & wait
    root 53725 53711 0 13:42 ? 00:00:00 sleep 300
    root 53726 53711 0 13:42 ? 00:00:00 sleep 301
  docker exec ps(容器里的视角):
    PID PPID COMMAND COMMAND
    1 0 sh sh -c sleep 300 & sleep 301 & wait
    7 1 sleep sleep 300
    8 1 sleep sleep 301
    9 0 ps ps -o pid,ppid,comm,args
  容器主进程在虚拟机里的 PID = 53711;/proc/53711/status 的 NSpid = NSpid:	53711	1

docker top 在虚拟机里对容器 cgroup 里的进程跑 ps,所以 PID 是虚拟机的 PID;容器里的 ps 看到的是容器自己的 PID 命名空间。/proc/<PID>/status 的 NSpid 能把两个编号对上。

参数与列

实测 · 本机执行输出
  docker top -o pid,ppid,user,comm:退出码 0;PID PPID USER COMMAND | 53711 53687 root sh | 53725 53711 root sleep
  docker top aux:退出码 0;USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND | root 53711 0.0 0.0 1732 1072 ? Ss 13:42 0:00 sh -c sleep 300 & sleep 3 | root 53725 0.0 0.0 1716 880 ? S 13:42 0:00 sleep 300
  docker top -eo pid,nlwp,rss,etime,args:退出码 0;PID NLWP RSS ELAPSED COMMAND | 53711 1 1072 00:01 sh -c sleep 300 & sleep 301 & wait | 53725 1 880 00:01 sleep 300

docker top 后面的参数原样交给虚拟机里的 ps,可以自定义列、用 aux 等写法;输出里必须有 PID 列。

用户名

实测 · 本机执行输出
  容器里 uid 1 的名字(容器的 /etc/passwd):bin / bin
  虚拟机里 uid 1 的名字:daemon
  docker top 显示这个进程的 UID 列:UID PID PPID C STIME TTY TIME CMD | daemon 53878 53853 0 13:42 ? 00:00:00 sl
  docker top -o user,uid:Error response from daemon: Couldn't find PID field in ps output

用户名是虚拟机的 ps 去解析的,容器里的 /etc/passwd 对它没用:同一个 uid 1,容器里叫 bin,docker top 显示的是虚拟机里的 daemon。

没有 ps 的镜像

实测 · 本机执行输出
  scratch 镜像里 docker exec ps:退出码 127;OCI runtime exec failed: exec failed: unable to start container process: exec: "ps": executable file not found
  同一个容器 docker top:UID PID PPID C STIME TTY TIME CMD | root 54092 54068 0 13:42 ? 00:00:00 /app

distroless 或 scratch 镜像里没有 ps,docker exec 无计可施,docker top 仍然可用,是排查这类容器的少数办法之一。僵尸进程在 docker top 里看不到,见 c31。

分步演示

docker top
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。docker top 与 docker exec ps 的输出在同一时刻取得;虚拟机里的 /proc 与 /etc/passwd 通过特权容器加 nsenter 读取(方法见 c19);scratch 镜像是用宿主机 go 交叉编译的静态程序;PID 每次运行不同,文中取自最后一次运行;实验后已删除容器和镜像
    • 没有验证:Linux 宿主机上 docker top 的 PID(与宿主机 PID 相同,我没有测)、有 user namespace 重映射时的用户名、docker top 在容器很多进程时的性能、Windows 容器
    京ICP备2026067502号-1京公网安备11010502063487号