Docker 容器内查看占用端口的进程
bash docker exec -it <容器名或ID> /bin/sh
若容器使用 bash,也可用 /bin/bash
> 提示:部分极简容器(如基于 Alpine)可能连 `bash` 都没有,请改用 `sh`。
### 方法一:使用传统 `netstat` 命令
`netstat` 是最经典的工具,在多数标准 Linux 发行版中默认预装,但精简镜像中很可能不存在。
查看所有监听端口及对应的进程信息:
```bash
netstat -tunlp
参数说明:
-t显示 TCP 端口-u显示 UDP 端口-n以数字形式显示地址和端口,避免反向域名解析-l仅显示处于监听状态的服务-p显示使用该端口的程序名及 PID
输出示例:
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 42/nginx: master
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 42/nginx: master
若容器内未安装 netstat,可通过包管理器快速安装:
- Debian/Ubuntu:
apt update && apt install net-tools - CentOS/RHEL:
yum install net-tools - Alpine:
apk add net-tools
方法二:使用现代化 ss 命令
ss (Socket Statistics) 是 netstat 的现代替代品,速度更快,而且多数精简镜像(如基于 Alpine 的 busybox)可能会内置。
执行以下命令查看端口占用:
ss -tunlp
参数含义与 netstat 完全一致,输出格式也高度相似。若命令不存在,可安装 iproute2 包:
- Debian/Ubuntu:
apt install iproute2 - Alpine:
apk add iproute2
ss 还支持直接过滤特定端口,例如仅查看 8080 端口:
ss -tunlp sport = :8080
方法三:通过 lsof 定位端口
lsof (List Open Files) 可以列出所有打开的文件,包括网络套接字。在排查端口占用时十分精准。
查看所有监听端口的进程:
lsof -i -sTCP:LISTEN -nP
参数解释:
-i选择网络文件(不指定协议则显示所有)-sTCP:LISTEN仅显示处于 LISTEN 状态的 TCP 套接字-n不解析主机名-P不解析服务名,直接显示端口号
直接查看某个特定端口,例如 3306:
lsof -i :3306
安装 lsof:
- Debian/Ubuntu:
apt install lsof - Alpine:
apk add lsof
注意:
lsof通常需要 root 权限,容器内默认以 root 运行,故无问题。
方法四:零工具方案 —— 直接读取 /proc 文件系统
当容器极度精简,没有任何网络工具且不允许安装额外软件时,可以直接通过 Linux 的 /proc 文件系统获取信息。
查看所有 TCP/UDP 套接字状态:
cat /proc/net/tcp
cat /proc/net/udp
输出以十六进制显示,监听端口在 local_address 列的第二段。例如:
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:1F90 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 12345 1 ...
00000000表示0.0.0.01F90(十六进制)代表端口 8080(转换为十进制:1×16³+15×16²+9×16¹+0 = 4096+3840+144 = 8080)0A表示LISTEN状态
获取占用该 inode 的进程。从上述 inode 列得知 12345,再查找进程:
# 通过 inode 找到对应的进程 ID
ls -l /proc/*/fd/* 2>/dev/null | grep socket:\[12345\]
这将显示类似 /proc/42/fd/12 -> socket:[12345],其中 42 即为 PID。然后可通过 ps 查看进程名:
ps -p 42 -o comm=
将以上步骤封装为脚本,可在任何容器内直接执行:
#!/bin/sh
echo "Listening ports:"
for i in $(awk '/0A/ {print $2,$10}' /proc/net/tcp); do
port_hex=$(echo $i | cut -d: -f2)
port_dec=$((0x$port_hex))
inode=$(echo $i | awk '{print $2}')
pid=$(ls -l /proc/*/fd/* 2>/dev/null | grep "socket:\[$inode\]" | head -1 | awk -F'/' '{print $3}')
comm=$(ps -p $pid -o comm= 2>/dev/null)
echo "Port: $port_dec -> PID: $pid ($comm)"
done
该方法无需安装任何工具,适用于任何 Linux 容器。
方法五:从宿主机查看容器内进程端口
在某些场景下,你可能无法或不方便进入容器,这时可直接在宿主机上检查。
查看容器所有的端口映射(仅限已映射到宿主机的端口):
docker port <容器名或ID>
这会显示容器的内部端口与宿主机的映射关系,但无法告诉你容器内哪个进程在监听。
直接查看容器内进程的网络信息:
Docker 容器的进程在宿主机上同样可见。首先找到容器内进程在宿主机的 PID:
docker inspect -f '{{.State.Pid}}' <容器名或ID>
假设返回 12345,接着使用宿主机的网络工具结合该 PID 过滤:
nsenter -t 12345 -n ss -tunlp
nsenter 会进入目标进程的网络命名空间运行 ss,效果完全等同于在容器内执行。宿主机无需安装任何容器内的额外工具。
如果宿主机的 ss 版本较旧,也可使用 /proc:
nsenter -t 12345 -n cat /proc/net/tcp