Docker之网络通信

一、引言

Docker 安装完成之后会使用 Linux桥接 在宿主机虚拟一个Docker容器网桥( docker0 ),该网桥是每个容器的默认网关,容器会从此网段获得IP地址,称为 container-ip,容器之间能够通过container-ip 直接通信

由于 docker0 网卡是虚拟出来的,所以外部网络无法直接进行通讯,只能通过端口映射来进行访问容器,即通过 -p, -P 参数来启用

二、正文

有四种网络模式

(一)网络模式

网络模式 配置 说明
Bridge --net=bridge 桥接模式,默认
Host --net=host 主机模式,容器和宿主机共享网络
Container --net=容器:NAME/ID 和指定容器共享网络
None --net=none 无网络模式

查看网络

1
2
3
4
5
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
dfcce22b9290 bridge bridge local
73513df83c7c host host local
28621e1b3b45 none null local

Bridge 模式

该模式是 Docker 的 默认网络 设置,当 Docker 服务启动时,会在主机上创建一个名为 docker0 的虚拟网桥,并分配 172.17.0.0/16 网段分配给 docker0 网桥,默认创建的容器也是连接到这个虚拟网桥上

特点

  • 默认为每个容器分配单独的网络空间,彼此相互隔离
  • 每个容器都单独的网卡、路由、IP等一些列基本的网络设施
  • 每个容器启动后,都会被分配一个独立的虚拟IP
  • 该模式会自动,将宿主机上的所有容器,都链接到 ip a 看到的 docker0 的虚拟网卡上
  • 外界主机不能直接访问宿主机内的容器服务,需要宿主机通过 -p 做端口映射后访问宿主的映射端口

查看端口

1
2
3
4
5
$ ip add | grep -A 10 docker0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:e2:0c:c0:f2 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever

拓扑图

kvkasw83.png

演示

指定网络启动

1
2
docker run -itd --net=bridge --name docker1 centos
docker run -itd --net=bridge --name docker2 centos

查看容器网络

1
2
docker exec -it docker1 ip a
docker exec -it docker2 ip a

Host 模式

该模式下容器与宿主机在同一个 Network Namespace 网络空间,使用宿主机的IP,容器内部的服务端口也可以使用宿主机的端口,不需要进行 NAT,不会虚拟出自己的网卡,配置自己的IP等

这种模式的好处就是网络性能比桥接模式的好,点就是会占用宿主机的端口,网络的隔离性不好

特点

  • 没有独立的网络空间
  • 完全和宿主机共用一个网络空间(端口、IP等),所以该模式下的容器不会虚拟出容器自身的虚拟网卡,也不会配置自己的虚拟 IP
  • 除了网络和宿主机共享,其他的资源,如文件系统、进程列表等,容器之间依然是相互隔离的

缺点

同一个端口,比如宿主机的 8080 端口,只能被一个服务占用,如果被某个容器占用了,宿主机就不能用,后续的容器也不能用,直到优先抢到 80 端口的服务,停止提供服务(放弃80端口)

拓扑图

kvkcrxap.png

演示

启动容器

1
docker run -it -d --net=host --name=Nginx1 nginx

测试

1
2
3
4
5
6
7
8
9
10
$ curl --head 192.168.6.128
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 04 Nov 2021 10:49:11 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes

Container 模式

这个模式指定新创建的容器和已经存在的一个容器共享同个 Network Namespace 网络空间,但不会自动创建网卡、配置IP,而是和指定的容器共享 IP、端口范围等,容器之间可以通过 lo 网卡设备通信

特点

  • 新创建的容器,仅同前面已存在的容器,共享网络空间,不与宿主机共享网络
  • 新创建的容器,不会有自己的虚拟网卡和IP,后面新创建容器的网络资源用的是上一个容器的
  • 新创建的容器,仅仅是网络和第一个容器共享,其他资源彼此还都是相互隔离的

缺点

第一个指定容器服务停止,则后续的容器也没有办法继续运行

拓扑图

kvkd80na.png

None 模式

该模式关闭了容器的网络功能,容器会有自己的 Network Namespace 网络空间,但是容器不会配置网络,如IP、路由等信息,需要手动添加

等于断网的状态,经常用于测试,生产环境一般不会用到这种

特点

  • 容器拥有自己的网络空间,但不会进行任何网络配置
  • 容器没有网卡、IP、路由等信息,需要手动添加网卡、配置IP等

拓扑图

kvkcwybb.png

演示

启动容器

1
docker run -it -d --net none --name Docker1 centos

查看网络配置

1
docker exec -it Docker1 ip a 

可见没有网络配置

1
2
3
4
5
$ docker exec -it Docker1 ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever

(二)自定义网络

自定义网络是可以用 ip 或者容器名相互 ping 通的,相当于修复了 docker0 的容器之间无法用容器名相互 ping 通的问题,只能使用 ip 才能 ping

创建网络

创建网络

1
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
选项 注释
–bridge 网络模式桥连接
–subnet 子网络网段
–gateway 路由
–mynet 网络名

查看

1
2
3
4
5
6
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
dfcce22b9290 bridge bridge local
73513df83c7c host host local
b39f65cb8792 mynet bridge local
28621e1b3b45 none null local

查看网络信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$ docker network inspect mynet
[
{
"Name": "mynet",
"Id": "b39f65cb8792ef4010c6bab0a9a39e1b5a7651e2241204685d019ddc87eccd4a",
"Created": "2021-11-04T19:23:49.532855448+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.111.0/24",
"Gateway": "192.168.111.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]

在自己的网段里创建两个容器

创建两个容器

1
2
docker run -it -d --name centos01 --net mynet centos
docker run -it -d --name centos02 --net mynet centos

查看自定义网络信息

1
docker network inspect mynet

可见我们的容器在自己创建的网络当中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[
{
...
"Containers": {
"aca92dfb060391893b3096ae66ca051292589066a8663522e4c7d5c386092c07": {
"Name": "centos02",
"EndpointID": "822265b96d5de90d7775e553b94d2337a3179d995077a504d734cd91f1379f69",
"MacAddress": "02:42:c0:a8:6f:03",
"IPv4Address": "192.168.111.3/24",
"IPv6Address": ""
},
"ec64f1fd5fc7b5287b4ffa4f3bbb80e2178cbb4ef6f3733c27284f84c3f00d97": {
"Name": "centos01",
"EndpointID": "ee22a76a823a026a42f01274ca4a6da1c90bca4f4c4c02cd61e851607f56afbf",
"MacAddress": "02:42:c0:a8:6f:02",
"IPv4Address": "192.168.111.2/24",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}

}
]

相互使用容器名ping测试

互ping

1
2
docker exec -it centos01 ping centos02
docker exec -it centos02 ping centos01

发现是可以 ping 通的

1
2
3
4
5
6
7
8
9
$ docker exec -it centos01 ping centos02
PING centos02 (192.168.111.3) 56(84) bytes of data.
64 bytes from centos02.mynet (192.168.111.3): icmp_seq=1 ttl=64 time=0.174 ms
64 bytes from centos02.mynet (192.168.111.3): icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from centos02.mynet (192.168.111.3): icmp_seq=3 ttl=64 time=0.072 ms
^C
--- centos02 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.066/0.104/0.174/0.049 ms

发现是可以 ping 通的

1
2
3
4
5
6
7
8
9
$ docker exec -it centos02 ping centos01
PING centos01 (192.168.111.2) 56(84) bytes of data.
64 bytes from centos01.mynet (192.168.111.2): icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from centos01.mynet (192.168.111.2): icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from centos01.mynet (192.168.111.2): icmp_seq=3 ttl=64 time=0.066 ms
^C
--- centos01 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.050/0.060/0.066/0.011 ms

跨网段

那如果在创建一个容器不在该网段内如何能和该网段内的容器进行ping吗?

没有加 -net 默认是走 docker0 的网段

1
2
docker run -it -d --name centos03 centos
docker run -it -d --name centos04 centos

互ping

1
docker exec -it centos03 ping centos04

互ping不通

1
2
$ docker exec -it centos03 ping centos04
ping: centos04: Name or service not known

跨网络也是ping不通

1
2
$ docker exec -it centos03 ping centos01
ping: centos01: Name or service not known

结论

  • 在 Docker 中直接 run 创建容器时不加自定义的网络,是 无法使用 容器名 相互ping通的,只能通过IP(通过 docker0 的桥连接相互通信)
  • 我们自己定义好的网络在创建容器时,是可以直接通过容器名相互ping通的

让容器和网络链接

1
docker network connect mynet centos03

链接完成之后再去ping

1
docker exec -it centos03 ping centos01

发现可以ping通了,这是为什么呢?

1
2
3
4
5
6
7
8
9
$ docker exec -it centos03 ping centos01
PING centos01 (192.168.111.2) 56(84) bytes of data.
64 bytes from centos01.mynet (192.168.111.2): icmp_seq=1 ttl=64 time=0.081 ms
64 bytes from centos01.mynet (192.168.111.2): icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from centos01.mynet (192.168.111.2): icmp_seq=3 ttl=64 time=0.068 ms
^C
--- centos01 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4000ms
rtt min/avg/max/mdev = 0.066/0.070/0.081/0.007 ms

原因:一个容器两个ip

1
docker network inspect mynet

kvkfeein.png

这里可以看到 centos03 加入到了 mynet 的网络中了

查看 centos03 容器详细信息

1
docker inspect centos03

kvkfilz1.png

自定义网桥与默认网桥的区别

  • 用户自定义桥可以在容器之间提供自动DNS解析【DNS resolution 】能力。

    默认网桥网络上的容器只能通过IP地址相互访问,除非您使用--link选项,但不推荐。在自定义网桥网络中,容器之间可以通过名称或别名进行解析

  • 用户自定义桥提供了更好的隔离

    • 所有没有指定--network的容器都附加到默认网桥网络。这可能是一个风险,因为不相关的堆栈/服务/容器可以进行通信。
    • 使用用户定义的网桥提供了一个有作用域的网络,其中只有连接到该网络的容器才能进行通信
  • 容器可以动态地连接或断开与用户定义的网桥的连接

    • 在容器的生命周期内,可以动态地连接或断开它与用户定义的网桥的连接。
    • 从默认网桥网络中删除容器,需要停止容器并使用不同的网络选项重新创建它。
  • 每个用户定义的网桥都会创建一个可配置的网桥,默认网桥的配置是全局的

    • 如果容器使用默认网桥网络,则可以配置它,但所有容器都使用相同的设置,例如MTU和iptables规则。此外,配置默认网桥网络发生在Docker本身之外,并且需要重新启动Docker。
    • 用户自定义网桥网络使用docker network create创建和配置。如果不同的应用程序组有不同的网络需求,可以在创建桥接时分别配置每个用户定义的桥接。
  • 连接到默认网桥上的所有容器共享环境变量

    最初在两个容器之间共享环境变量的唯一方法是使用

    1
    --link

    标志将它们链接起来。这种类型的变量共享在用户定义的网络中是不可能的。但是,有更好的方法来共享环境变量,如下:

    • 多个容器可以挂载包含共享信息的文件或目录
    • 多个容器可以使用docker-compose一起启动,并且compose文件可以定义共享变量

host

对于独立容器,移除容器和Docker主机之间的网络隔离,直接使用主机的网络。

  • 如果容器使用主机网络模式,该容器的网络堆栈不会与Docker宿主机隔离(容器共享主机的网络命名空间),并且容器不会分配自己的ip地址。例如,如果您运行一个绑定到端口80的容器,并且使用主机网络,则容器的应用程序在主机IP地址的端口80上可用。
  • port-mapping 不生效, -p--publish-P--publish-all 选项被忽略,并产生一个告警WARNING: Published ports are discarded when using host network mode
  • 主机模式网络对于优化性能非常有用, 在容器需要处理大量端口的情况下,因为它不需要网络地址转换(NAT),并且没有为每个端口创建“用户空间-代理”。
  • 该主机网络驱动程序仅适用于Linux主机,不支持Mac、Windows和Windows Server的Docker Desktop

使用命令如下:
docker run --rm -d --network host --name my_nginx nginx

overlay

在多个Docker守护进程主机之间创建分布式网络。 该网络位于特定主机网络之上(overlays),允许连接到它的容器在启用加密时安全通信。Docker透明地处理每个数据包往返于正确的Docker守护进程主机和正确的目标容器间的路由

overlay网络可以实现如下容器间的通信,这种策略消除了在这些容器之间进行操作系统级路由的需要。

  • 将多个Docker守护进程连接在一起,使swarm services能够相互通信
  • swarm services和独立容器之间通信
  • 在不同Docker守护进程上的两个独立容器之间通信

组网方式

当初始化一个swarm或将一个Docker主机加入到一个现有的swarm时,在该Docker主机上创建了两个新的网络:

  • ingress: 处理与swarm service 相关的控制和数据流量。创建swarm service 时,如果没有连接到自定义的overlay网络,默认连接到这个网络

  • docker_gwbridge

    • 将单个Docker守护进程连接到参与swarm的其他守护进程.
    • docker_gwbridge是一个虚拟网桥,连接overlay网络(包括ingress网络)到单个Docker守护进程的物理网络。
    • 它不是Docker设备。它存在于Docker主机的内核中。
    • 如果需要对docker_gwbridge进行自定义设置,则必须在将Docker主机加入swarm之前或暂时从swarm中移除后进行。

创建overlay的必要条件

  • 需要为参与overlay网络的每个Docker主机开放以下端口:
    • TCP端口2377 用于集群管理通信
    • TCP和UDP端口 7946 用于节点间通信
    • UDP端口4789 用于覆盖网络流量
  • 在创建overlay网络之前,需要使用docker swarm init将Docker守护进程初始化为swarm manager ,或者使用docker swarm join将其加入现有的swarm 。其中任何一个都会创建默认的ingress overlay网络,默认情况下由swarm service使用。即使您从未计划使用swarm services,也需要这样做。之后,可以创建额外的用户定义overlay网络。

常用操作命令

  • 自定义ingress网络
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1.停止所有连接ingress的容器服务,
# 2.删除ingress网桥
docker network rm ingress

# 3. 创建自定义的ingress网桥
ocker network create \
--driver overlay \
--ingress \
--subnet=10.11.0.0/16 \
--gateway=10.11.0.2 \
--opt com.docker.network.driver.mtu=1200 \
my-ingress

# 4. 重启在第一步关闭的服务
  • 自定义docker_gwbridge网络
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. Stop Docker.
# 2. 删除已有的docker_gwbridge接口
sudo ip link set docker_gwbridge down
sudo ip link del dev docker_gwbridge
# 3. Start Docker. Do not join or initialize the swarm.

# 4.Create or re-create the docker_gwbridge bridge
docker network create \
--subnet 10.11.0.0/16 \
--opt com.docker.network.bridge.name=docker_gwbridge \
--opt com.docker.network.bridge.enable_icc=false \
--opt com.docker.network.bridge.enable_ip_masquerade=true \
docker_gwbridge

# 5. 初始化或加入swarm。由于桥已经存在,Docker不会通过自动设置创建它。

【ipvlan】

1
IPvlan`网络让用户完全控制`IPv4`和`IPv6`寻址【`addressing`】,`VLAN`驱动程序建立在此基础上,为用户提供对二层VLAN标记【`layer 2 VLAN tagging` 】的完全控制,甚至对底层网络集成感兴趣的用户提供 `IPvlan L3 routing

IPvlan是经过验证的、真实的网络虚拟化技术的一个新转变。Linux实现非常轻量级,因为它们不是使用传统的Linux网桥进行隔离,而是与Linux以太网接口或子接口相关联,以加强网络之间的分离和到物理网络的连接。

IPvlan提供了许多独特的功能,并为各种模式的进一步创新提供了大量的空间,2个突出优点如下:

  • 移除通常存在于Docker主机NIC【network interface controller】和容器接口之间的桥接,
  • 留下一个由容器接口【container interfaces】组成的简单设置,直接连接到Docker主机接口。
1
2
3
4
5
6
docker network create -d ipvlan \
--subnet=192.168.210.0/24 \
--subnet=192.168.212.0/24 \
--gateway=192.168.210.254 \
--gateway=192.168.212.254 \
-o ipvlan_mode=l2 -o parent=eth0 ipvlan210

【macvlan】

Macvlan网络允许为容器分配MAC地址,使其显示为网络上的物理设备。 Docker守护进程通过容器的MAC地址将流量路由到容器。
在处理希望直接连接到物理网络的遗留应用程序(而不是通过Docker主机的网络堆栈路由)时,使用macvlan驱动程序有时是最佳选择

一些应用程序,特别是遗留应用程序或监视网络流量的应用程序,希望直接连接到物理网络, 可以使用macvlan网络驱动程序为每个容器的虚拟网络接口分配MAC地址,使其看起来像一个直接连接到物理网络的物理网络接口

使用macvlan需要注意如下几点:

  • 由于IP地址耗尽或“VLAN扩散”,很容易无意中损坏您的网络,在这种情况下,您的网络中有不适当的大量唯一MAC地址
  • 网络设备需要能够处理“混杂模式”,即一个物理接口可以分配多个MAC地址
  • 应用程序可以使用桥接(在单个Docker主机上)或overlay(在多个Docker主机上通信)工作,从长远来看,这些解决方案可能会更好。
1
2
3
4
5
6
docker network create -d macvlan \
--subnet=192.168.32.0/24 \
--ip-range=192.168.32.128/25 \
--gateway=192.168.32.254 \
--aux-address="my-router=192.168.32.129" \
-o parent=eth0 macnet32

自定义网络


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
version: "3"
services:
proxy:
container_name: proxy
image: nginx:lastest
networks:
- frontend
app:
container_name: springboot-service
networks:
- frontend
- backend
db:
image: postgres
networks:
- backend

networks:
frontend:
driver: bridge
backend:
# Use a custom driver which takes special options
ipam:
driver: default
config:
- subnet: 172.28.0.0/16

配置默认网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: "3"
services:
web:
container_name: web
ports:
- 8088:8080
db:
container_name: db
image: postgres

networks:
default:
# Use a custom driver
driver: bridge

指定一个已经存在的网络

1
2
3
4
networks:
default:
external:
name: my-pre-existing-network

解决macvlan网络容器与宿主机通讯

默认情况下各个macvlan之间可以通讯,但是不能与宿主机进行通讯!! 出现这种情况的原因是为了安全而禁止互通,如宿主机ping容器的ip,尽管他们属于同一网段,但是也是ping不通的,反过来也是。

【解决方案】:

可以在宿主机上建立一个macvlan链接,这样就可以通过宿主机上的macvlan与容器内部的macvlan进行连接,从而解决了宿主机与macvlan容器之间不能通讯的问题。

  • 创建macvlan网络
1
2
3
4
5
docker network create -d macvlan \
--subnet=192.168.123.0/24(子网) \
--gateway=192.168.123.1(网关) \
-o parent=ens33(父网卡) \
macnet(新网络名称)
  • 运行docker容器,macvlan网络模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
docker run -d \
--name=container \
--network macnet(macvlan名称) \
--ip=192.168.199.120(指定macvlan ip) \
--dns=192.168.199.170(指定dns服务器,这里写的宿主机) \
--restart=always \
aisyun/image:version

#完整命令:
docker run -d \
--name=container \
--network macnet \
--ip=192.168.199.120 \
--dns=192.168.199.170 \
--restart=always \
aisyun/image:version
  • 配置宿主机和容器通讯
  1. 宿主机创建一个macvlan网络,名称:hostvlan
1
2
3
4
ip link add hostvlan(macvlan名称) link ens33(物理网卡) type macvlan(macvlan驱动) mode bridge(桥接模式)   

#完整命令:
ip link add hostvlan link ens33 type macvlan mode bridge
  1. 设置macvlan IP 并启用
1
2
ip addr add 192.168.199.252/32(hostvlan IP) dev hostvlan                           
ip link set hostvlan up #启用hostvlan网络
  1. 增加路由表
1
2
3
4
ip route add 192.168.199.120(需要建立通讯的macvlan容器IP) dev hostvlan(刚宿主机新建macvlan)

#完整命令:
ip route add 192.168.199.120 dev hostvlan

到此宿主机和容器可以正常通信

三、Docker防火墙

(一)Docker容器之端口转发

docker容器firewalld端口转发规则

1、配置firewalld端口转发,要先打开端口转发,则需要先

1
firewall-cmd --zone=public --add-masquerade --permanent

2、然后转发22端口至3753

1
firewalld-cmd --zone=public --add-forward-port=port22:proto=tcp:toport=3753

3、转发22端口数据至另一个ip的 相同端口上

1
firewalld-cmd --zone=public --add-forward-port=port22:proto=tcp:toport=192.168.199.120

4、转发22端口数据至另一个ip的3753端口上

1
firewalld-cmd --zone=public --add-forward-port=port22:proto=tcp:toport=3753:toaddr=192.168.199.120

(二)Docker与Firewalld冲突怎么办

第一种方式:按顺序重启firewalld与docker

仅限于利用firewalld限制docker映射之外的端口,如果是docker使用了该端口,则firewalld配置无效,如果想要对docker使用的端口进行限制,这种方式是不合适的。当启动firewalld出现冲突的时候,首先重启firewalld,然后重启docker,注意顺序不可以反过来。这是最垃圾的一种方式,当然如果它能解决燃眉之急的话也不错。

第二种方式:在DOCKER-USERchain中添加规则

DOCKER-USER 链中添加的规则会先于DOCKER链生效,因此在这个链中手动添加规则将会生效。这是最推荐的方式,没有之一。

1、不要尝试去手动修改DOCKER链,这样可能会使docker网络出现问题。
2、注意添加的规则要插在DOCKER-USER链的顶部,默认情况下所有到达docker主机的连接都会被允许。
3、限制条件就是,如果端口不是在Docker中开放的,比如22端口,那么在DOCKER链中插入规则不会生效,需要在INPUT链中设置规则。

几个示例:

1
2
3
4
5
6
7
## 限制 192.168.3.0/24 网络防止3306端口
iptables -I DOCKER-USER -s 192.168.3.0/24 -p tcp --dport 3306 -j DROP
## 拒绝来自所有主机的连接,除了192.168.1.1,注意修改外网卡地址
iptables -I DOCKER-USER -i eth0 ! -s 192.168.1.1 -j DROP
## 当然也可以只允许一部分IP
iptables -I DOCKER-USER -i eth0 ! -s 192.168.1.0/24 -j DROP
iptables -I DOCKER-USER -m iprange -i eth0! --src-range 192.168.1.1-192.168.1.3 -j DROP

第三种方式:最新版本的Docker支持与firewalld共存

前提:Docker版本大于等于 20.10.0,
Docker在最新的版本里自动创建了一个名为docker的 firewalld zone,并把它的所有网络接口(包括docker0)加入到了这个区域里面,执行下面的命令将你的docker0接口移到docker区域。

1
2
3
# Please substitute the appropriate zone and docker interface
firewall-cmd --zone=trusted --remove-interface=docker0 --permanent
firewall-cmd --reload

(三)常用规则

  • 将访问192.168.1.123(本机)主机8080端口的请求转发至80端口
1
#firewall-cmd --permanent --zone=public --add-forward-port=port=8080:proto=tcp:toport=80:toaddr=192.168.1.123
  • 将访问192.168.1.123(本机)主机8080端口的请求转发至192.168.1.111的80端口
1
#firewall-cmd --permanent --zone=public --add-forward-port=port=8080:proto=tcp:toaddr=192.168.1.111:toport=80
  • 将本机的80端口转发至192.168.1.109 8080端口
1
#firewall-cmd --permanent --zone=public --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=192.168.1.109
  • 允许IP 192.168.1.142访问本机器的6379端口
1
#firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.1.142" port protocol="tcp" port="6379" accept"
  • 拒绝IP 192.168.1.142访问本机的22号端口
1
#firewall-cmd --permanent --add-rech-rule="rule family="ipv4" source address="192.168.1.142" port protocol="tcp" port="80" drop"

注:转发时,要开启伪装,伪装就是SNAT

允许IP伪装

1
2
3
4
5
6
[root@localhost ~]#  firewall-cmd --permanent --zone=public --add-masquerade
success
[root@localhost ~]# firewall-cmd --reload
success
[root@localhost ~]# firewall-cmd --query-masquerade
yes