Docker 容器内查看占用端口的进程

FreeGuideOnline 最新 2026-07-06

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.0
  • 1F90(十六进制)代表端口 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