docker 网络
docker网络主要解决如下问题
- 容器与外界通信
- 容器间通讯,跨主机容器间通讯
- 网络隔离(容器网络命名空间、子网隔离)
- 提供网络自定义能力
- 提供容器间发现功能 (dns解析)
- 提供负载均衡能力
docker网络命令
#连接一个容器到一个网络
docker network connect Connect a container to a network
#创建一个网络
docker network create Create a network
#将容器从一个网络中断开
docker network disconnect Disconnect a container from a network
#查看网络的详细信息
docker network inspect Display detailed information on one or more networks
#查看网络列表
docker network ls List networks
#移除所有未使用的网络
docker network prune Remove all unused networks
#移除一个或多个网络
docker network rm Remove one or more networks
常见操作
发布端口
# 将容器中tcp端口80映射到主机8080端口
-p 8080:80
# 将容器中tcp端口80映射到地址192.168.239.154:8080
-p 192.168.239.154:8080:80
# 将容器中的udp端口80映射到主机8080端口
-p 8080:80/udp
# 将容器中的udp端口80映射到主机的udp端口8080
# 将容器中的tcp端口80映射到主机的tcp端口8080
-p 8080:80/tcp -p 8080:80/udp
修改hostname
docker run -d --rm --name mynginx1 -p 8081:80 --hostname mynginx1.test.com
nginx:1.23.4
curl http://localhost:8081
iptables简介
docker安装后会自动设置iptables规则来管理网络流量。这是docker网络核心部分之一
iptables结构
iptables由上而下,由Tables,Chains,Rules组成。
tables与链chains
iptables有Filter, NAT, Mangle, Raw四种内建表:
Filter
Filter是iptables的默认表,它有以下三种内建链(chains):
-
INPUT链 – 处理来自外部的数据
-
OUTPUT链 – 处理向外发送的数据。
-
FORWARD链 – 将数据转发到本机的其他网卡设备上。
NAT表
NAT表有三种内建链:
PREROUTING链 – 处理刚到达本机并在路由转发前的数据包。它会转换数据包中的目标IP地址(destination ip address),通常用于DNAT(destination NAT)。
POSTROUTING链 – 处理即将离开本机的数据包。它会转换数据包中的源IP地址(source ip address),通常用于SNAT(source NAT)。
OUTPUT链 – 处理本机产生的数据包。
Mangle表
Mangle表用于指定如何处理数据包。它能改变TCP头中的QoS位。Mangle表具有5个内建链(chains):
- PREROUTING
- OUTPUT
- FORWARD
- INPUT
- POSTROUTING
Raw表
Raw表用于处理异常,它具有2个内建链:
PREROUTING chain
OUTPUT chain
rules
规则的关键知识点:
Rules包括一个条件和一个目标(target)
如果满足条件,就执行目标(target)中的规则或者特定值。
如果不满足条件,就判断下一条Rules
Target Values
在target里指定的特殊值:
- ACCEPT – 允许防火墙接收数据包
- DROP – 防火墙丢弃包
- QUEUE – 防火墙将数据包移交到用户空间
- RETURN – 防火墙停止执行当前链中的后续Rules,并返回到调用链(the calling chain)中
[root@localhost gpt-data]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destinationChain FORWARD (policy DROP)
target prot opt source destination
DOCKER-USER all -- anywhere anywhere
DOCKER-ISOLATION-STAGE-1 all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhereChain OUTPUT (policy ACCEPT)
target prot opt source destinationChain DOCKER (1 references)
target prot opt source destinationACCEPT tcp -- anywhere 172.17.0.2 tcp dpt:httpChain DOCKER-ISOLATION-STAGE-1 (1 references)
target prot opt source destination
DOCKER-ISOLATION-STAGE-2 all -- anywhere anywhere
RETURN all -- anywhere anywhereChain DOCKER-ISOLATION-STAGE-2 (1 references)
target prot opt source destination
DROP all -- anywhere anywhere
RETURN all -- anywhere anywhereChain DOCKER-USER (1 references)
target prot opt source destination
RETURN all -- anywhere anywhere
网络驱动
bridge 网桥网络
- bridge是docker默认的网络驱动程序。如果没有指定驱动程序,这就是正在创建的网络类型。当应 用程序在需要与同一主机上的其他容器通信的容器中运行时,通常会使用桥接网络。
- 就联网而言,桥接网络是在网段之间转发流量的链路层设备,链路层设备Mac地址进行通信。桥接 器可以是在主机内核运行的硬件设备或者软件设备。
- 就docker而言,网桥网络为软件网桥。允许连接到同一网桥的容器进行通讯,同时提供与未连接到 该网桥的容器的隔离。不同网桥上的容器无法直接通讯。
- 启动docker是,会自动创建一个名为docker0的网桥网络,并且新启动的容器会默认连接到该网络
[root@localhost gpt-data]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242832fe5ed no veth861b463vetha32efdf
默认网桥&&自定义网桥
- 自定义网桥提供容器之间的自动DNS解析,可通过容器名称或别名互相访问,默认网桥网络上的容 器只能通过IP地址互相访问。
- 自定义网桥提供更好的网络隔离,因为所有未指定网络的容器都将连接到默认网桥,而自定义网桥 则必须显示指定容器网络后,方可加入该网络。
- 每个自定义网络都会创建一个可配置的网桥。如果使用默认网桥,对其配置将使得所有容器都使用 相同的设置,此外配置默认网桥发生在docker本身之外,需要重新启动docker。使用docker网络 创建和配置自定义网桥网络,可以在创建是分别对不同的网桥做不同的配置。
使用网桥驱动创建网络options
选项 | 默认值 | 描述 |
---|---|---|
com.docker.network.bridge.name | 创建Linux网桥时要使用的接口名称 | |
com.docker.network.bridge.enable_ip_masquerade | true | 是否启用IP伪装,即将容器的IP地址转换成宿主机的ip地址进行网络访问,从而实现容器访问外部网络的功能,即容器对外部网络访问的权限等同宿主机 |
com.docker.network.bridge.enable_icc | true | 启用或禁用容器间连接(不是DNS解析) |
com.docker.network.bridge.host_binding_ipv4 | 0.0.0.0 | 绑定容器端口时的默认IP |
com.docker.network.driver.mtu | 0(不限制) | 设置容器最大传输单元 |
com.docker.network.container_iface_prefix | eth | 容器接口自定义前缀 |
查看默认网络
docker network ls
查看路由表
route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.74.18.1 0.0.0.0 UG 104 0 0 eth0
10.74.18.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
169.254.0.0 0.0.0.0 255.255.0.0 U 1002 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
所有以172.17开头并且子网掩码为255.255.0.0的IP地址的数据包都会被发送到docker0网桥
查看iptables规则
docker安装后悔自动设置iptables规则来管理网络流量。查看filter表
[root@localhost gpt-data]# iptables -t filter --line-numbers -L -n -v | column -tChain INPUT (policy ACCEPT 10M packets, 2480M bytes)
num pkts bytes target prot opt in out source destinationChain FORWARD (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 2309 8646K DOCKER-USER all -- any any anywhere anywhere
2 2309 8646K DOCKER-ISOLATION-STAGE-1 all -- any any anywhere anywhere
3 1194 8580K ACCEPT all -- any docker0 anywhere anywhere ctstate RELATED,ESTABLISHED
4 0 0 DOCKER all -- any docker0 anywhere anywhere
5 1115 66538 ACCEPT all -- docker0 !docker0 anywhere anywhere
6 0 0 ACCEPT all -- docker0 docker0 anywhere anywhereChain OUTPUT (policy ACCEPT 16M packets, 2444M bytes)
num pkts bytes target prot opt in out source destinationChain DOCKER (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT tcp -- !docker0 docker0 anywhere 172.17.0.2 tcp dpt:httpChain DOCKER-ISOLATION-STAGE-1 (1 references)
num pkts bytes target prot opt in out source destination
1 1115 66538 DOCKER-ISOLATION-STAGE-2 all -- docker0 !docker0 anywhere anywhere
2 2309 8646K RETURN all -- any any anywhere anywhereChain DOCKER-ISOLATION-STAGE-2 (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 DROP all -- any docker0 anywhere anywhere
2 1115 66538 RETURN all -- any any anywhere anywhereChain DOCKER-USER (1 references)
num pkts bytes target prot opt in out source destination
1 2309 8646K RETURN all -- any any anywhere anywhere
- Chain INPUT (policy ACCEPT) :Chain INPUT 是一个默认的过滤链,它决定了进入本地系统的数
据包如何处理。policy ACCEPT 表示该链的默认策略是接受(allow)所有进入的数据包。 - Chain OUTPUT (policy ACCEPT):OUTPUT链用于处理从本地系统发出的数据包。它决定了本地系统发往外部网络的流量如何进行过滤和处理。默认情况下,OUTPUT链的策略是ACCEPT,意味着所有从本地系统发出的数据包都会被允许通过。
- Chain FORWARD (policy DROP):FORWARD链用于处理转发(Forwarding)数据包,即通过本地系统进行转发的数据包。它决定了经过本地系统的数据包如何进行过滤和处理。默认情况下,FORWARD链的策略是DROP,意味着所有经过本地系统的转发数据包都会被丢弃。这样可以确保只有经过明确允许的规则才能进行转发
- Chain DOCKER:DOCKER链用于处理与Docker容器相关的网络流量。它是由Docker自动创建的一个用户定义链(user-defined chain),用于进行NAT(Network Address Translation)和过滤规则。
- Chain DOCKER-USER:DOCKER-USER链是Docker自动创建的另一个用户定义链(user-defined chain),用于处理与Docker容器相关的用户定义规则。
- Chain DOCKER-ISOLATION-STAGE:DOCKER-ISOLATION-STAGE链是Docker自动创建的用户定义链(user-defined chain),用于实现容器网络隔离。
查看iptables nat表规则列表
[root@localhost docker]# iptables -t nat -L -n -v --line-numbers | column -t
Chain PREROUTING (policy ACCEPT 29 packets, 3391 bytes)
num pkts bytes target prot opt in out source destination
1 962 54116 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 21 packets, 1767 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 1 packets, 60 bytes)
num pkts bytes target prot opt in out source destination
1 3 180 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 3 packets, 180 bytes)
num pkts bytes target prot opt in out source destination
1 49 3160 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
2 0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
3 0 0 MASQUERADE tcp -- * * 172.17.0.6 172.17.0.6 tcp dpt:80
Chain DOCKER (2 references)
num pkts bytes target prot opt in out source destination
1 0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
2 27 1620 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8081 to:172.17.0.2:80
3 74 4440 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:82 to:172.17.0.6:80
- -t nat: 指定使用nat表,即网络地址转换表
- -v: 显示详细信息,包括数据包和字节计数
- n: 不进行域名解析,直接显示IP地址
- -L: 列出规则列表
- Chain PREROUTING:(预路由链)是iptables中的一个网络地址转换表(nat表)的链。它用于在数据包到达主机之前进行处理和转发
- Chain POSTROUTING:(后路由链)是iptables中的一个网络地址转换表(nat表)的链。它用于在数据包离开主机之前进行处理和转发。
- 规则解读
Chain POSTROUTING (policy ACCEPT 7697 packets, 516K bytes)pkts bytes target prot opt in out source destination49 3160 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/00 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
表示对于从不在docker0接口上的网络流量(即输出流量),如果源IP地址属于172.17.0.0/16网段,则进行伪装(MASQUERADE),将源IP地址替换为本机的外部IP地址,以实现网络地址转换(NAT)功能。这样可以确保来自172.17.0.0/16网段的数据包能够正确地回应到发起请求的主机
bridge驱动使用案例
启容器
docker run -dit --rm --name alpine1 myalpine ash
docker run -dit --rm --name alpine2 myalpine ash
查看bridge网络
docker network inspect bridge
[{"Name": "bridge","Id": "52c18e3316468f9f14736d495029aa15b63473dbca0818b8ceab3f1d526dbac5","Created": "2023-12-26T11:26:27.150249598+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": [{"Subnet": "172.17.0.0/16","Gateway": "172.17.0.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {"5c35cf3a8315d1477da3cd7693f83444af91d5a846007572cfc0c663c03c12a8": {"Name": "alpine1","EndpointID": "46340efda036eda601504b5ca6928db7a098d3776bc77ff819921485156df026","MacAddress": "02:42:ac:11:00:04","IPv4Address": "172.17.0.4/16","IPv6Address": ""},"d9bd1dac57b716ad763d2cedc57ccb9de63e77074c6a16ba6b672cdec1c0cd1c": {"Name": "alpine2","EndpointID": "fc082c335bb511f9518fa0c15fe717432b8c1b3b81d71e1bd3f6fc79620df7ee","MacAddress": "02:42:ac:11:00:05","IPv4Address": "172.17.0.5/16","IPv6Address": ""}},"Options": {"com.docker.network.bridge.default_bridge": "true","com.docker.network.bridge.enable_icc": "true","com.docker.network.bridge.enable_ip_masquerade": "true","com.docker.network.bridge.host_binding_ipv4": "0.0.0.0","com.docker.network.bridge.name": "docker0","com.docker.network.driver.mtu": "1500"},"Labels": {}}
]
查看系统网络接口,会多出两张veth
ip ad
[root@localhost docker]# ip ad
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 hostvalid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000link/ether fa:16:3e:30:2c:c0 brd ff:ff:ff:ff:ff:ffinet 10.74.18.61/24 brd 10.74.18.255 scope global eth0valid_lft forever preferred_lft foreverinet6 fe80::f816:3eff:fe30:2cc0/64 scope linkvalid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defaultlink/ether 02:42:83:2f:e5:ed brd ff:ff:ff:ff:ff:ffinet 172.17.0.1/16 scope global docker0valid_lft forever preferred_lft foreverinet6 fe80::42:83ff:fe2f:e5ed/64 scope linkvalid_lft forever preferred_lft forever
309: vethf7628d0@if308: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group defaultlink/ether 8a:ab:91:3a:0c:a7 brd ff:ff:ff:ff:ff:ff link-netnsid 2inet6 fe80::88ab:91ff:fe3a:ca7/64 scope linkvalid_lft forever preferred_lft forever
169: veth861b463@if168: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group defaultlink/ether c2:d4:57:7a:85:51 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet6 fe80::c0d4:57ff:fe7a:8551/64 scope linkvalid_lft forever preferred_lft forever
185: vetha32efdf@if184: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group defaultlink/ether e6:4d:1a:49:65:15 brd ff:ff:ff:ff:ff:ff link-netnsid 1inet6 fe80::e44d:1aff:fe49:6515/64 scope linkvalid_lft forever preferred_lft forever
docker0网桥工作原理
默认桥接网络不提供dns解析,容器之间可以通过ip地址相互访问,但不能通过容器名称相互访问。可以使用自定义网络,将容器添加进网络,这样容器间就可以相互使用名字访问了
自定义bridge网络
docker network create --driver bridge nginx-net
运行两个容器
docker run -d -p 8088:80 --network nginx-net --name nginx1 nginx
docker run -d -p 8089:80 --network nginx-net --name nginx2 nginx
# 查看nginx-net
[root@localhost docker]# docker inspect nginx-net
[{"Name": "nginx-net","Id": "b9bc42bfe03ffe38df86dd3b388d8d1ff58c1f8d5614ffe606191427fc6c5288","Created": "2024-01-03T14:47:57.506257705+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": {},"Config": [{"Subnet": "172.18.0.0/16","Gateway": "172.18.0.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {"3d22cf84216493e7fbb3a5ad773b8e77fc750a5aab356a06af083bff59944b5a": {"Name": "nginx2","EndpointID": "3b47ad3fafebebee7acdc0243f0e0f3fac46b3039411fb46c6d62f8e292de6f4","MacAddress": "02:42:ac:12:00:02","IPv4Address": "172.18.0.2/16","IPv6Address": ""},"e9c736a4ca090945fcee290614f491fe1fca5048b2d2b34fd78d878b96e88eba": {"Name": "nginx1","EndpointID": "c2ecc9cecf7e8a1ae8c76fc2027feef1c169c9508a77ca382db63c2efd0362e3","MacAddress": "02:42:ac:12:00:03","IPv4Address": "172.18.0.3/16","IPv6Address": ""}},"Options": {},"Labels": {}}
]
两个容器之间可以使用容器名访问。容器网络,直接访问80端口
[root@localhost docker]# docker exec -it nginx1 bash
root@e9c736a4ca09:/# curl http://nginx2:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p><p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p>
</body>
</html>
将已有容器加入到新的网络
# 将容器 nginx3 加入网络 nginx-net
docker network connect nginx-net nginx3
# 将容器 nginx4 加入网络 nginx-net
docker network connect nginx-net nginx4
# 查看网络详情
docker network inspect nginx-net
从自定义网络中移除所有容器
加入默认网络中的容器无法再不停服的情况下与docker0网桥断开
docker network disconnect nginx-net nginx1
docker network disconnect nginx-net nginx2
docker network disconnect nginx-net nginx3
docker network disconnect nginx-net nginx4
移除网络
docker network rm alpine-net
带option创建自定义网络
docker network create \
--driver=bridge \
--subnet=172.28.0.0/16 \
--ip-range=172.28.5.0/24 \
--gateway=172.28.5.254 \
--opt com.docker.network.bridge.name=nginx-net1 \
--opt com.docker.network.bridge.enable_ip_masquerade=false \ #禁用IP伪装,无法访问外网
--opt com.docker.network.bridge.enable_icc=false \ #禁用容器间通讯
--opt com.docker.network.container_iface_prefix=ethtest \ # 网络接口前缀
nginx-net1
一点问题记录
启动nginx后,外部机器无法访问首页(之前一直没啥问题)。查了下原因是因为ip转发未开启 net.ipv4.ip_forward=0
修改为1即可
sysctl -w net.ipv4.ip_forward=1
Overlay 覆盖网络与vxlan
https://blog.51cto.com/u_14928887/3084685
https://zhuanlan.zhihu.com/p/629065642