当前位置: 首页 > news >正文

深入解析Docker网桥模式:从docker0到容器网络的完整通信链路

1. 简介docker 网桥模式

在这里插入图片描述
Docker 启动时默认创建 docker0 虚拟网桥(Linux bridge),并分配私有 IP 地址范围(如 172.17.42.1/16),它的作用相当于一个虚拟交换机,让宿主机和多个容器之间可以通信。

Docker 创建容器时,会分配一对虚拟以太网设备(veth pair),一端放在容器内(通常命名为 eth0)另一端连接到 docker0 网桥,Docker 会从子网中为容器分配一个 IP 地址,容器内的默认网关设置为 docker0 的 IP 地址,通过 iptables 设置 NAT 规则实现容器与外部网络通信。

2. 采用网桥模式创建redis容器

docker run -d --name redis -p 6379:6379 redis:6.2.5

ps: 网络模式默认就是网桥模式

3. 分析docker0 与容器的网卡映射关系

查看redis容器的网卡:

docker exec -it 450b2337fc1c  ip addr

输出如下:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever
256535: eth0@if256536: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0valid_lft forever preferred_lft forever

可以看到容器网卡接口索引是256535:网卡名称是:eth0,@if256536表示这个网卡接口的对端接口索引是256536

执行以下命令,查找接口索引为256536的网卡接口:

ip link | grep 256536

输出如下:

256536: veth4a50f5e@if256535: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default 

这里,256536是宿主机上,虚拟网卡 veth4a50f5e 接口的接口索引;veth4a50f5e 是宿主机端的 veth 接口名称;@if256535 表示这个接口的对端接口索引是 256535(即容器内的 eth0 的接口索引)。

执行以下命令查看连接到docker0的虚拟网卡接口:

ip link show master docker0

得到如下输出:

256536: veth4a50f5e@if256535: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether 02:ac:01:6c:71:d8 brd ff:ff:ff:ff:ff:ff link-netnsid 0

这里,veth4a50f5e 就是连接到docker0的虚拟网卡接口

4. 分析 iptables 转发规则

iptables-save -t nat

输出如下:

-A DOCKER ! -i docker0 -p tcp -m tcp --dport 6379 -j DNAT --to-destination 172.18.0.2:6379

这条规则的意思是:把所有 不是从 docker0 网卡 进入、目标端口为 6379 的 TCP 流量,重定向到容器 IP 172.18.0.2 的 6379 端口。

为什么加 ! -i docker0?这相当于只处理来自“外部(宿主机或外网)”的流量,而不是容器内部之间的通信。如果不加 ! -i docker0,Docker 容器之间通信也会被错误重定向,可能导致死循环或转发混乱。通过排除 docker0 网卡,确保这条规则只匹配从宿主机外部来的连接请求(例如本地开发机访问 localhost:6379)。

5. 分析docker-proxy 代理

执行以下命令看宿主机上的 6379 端口所属进程:

netstat -tulnp | grep 6379

输出如下:

tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      20010/docker-proxy  
tcp6       0      0 :::6379                 :::*                    LISTEN      20015/docker-proxy  

其中,pid为20010,进程名为docker-proxy的进程监听ipv4的6379端口, pid为20015,进程名为docker-proxy的进程监听ipv6的6379端口,

查看进程20010的命令行参数:

ps -ef  |grep 20010

输出如下:

root     20010 27367  0 21:27 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 6379 -container-ip 172.18.0.2 -container-port 6379

这个结果的意思是:
Docker 启动了一个代理程序 docker-proxy,它监听宿主机的 0.0.0.0:6379,并将所有进入该端口的 TCP 流量转发到容器内的 172.18.0.2:6379。

查看进程20015的命令行参数:

ps -ef  |grep 20015

输出如下:

root     20015 27367  0 21:27 ?        00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 6379 -container-ip 172.18.0.2 -container-port 6379

这个结果的意思是:

Docker 启动了一个代理程序 docker-proxy,它监听宿主机的 :::6379,并将所有进入该端口的 TCP 流量转发到容器内的 172.18.0.2:6379。

6. 从外部进入容器的流量是通过docker-proxy还是iptables的DNAT?

docker-proxy 和 iptables 都可以实现流量转发到容器,那么从外部进入容器的流量是通过docker-proxy还是iptables的DNAT呢?
这取决于 Docker 的网络配置和系统环境:现代 Docker(默认)主要使用的是 iptables DNAT,而 docker-proxy 是作为某些场景的补充或兼容机制存在,比如容器需要访问宿主机本身的公开端口(特殊回环场景),或者某些旧版 Docker 或特殊配置下作为备用路径。

7. 分析容器网络空间

查看redis容器内的进程:

docker top redis

输出如下:

UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
polkitd             20048               20029               0                   21:27               ?                   00:00:00            redis-server *:6379

查看容器进程命令行参数:

ps -ef  |grep 20015

输出如下:

polkitd  20048 20029  0 21:27 ?        00:00:01 redis-server *:6379

进入redis容器网络空间:

nsenter -t $container_pid -n /bin/sh

ps : container_pid 即 20048

执行命令:

netstat -tunlp

输出如下:

sh-4.2# netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      20048/redis-server  
tcp6       0      0 :::6379                 :::*                   LISTEN      20048/redis-server 

可以发现在容器的网络空间中,可以查看容器启动的进程监听的端口,而在宿主机上则看不到。这是因为在 Docker 容器中,每个容器默认会被分配一个独立的网络命名空间,容器内的所有进程共享同一个网络命名空间。

8.分析宿主机与容器之间的通信过程

在这里插入图片描述
在这里插入图片描述

http://www.xdnf.cn/news/976069.html

相关文章:

  • TBrun测试工具使用教程(Windows)
  • R语言缓释制剂QBD解决方案之一
  • 开源项目实战学习之YOLO11:12.9 ultralytics-models-sam-amg.py
  • 如何选择合适的IP轮换周期
  • 建筑末端配电回路安全用电解决方案:筑牢电气防火最后一道防线
  • 句法分析 自然语言处理
  • thinkphp ThinkPHP3.2.3完全开发手册
  • React前端框架学习
  • 腾讯云TVP走进泸州老窖,解码AI数智未来
  • 机器学习与深度学习19-线性代数02
  • 青少年编程与数学 01-011 系统软件简介 14 Foxpro数据库
  • 【从零开始学习JVM | 第六篇】运行时数据区
  • 使用Apache POI操作Word文档:从入门到实战
  • 【android bluetooth 框架分析 04】【bt-framework 层详解 2】【如何配置和启动蓝牙profile服务】
  • 【多线程初阶】详解线程池(下)
  • PROFINET主站(M580)通过网关访问CANopen从站(NJ系列)的技术解析
  • 深度强化学习 | 详细推导随机/确定性策略梯度定理
  • Flutter setState() 状态管理详细使用指南
  • 使用 C/C++、OpenCV 和 Libevent 构建联网人脸识别考勤系统 [特殊字符]‍[特殊字符]
  • 电机控制基础,小白入门篇
  • 第三章支线六 ·数据幻域 · 状态管理与数据流
  • Android 默认第三方app运行权限(android11-13)
  • 小程序 UI 设计,怎样在方寸间实现高效交互
  • Fastapi + vue3 自动化测试平台(6):AI + Web UI的完美结合
  • 把下载的ippicv.tgz放入<opencv_build_dir>/3rdparty/ippicv/download/中cmake依然无法识别
  • 快速了解JVM的GC历史
  • 【Lua热更新知识】学习三 XLua学习
  • 【AI 时代,食品科技远未触及天花板,新一轮颠覆性突破正在酝酿】
  • 神舟笔记本Control Center无法打开风扇设置
  • Web 架构之服务网格(Service Mesh)实战解析