Docker07-docker网络
网络模型
CNM(Container Network Model)
- CNM 是 Docker 提出的容器网络模型,旨在标准化和简化容器网络的管理。
- CNM 定义了一种通用的网络模型和 API,允许各种网络插件集成到 Docker 中,从而支持不同的网络实现方式。
- CNM 提供了一个统一的接口,使得不同的网络插件可以通过相同的方式与 Docker 集成。
CNM 的核心组件包括:
- 网络(Network):抽象出一个连接点,类似于传统网络中的子网。
- 端点(Endpoint):连接容器到网络的接口。
- 控制器(Controller):管理网络和端点的生命周期。
CNI(Container Network Interface)
- CNI 是由 CNCF(Cloud Native Computing Foundation 云原生计算基金会)维护的一个标准接口,用于配置 Linux 容器的网络。
- CNI 的目标是为容器网络提供一个简单、灵活和可扩展的接口,允许各种网络插件配置容器网络。主要面向 Kubernetes 等容器编排系统。
CNI 主要由以下部分组成:
- CNI 规范:定义了网络插件的标准接口,包括如何配置和删除网络。
- CNI 插件:实际实现网络功能的程序,如 Flannel、Calico 等。
- CNI 最初是为 Kubernetes 设计的,但由于其灵活性和广泛支持,现在也被其他容器编排系统所采用。
libnetwork
- libnetwork 是 Docker 基于 CNM 实现的原生网络库(将Docker的网络功能从Docker核心代码中分离出去,用Go语言实现的一个独立库),旨在为 Docker 提供网络驱动的实现。
- 它基于 CNM 规范,提供了一组 API 供 Docker 使用。libnetwork 支持多种网络驱动,包括 bridge、overlay、macvlan 等,通过这些驱动,libnetwork 可以满足不同的网络需求。
单机容器间通信
默认桥接网络(Bridge Network)
将容器加入到同一个网段中可以进行通信
docker network connect my_netwoer container_name # 将容器连接到自定义网络
docker network connect bridge container_name # 将容器连接到默认网络
docker --link 选项
docker run -d -P --name webapp --link db:db nginx
--link name:alias # name是要连接的容器名,alias是这个连接的别名
Docker通过两种方式为容器公开连接信息:环境变量和/etc/hosts文件
使用env命令来查看web容器的环境变量:
docker run -d -P --name webapp2 --link db:db nginx env
跨主机的容器间通信
容器访问外部网络--NAT
- 确认主机的端口转发是否开启,sysctl net.ipv4.ip_forward=1
- 检查docker daemon 启动选项,--ip-forward=true,重新设置为true后需重启docker
SNAT 源地址转换
如果docker0收到来自172.17.0.0/16网段的外出包,进行MASQUERADE处理
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
外部网络访问容器--端口映射
使用 -p 可以将主机上的端口映射到容器内部端口
# 启动一个 Nginx 容器并将主机的 8080 端口映射到容器的 80 端口
docker run -d -p 8080:80 nginx
# 只希望绑定到特定的 IP 地址
docker run -d -p 127.0.0.1:8080:80 nginx
另外可以在 Docker Compose 文件中,可以通过 ports 配置端口映射
version: '3'
services:
web:
image: nginx
ports:
- "8080:80"
外部网络访问容器--使用 Host 网络模式
- 直接使用主机的网络栈,可以使用 --network host 选项
- 容器将直接使用主机的网络接口和 IP 地址,端口不再需要映射
- 只适用于linux平台
docker run -d --network host nginx
外部网络访问容器--配置防火墙和安全组
- 确保主机的防火墙规则允许外部访问到 Docker 映射的端口
- 如果在云环境中运行,还需配置安全组或网络 ACL 以允许相应的入站流量
容器与主机间的通信
-
端口映射
-
使用 Host 网络模式
-
使用卷共享文件系统
docker网络模式
1、bridge模式,--net=bridge(默认,可省略)
2、host模式,--net=host
3、container模式,--net =container:指定容器名
4、none模式,--net=none
5、overlay
overlay
Docker原生的跨主机多子网模型
底层需要etcd这样的KV存储系统进行消息同步,核心是通过linux网桥与vxlan隧道实现跨主机划分子网
每创建一个网桥,Docker会在主机上创建一个沙盒(实质是Network Namespace),在沙盒中创建名为br0的网桥,在网桥上增加vxlan接口。vxlan接口有一个ID号(256-1000),相同ID号的vxlan可以通信。当添加一个容器到某网络上时,Docker会创建一对veth pair,一端接br0网桥,一端接容器的Network Namespace,并将br0的IP设为容器的网关,实现容器加入网络的目的
Docker创建的沙盒保存在/var/run/docker/netns/46acfc9bbb77
ln -s /var/run/docker/netns/46acfc9bbb77 /var/run/netns/46acfc9bbb77
ip netns exec 46acfc9bbb77 ip addr show
bridge
Docker的NAT网络模型
Docker网络的默认模式,Docker daemon启动时,会创建docker0网桥
容器启动时,Docker会创建一对veth pair(虚拟网络接口)设备,它的特点是成对出现,从一端进入的数据会同时出现在另一端
Docker会将一端挂载到docker0网桥上,另一端放入容器的Network Namespace
默认子网 172.17.42.1/16
ip addr show docker0
route -n
brctl show
host
与主机共享Network Namespace,容器不会创建自己的网卡,配置IP等,而是使用宿主机的IP和端口。而文件系统和进程列表还是和宿主机隔离,不安全
docker run -it --net=host nginx:latest bash
容器的网络配置信息与所在的主机完全相同。容器可以操纵主机的网络配置。
如果重复运行一个容器,并使用相同端口,则不可行,因为端口被占用
container
与另一个运行中的容器共享network namespace,容器不会创建自己的网卡,配置IP等,而是使用指定容器的IP和端口。两个容器的文件系统和进程列表还是隔离的
将容器B运行在容器A的网络模式上,容器A使用briage网络模式
docker run --net=container:containerA -itd --name=containerB busybox
如果用docker network inspect bridge查看bridge网络,不会看到容器containerB运行在该网络
连上containerB看看网络信息,发现containerB和containerA的网络接口信息完全相同,说明两个容器共享一个网卡eth0
none
docker不会为容器配置网卡和IP,需要我们自行配置网卡和IP
docker run -it --net=none nginx ip addr show
此模式下创建的不会创建网络,容器里只有lo口
此模式的容器不能互相通信,或与外部通信
用户仍然可以手动配置网络,若想使用pipework手工配置指定docker容器的ip地址,必须要在none模式下才可以
docker网络创建过程
Docker 创建一个容器的时候,会具体执行如下操作:
- 创建一对虚拟接口,分别放到本地主机和新容器的命名空间中。
- 本地主机一端的虚拟接口连接到默认的docker0网桥或指定网桥上,并具有一个以veth开头的唯一名字,如veth1234。
- 容器一端的虚拟接口将放到新创建的容器中,并修改名字作为eth0。这个接口只在容器的命名空间可见。
- 从网桥可用地址段中获取一个空闲地址分配给容器的eth0(例如172.17.0.2/16),并配置默认路由网关为 docker0 网卡的内部接口docker0的IP地址(例如172.17.42.1/16)。
自定义网络模型
# 创建一个自定义桥接网络 docker03 并指定子网和桥接接口名称
docker network create docker03 --subnet=172.30.0.0/16 -o com.docker.network.bridge.name=docker03
--subnet=172.30.0.0/16: 指定网络的子网。
-o com.docker.network.bridge.name=docker03: 指定桥接接口的名称为 docker03。
# 在 docker01 网络中运行一个 nginx 容器并映射端口
docker run -itd --network=docker01 -p 8080:80 nginx
# 创建另一个自定义网络 docker02 使用桥接驱动
docker network create --driver bridge docker02
--driver bridge: 使用桥接网络驱动程序
网络相关参数
-b BRIDGE or --bridge=BRIDGE 指定容器的网桥
--bip=CIDR 定制 docker0 的掩码
-H SOCKET... or --host=SOCKET... 指定Docker服务端接收命令的通道
--icc=true|false 是否支持容器之间进行通信
--ip-forward=true|false 启用net.ipv4.ip forward,即打开转发功能
--iptables=true|false 禁止Docker添加iptables 规则
--mtu=BYTES 指定容器网络中的 MTU
# 以下2个选项可在docker服务启动时指定,也可在docker run时指定。后者会覆盖前者
--dns=IP_ADDRESS... 使用指定的DNS服务器
--dns-search=DOMAIN... 指定 DNS 搜索域
# 以下选项只能在docker run 执行时使用
-h HOSTNAME or --hostname=HOSTNAME 配置容器主机名。
--link=CONTAINER_NAME:ALIAS 添加到另一个容器的连接
--net=bridge|none|container:NAME_or_ID|host 配置容器的桥接模式
-p SPEC or publish=SPEC 映射容器端口到宿主主机。
-P or --publish-all=true|false 映射容器所有端口到宿主主机。
docker network list 列出所有 Docker 网络
docker network inspect docker01 显示 docker01 网络的详细信息
veth-pair
用于两个命名空间的通信
# 创建两个命名空间
ip netns add red
ip netns add blue
# 创建一个veth-pair(包括veth-red veth-blue两张虚拟网卡)
ip link add veth-red type veth peer name veth-blue
# 将两个虚拟网卡分别放入对应的命名空间
ip link set veth-red netns red
ip link set veth-blue netns blue
# 给两个虚拟网卡分别设置IP
ip netns exec red ip addr add 192.168.15.1/24 dev veth-red
ip netns exec blue ip addr add 192.168.15.2/24 dev veth-blue
# 启动两个虚拟网卡
ip netns exec red ip link set dev veth-red up
ip netns exec blue ip link set dev veth-blue up
# 在red命名空间中ping另一个命名空间
ip netns exec red ping 192.168.15.2
相关命令
ip link # 查看网络接口
arp # 查看arp表
ip netns add red # 在linux中创建命令空间
ip netns # 查看命名空间
ip netns exec red ip link # 查看命名空间red中的网络接口
ip netns exec red arp # 查看命名空间red中的arp表
linux bridge
有更多命名空间时,需要将命名空间两两相连,配置繁琐,所以需要创建一个虚拟交换机,用于连接不同的命名空间。
可以通过linux bridge或open vswitch
# 在主机中创建一个bridge
ip link add br0 type bridge 或者 brctl addbr br0 (yum install bridge-utils)
# 启动网桥
ip link set dev br0 up
# 创建veth-pair,一端连接网桥,一端连接命名空间的虚拟网卡
ip link add veth-red type veth peer name veth-red-br
ip link add veth-blue type veth peer name veth-blue-br
ip link add veth-green type veth peer name veth-green-br
# 将veth-pair一端放入命名空间,一端放入bridge,并启动(其他命名空间同理)
ip link set veth-red netns red
ip link set veth-red-br master br0
ip link set veth-red-br up
# 给命名空间的虚拟网卡设置IP,并启动(其他命名空间同理)
ip netns exec red ip addr add 192.168.15.1/24 dev veth-red
ip netns exec red ip link set dev veth-red up
# 在red命名空间中ping另一个命名空间
ip netns exec red ping 192.168.15.2
overlay
为支持容器跨主机通信,Docker提供了overay driver,使用户可以创建基于 VxLAN 的overlay 网络。VxLAN 可将二层数据封装到 UDP 进行传输,VxLAN 提供与 VLAN 相同的以太网二层服务,但是拥有更强的扩展性和灵活性。
overlay网络的具体实现
docker会为每个overlay网络创建一个独立的 network namespace,其中会有一个 linux bridge br0,endpoint 还是由 veth pair 实现,一端连接到容器中(即 eth0),另一端连接到namespace的br0上。br0 除了连接所有的 endpoint,还会连接一个 vxlan 设备,用于与其他host建立 vxlan tunnel。容器之间的数据就是通过这个tunnel 通信的。逻辑网络拓扑结构如图所示。
macvlan
- macvlan 允许为每个容器分配一个唯一的 MAC 地址,并将其直接连接到物理网络。这使得每个容器都可以作为一个独立的网络设备出现在网络上,就像物理机一样。
- macvlan本身是linxukerel 模块,其功能是允许同一个物理网卡配置多个 MAC 地址,即多个 interface,每个interface 可以配置自己的IP。
- macvlan 的最大优点是性能极好,相比其他实现,macvlan不需要创建Linux bridge,而是直接通过以太interface连接到物理网络
macvlan的工作模式
桥接模式(Brigde Mode)
- MACVLAN 最常用的模式。每个虚拟设备都像一个物理设备一样连接到同一个网络桥。
- 在这种模式下,MACVLAN 子接口会有一个唯一的 MAC 地址,并直接连接到物理网络。
- 网络流量在虚拟设备和物理网络之间直接转发。
- 适用于需要高性能和低延迟的场景。
- 缺点是如果父接口故障,所有Macvlan子接口会跟着故障,子接口之间也将无法进行通信
私有模式(Private Mode)
- 私有模式下,同一物理接口上的 MACVLAN 虚拟设备不能相互通信,它们只能与外部网络通信。
- 这种模式适用于需要强隔离的环境,如多租户环境中的网络隔离。
- 增强了安全性,避免了虚拟设备之间的直接通信。
虚拟局域网模式(VEPA Mode)
- 虚拟以太网端口聚合器(Virtual Ethernet Port Aggregator, VEPA)模式
- 允许 MACVLAN 虚拟设备通过物理交换机进行通信。
- 所有流量都会发送到物理交换机,然后再由交换机进行转发,包括虚拟设备之间的通信。
- 这种模式可以利用物理交换机的安全性和隔离特性。
源模式(Source Mode)
- 在源模式下,MACVLAN 设备可以与同一物理接口上的其他 MACVLAN 设备进行通信。
- 这与私有模式相反,允许更多的内部通信。
- 适用于需要容器或虚拟机之间通信但仍需要一些隔离的场景。
直通模式(Passthrough Mode)
- 主模式下,物理接口只会完全暴露给一个 MACVLAN 设备,其他虚拟设备无法使用该接口。
- 适用于需要直接访问物理网络的场景,如某些网络设备或虚拟机。
使用 macvlan 驱动的实际应用
在 macvlan 模式下,实现不同主机上容器间的通信,通常需要两台主机上的物理网络接口处于同一二层网络(如同一VLAN)内,并且这些接口能够互相通信。在这种情况下,可以不使用网桥,但仍需确保物理网络层的配置正确。以下是具体步骤:
主机1:
物理网络接口:enp0s8
子网:192.168.10.0/24
容器网络:192.168.10.0/24
主机2:
物理网络接口:enp0s9
子网:192.168.10.0/24
容器网络:192.168.10.0/24
步骤1:两台主机开启混杂模式
sudo ip link set enp0s8 promisc on
sudo ip link set enp0s9 promisc on
步骤2:配置 macvlan 网络
在主机1上创建 macvlan 网络
docker network create -d macvlan \
--subnet=192.168.10.0/24 \
--gateway=192.168.10.1 \
-o parent=enp0s8 macvlan_net
在主机2上创建 macvlan 网络
docker network create -d macvlan \
--subnet=192.168.10.0/24 \
--gateway=192.168.10.1 \
-o parent=enp0s9 macvlan_net
步骤3:运行容器并连接到 macvlan 网络
在主机1上启动容器
docker run -itd --name container1 --network macvlan_net busybox
在主机2上启动容器
docker run -itd --name container2 --network macvlan_net busybox
步骤4:验证容器间的通信
在 container1 中,ping container2 的 IP 地址:
docker exec -it container1 ping <container2-ip-address>
注意
1.确保两台主机的物理网络接口连接到同一个二层网络(如同一个交换机或VLAN)
2.确保容器 IP 地址不冲突。可以使用 DHCP 或手动分配 IP 地址(--ip=192.168.xx.xx)
3.确保没有防火墙规则阻止两个子网之间的通信
4.主机的网段和容器的子网可以不相同
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)