容器的网络实现
上网的要素:
每个容器都有自己的IP地址,、网关(路由)、DNS
容器中的主机名----->容器数据目录下的hostname文件
容器中的DNS---->容器数据目录下的resolv.conf文件
容器中的hosts---->容器数据目录下的hosts文件
如何上网的:默认采用bridge的网桥访问外网
每个容器在启动时,都会创建一组veth对(虚拟网卡对),这一组虚拟网卡,一端接入到容器中成为eth0的容器网卡,一端接入到docker0的网桥上,同时容器将网关地址指向docker0的网桥地址,所有的流量都会发送到docker0的网桥,docker的网桥根据NAT规则(通过iptables进行配置的)将其转发到物理网卡,进行外部网络的访问
Docker支持的网络模式
Bridge网络模式(桥接)
#查看具体的网桥配置
Docker network inspect bridge
Docker network ls
#创建桥接网络
docker network create zgs --subnet 172.17.0.0/24 --gateway 172.17.0.254
#将桥接网络设置为指定容器网络
Docker run -d -it --network zgs nginx:latest
#需要被外部访问到服务
Docker run -d -it --network zgs -p 主机端口:容器端口 nginx:latest
##容器之间互相访问
docker run -d -it --name demo03 --link demo01:test busybox:latest
--link demo01:test 已存在容器的名称:别名
配置完成后,即可通过名称或者是别名访问demo01的容器
性能开销
与 host 模式相比,Bridge 模式需要经过一层虚拟网桥和 NAT,这会引入轻微的网络性能开销。对于需要极致网络性能的场景(如高频交易),这可能是个问题。
复杂的网络配置
与简单的 host 模式相比,Bridge 网络的配置更复杂,涉及端口映射、网络创建和管理等概念,对新手来说学习曲线稍陡。
默认桥接网络的局限性
容器间通信依赖 IP 地址:
在默认的 bridge 网络上,容器不能通过容器名进行通信,必须使用 --link(不推荐)或直接使用 IP 地址,这非常不灵活。
自动化的缺失:
默认桥接网络不支持自动的 DNS 服务发现、自定义的 DNS 配置和容器连接/断开时的动态更新。
端口冲突
当多个容器都需要映射到宿主机的同一个端口时(例如,两个 Web 服务器都想使用宿主机的 80 端口),会发生端口冲突,需要管理员手动协调。
NAT 带来的复杂性
由于容器位于 Docker 的内部网络中,外部流量需要通过宿主机的 IP 和端口进行 NAT 转换。这有时会使网络流量路径变得不直观,尤其是在进行网络排障或设置防火墙规则时。从容器内部发起的连接,其源 IP 地址对于外部服务来说是宿主机的 IP,而不是容器的 IP。
Host网络模式
复用宿主机网络
在docker中,host模式是docker安装是默认创建的,不能用户认为定义,用来复用宿主机的网络,将容器设置为host模式后,容器的主机名将使用物理机的主机名,容器的hosts文件将使用物理机的hosts文件,因此可以像物理机一样去访问外部网络,并且在物理机中可以查询到容器内需要访问网络的进程
示例:
Docker run -it --network host nginx:latst
应用场景:
容器内的应用需要提供服务,被外部网络访问,并且需要较好的网络性能(外部网络直接访问),因此对比于bridge的桥接网络,该网络性能更好
None网络模式
容器没有网卡
如果容器使用该网络模式,则容器将不会创建网卡,也就是在容器有lo的回环接口,仅供测试使用,因此使用该模式的容器,不需要网络访问
让两个同处于none网络模式下的容器,可以共享一个网络命名空间,则共享命名空间的容器,可以用过127.0.0.1访问到被共享的容器
docker run -it --name by02 --network none --link container:by01 busybox:latest sh
container:by01 #表示共享by01容器的网络命名空间,也就是可以通过127.0.0.1访问到by01,需要注意在使用是避免端口冲突
Macvlan网络模式
macvlan可以用来解决容器跨主机访问的问题,通过给每个容器配置不同且唯一的mac地址,让容器可以直连到物理网络,得到物理网络子网的IP地址,使用物理网络进行跨主机节点之间的访问
原理
Docker的macvlan驱动允许你为每个容器分配一个唯一的MAC地址,并将其直接连接到主机的物理网络接口。容器在网络中表现为“独立的主机”,可以直接从物理网络获取IP地址,并与网络中的其他设备通信
基本原理是:
在宿主机的物理网卡上创建一个虚拟子接口(macvlan类型)
容器通过该子接口与外部通信,而不是使用NAT或桥接
该网络完全绕过宿主机的网络协议栈,具备更强的隔离性
特点
1、每个容器拥有独立IP(可被外部设备直接访问)
2、容器之间通过物理网络通信,不走docker默认的虚拟网络
3、容器与宿主机默认不能互通
4、适合需要“真实主机网络身份”的容器
5、性能高,无需端口映射,接近物理设备通信效率
应用场景
1. 运行需要被局域网内设备直接访问的容器(samba、ftp、dhcp、mqtt等)
2. 需要隔离容器网络但又要能让其访问物理网络的场景
3. 容器话传统应用时希望继续使用静态IP
4. 在物理网络中直接暴露容器服务而非通过NAPT或端口映射
5. 隔离容器和物理机的访问(保证安全)
配置方法
A节点
#创建macvlan网络
docker network create -d macvlan --subnet 192.168.135.0/24 --gateway 192.168.135.2 -o parent=ens160 mac-zgs
#创建容器进行测试
docker run -itd --name mac01 --network mac-zgs --ip 192.168.135.22 busybox:latest
#进入容器
/ # ping 192.168.135.33
PING 192.168.135.33 (192.168.135.33): 56 data bytes
64 bytes from 192.168.135.33: seq=0 ttl=64 time=0.558 ms
64 bytes from 192.168.135.33: seq=1 ttl=64 time=0.463 ms
B节点
#创建macvlan网络
docker network create -d macvlan --subnet 192.168.135.0/24 --gateway 192.168.135.2 -o parent=ens160 mac-zgs
#创建容器进行测试
docker run -itd --name mac02 --network mac-zgs --ip 192.168.135.33 busybox:latest
#进入容器
/ # ping 192.168.135.22
PING 192.168.135.22 (192.168.135.22): 56 data bytes
64 bytes from 192.168.135.22: seq=0 ttl=64 time=0.690 ms
64 bytes from 192.168.135.22: seq=1 ttl=64 time=0.610 ms
解决容器与宿主机的网络互通
在使用macvlan模式,因为容器复用了宿主机的网卡,当容器的流量达到物理机网卡时,物理网卡的mac地址和物理机自身IP的mac地址是同一个地址,linux内核会进行阻断,因此macvlan模式,容器和物理机默认不能通信,需要配置macvlan的子接口给到物理机使用,来访问容器
配置:
ip link add mac0 link ens160 type macvlan mode bridge

ip addr add 192.168.135.100/24 dev mac0
ip link set up mac0

这个时候,容器ping 192.168.135.100可以通信
删除:
ip link delete mac0
二层隔离机制
macvlan创建虚拟接口直接绑定物理网卡
相同mac地址的通信在二层被阻止(防止网络环路)
宿主机和容器共享一个物理网卡,但linux内核会阻止相同的MAC层设备的直接通信,也就是说容器和物理机都使用同一个物理网卡通信时,被linux内核阻止
注意事项
1、同一个macvlan网络下的容器与外部设备可以互相通信(默认和宿主机不可以互相通信)
2、多个容器需确保IP地址不冲突,且不被DHCP分配
3、交换机需要支持混杂模式,macvlan,使用虚拟mac进行通信,每个容器都是用单独虚拟mac
4、Parent网卡不能是虚拟接口(docker0或br-XXX),必须是真正的物理接口
Ipvlan网络模式
在某些网络中,物理网络对mac地址进行了管控,如果采用不同的mac可能会触发策略,导致不能访问网络,因此ipvlan的出现,就是为了让容器复用宿主机的mac地址来进行通信
原理
Ipvlan是linux提供的一种轻量级虚拟网络接口类型,docker通过它可以为容器分配和宿主机同一网段的IP地址,与macvlan相似
Ipvlan并不会为每个接口分配独立的MAC地址,而是复用宿主机的MAC地址
工作模式:
L2模式(默认):与macvlan类似,通过二层广播通信
通过共享宿主机的mac地址,来进行二层通信
L3模式:只通过IP(第三层)路由通信,无需二层桥接
通过ip路由,将不同主机上的docker子网打通,实现容器间通信
特点
IP独立 每个容器有独立IP,与宿主机同网段
MAC复用 所有容器复用宿主机网卡的MAC地址,适合对MAC限制严格的网络环境
容器与主机通信 默认无法通信
性能优秀 比macvlan更少的资源开销(无虚拟MAC)
L3模式支持路由 支持跨网段容器间通信,适用于多主机部署场景
应用场景
L2:
1、限制MAC地址数量的局域网中
2、容器需要拥有局域网独立IP的场景
3、不需要复杂路由、但希望容器可被直接访问的场合(直连物理网络)
L3:
1、数据中心或私有云中,有大量容器不俗在多主机,需要跨主机通信,且网络中不允许暴露额外的MAC或VLAN
2、不希望主机直接访问容器,增强安全性
3、容器跨物理主机通信,通过三层路由构建overlay
4、容器用于采集、爬虫、出站服务,不需要被局域网发现
5、内网批量部署轻量级容器服务
配置方法
L2模式:
#创建L2网络
docker network create -d ipvlan --subnet 192.168.135.0/24 --gateway 192.168.135.2 -o parent=ens160 -o ipvlan_mode=l2 ipvlan-l2
#配置容器使用该网络
docker run -itd --network ipvlan-l2 --ip 192.168.135.66 --name test-l2 busybox
L3模式:
A节点
#创建L3网络
docker network create -d ipvlan --subnet 192.168.30.0/24 --gateway 192.168.30.2 -o parent=ens160 -o ipvlan_mode=l3 ipvlan-l3
#配置容器使用该网络
docker run -itd --name ip-l3 --network ipvlan-l3 --ip 192.168.30.88 busybox:latest
#配置容器宿主机网卡
ip link add ipvlan-gw link ens160 type ipvlan mode l3
ip addr add 192.168.30.2/24 dev ipvlan-gw
ip link set up ipvlan-gw
没有配置网关时,容器也可以通信,是因为当容器发包时,目标是192.168.30.2,linux内核并不会像普通bridge那样查mac,而是直接将容器IP发出的IP包,从宿主机物理接口以原始IP包的形式发出去,但是宿主机将无法访问容器(默认场景中,如果不配置网关,容器可以访问物理机,物理机不可以访问容器)
#配置静态路由
ip route add 192.168.40.0/24 via 192.168.135.170
B节点
#创建L3网络
docker network create -d ipvlan --subnet 192.168.40.0/24 --gateway 192.168.40.2 -o parent=ens160 -o ipvlan_mode=l3 ipvlan-l3
#配置容器使用该网络
docker run -itd --network ipvlan-l3 --ip 192.168.40.88 --name ip-l3 busybox:latest
容器互相通信设置:
ip link add ipvlan-gw link ens160 type ipvlan mode l3
ip addr add 192.168.40.2/24 dev ipvlan-gw
ip link set up ipvlan-gw
#配置静态路由
ip route add 192.168.30.0/24 via 192.168.135.160
配置容器可以上网
iptables -t nat -A POSTROUTING -s 192.168.30.0/24 -o ens160 -j MASQUERADE
iptables -I FORWARD -s 192.168.30.0/24 -o ens160 -j ACCEPT
iptables -I FORWARD -d 192.168.30.0/24 -i ens160 -m state --state RELATED,ESTABLISHED -j ACCEPT
Overlay网络模式
Docker的集群专用网络,通过vxlan将各个节点docker物理节点打通,让容器处于一个大二层的网络中,容器本身对docker所在的节点没有网络感知
仅适用于docker swarm的集群,不支持单机版的docker
Docker节点和节点之间采用vxlan的隧道进行通信,将容器的网络信息封装到以太网的数据包中,采用UDP
配置
#初始化一个docker swarm集群
docker swarm init --advertise-addr 192.168.135.160
#添加一个节点到swarm集群(初始化之后,会生成这条命令)
docker swarm join --token SWMTKN-1-2sezwl1v1rry1rm0ay2uapiurmc516dwdwp3fywa0dslni2qal-98ipnc2qwxpnh9n3hoot3b29d 192.168.135.160:2377
#查看节点
docker node ls
#创建overlay网络
docker network create -d overlay --subnet 182.18.0.0/24 --attachable overlay01
--attachable 允许单个容器可以加入overlay网络
#创建容器进行测试
#A节点
docker run -itd --network overlay01 ovy busybox:latest
#B节点
docker run -itd --network overlay01 busybox:latest
overlay模式会创建一个名为docker-gwbridge的网桥,然后将该网桥连同overlay的网络,同时提供给到容器,在容器内采用overlay的隧道网络,进行容器间的互相通信,在容器外,采用docker-gwbridge进行上网和端口映射
#配置手动上网(新版好像没用,可以不做)
iptables -A FORWARD -s 182.18.0.0/24 -j ACCEPT
iptables -A FORWARD -d 182.18.0.0/24 -j ACCEPT
iptables -t nat -A POSTROUTING -s 182.18.0.0/24 ! -d 182.18.0.0/24 -o ens160 -j MASQUERADE
#服务创建
docker service create --name web --replicas 2 --network overlay01 -p 8090:80 nginx:latest
#查看服务
docker service ls
#查看服务详情
docker service ps web