在linux ubuntu 系统下,宿主机里看不到监听端口,但容器访问正常
现象:
root@bwoil:/data/redis# ls
conf data docker-compose.yaml redis.7.0.7.tgz
root@bwoil:/data/redis# nerdctl compose ps
NAME IMAGE COMMAND SERVICE STATUS PORTS
redis docker.io/library/redis:7.0.7 "redis-server /usr/l…" redis running 0.0.0.0:6379->6379/tcp
root@bwoil:/data/redis# more docker-compose.yaml
version: '3'
services:
redis:
hostname: redis
image: redis:7.0.7
container_name: redis
privileged: true
ports:
- 6379:6379
sysctls:
- net.core.somaxconn=1024
volumes:
- ./data:/data
- ./conf:/usr/local/etc/redis
- /etc/localtime:/etc/localtime:ro
entrypoint: redis-server /usr/local/etc/redis/redis.conf
restart: always
mem_limit: 4g
networks:
- meta
networks:
meta:
external: true
root@bwoil:/data/redis# netstat -ntpl |grep 6379
root@bwoil:/data/redis# ss |grep 6379
root@bwoil:/data/redis# sudo lsof -iTCP:6379 -sTCP:LISTEN
root@bwoil:/data/redis#
为什么呢?
查看防火墙规则:
root@bwoil:/data/redis# sudo iptables -L -n |grep 6379
root@bwoil:/data/redis# iptables -nvL|grep 6379
root@bwoil:/data/redis# sudo iptables -t nat -L -n |grep 6379
CNI-HOSTPORT-SETMARK tcp -- 10.4.2.0/24 0.0.0.0/0 tcp dpt:6379
CNI-HOSTPORT-SETMARK tcp -- 127.0.0.1 0.0.0.0/0 tcp dpt:6379
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:6379 to:10.4.2.159:6379
CNI-DN-635091dd85894072ba7c2 tcp -- 0.0.0.0/0 0.0.0.0/0 /* dnat name: "meta" id: "k8s.io-5af4d10ddad658ac61103431f71ec0407007b4bac055902820f1ce940a3be89b" */ multiport dports 6379
CNI-HOSTPORT-SETMARK tcp -- 10.4.2.0/24 0.0.0.0/0 tcp dpt:6379
这条规则用于标记来自特定子网10.4.2.0/24的流量,以便后续的处理
CNI-HOSTPORT-SETMARK tcp -- 127.0.0.1 0.0.0.0/0 tcp dpt:6379
这条规则标记来自本机的6379端口的流量
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:6379 to:10.4.2.159:6379
这条规则将所有发往6379端口的流量转发到IP地址为10.4.2.159的主机的6379端口。这是典型的DNAT(目的地址转换)规则,常用于将外部流量转发到内部服务
CNI-DN-635091dd85894072ba7c2 tcp -- 0.0.0.0/0 0.0.0.0/0 /* dnat name: "meta" id: "k8s.io-5af4d10ddad658ac61103431f71ec0407007b4bac055902820f1ce940a3be89b" */ multiport dports 6379
这条规则是一个注释规则,表示它是由Kubernetes网络插件创建的,可能用于将流量转发到多个6379端口的服务。注释中包含了元数据,可能用于追踪或管理
如果iptables 中有DNAT 规则将数据量转发到容器,所以在宿主机里执行netstat /ss 才导致看不到对应的端口
在宿主机上执行 netstat 或 ss 命令时看不到容器端口的原因,确实与 iptables 中的 DNAT 规则有关
网络流量处理流程外部请求到达宿主机: 当外部请求(如访问6379端口)到达宿主机时,数据包首先到达网络接口。内核处理: 数据包进入Linux内核,经过网络协议栈的不同层次(链路层、网络层和传输层)。iptables 规则匹配: 数据包在到达应用层之前,会经过 iptables 的规则匹配。iptables 是在内核空间中管理网络流量的工具,使用 netfilter 框架。 如果存在 DNAT 规则(如将6379端口的流量转发到容器的6379端口),内核会将流量的目标地址修改为容器的IP地址。 数据包转发: 修改后的数据包被转发到目标容器的网络命名空间。容器内部的服务(如Redis)会接收这个流量。 容器内部处理: 容器内部的服务处理请求并生成响应。响应数据包会通过宿主机的网络栈返回。为什么 netstat 或 ss 无法查看端口网络命名空间隔离: 容器使用网络命名空间来隔离网络环境,因此在宿主机上执行 netstat 或 ss 命令时,无法看到容器内部的端口状态。容器的网络栈与宿主机的网络栈是分开的DNAT 规则的影响:由于有 DNAT 规则将流量转发到容器,宿主机的6379端口实际上并不直接监听来自外部的流量。即使在宿主机上有流量通过6379端口,netstat 和 ss 也不会显示这个端口,因为它的流量已经被重定向到容器。流量处理顺序:iptables 规则在数据包到达应用层之前处理数据包,因此它们的匹配和处理优先于 netstat 和 ss 的查询。这意味着,如果数据包在 iptables 规则中被处理或修改,宿主机的网络状态将无法反映出容器的端口状态在宿主机上执行 netstat 或 ss 时无法查看到容器的6379端口,是因为:
容器和宿主机的网络命名空间隔离,导致宿主机无法直接查看容器内部的端口状态。DNAT 规则的作用,使得流量在到达容器之前被修改和转发,宿主机上6379端口的流量并不直接与宿主机的网络状态相对应。要查看容器内部的端口状态,您需要进入容器内部执行相应的命令