docker网络配置

docker网络

在docker中,几个容器间的互相通信是通过docker自带的网络就行通讯的。

docker网络类型分为三种,分别是:none(无网络)、bridge(桥接)和host(仅主机)。

通过以下命令可以查看

docker network ls

none(无网络)

none网络指无网络

也就是挂载在none下的容器没有任何网卡,可以通过以下命令指定使用none网络

docker run -itd --network=none nginx

none网络的实际应用:

封闭意味着隔离,一些对安全性要求高并且不需要联网的应用可以使用none网络。

比如某个容器的唯一用途是生成随机密码,就可以放到none网络中避免密码被窃取。

host(仅主机)

host指仅主机,使用host网络的容器会和宿主机共享网络空间

docker网络配置_第1张图片

在host网络下,由于docker容器会和宿主机公用网络空间,即公用网卡,因此IP会和宿主机一致。

因此在host网络下会出现端口冲突的问题,需要docker容器向外进行端口映射避开宿主机中已经使用的端口。

可以通过-network-host 指定使用host网络

docker run -itd --network=host nginx

bridge(桥接)

bridge指桥接,在Docker安装时会创建一个命名为docker0的Linux bridge。如果不知道-network,创建的容器都会挂到docker0上。

docker创建容器时如果不指定网络连接方式,默认使用bridge连接。

网桥可以简单理解为两台网络设备相互通讯的桥梁:

请添加图片描述

而在docker中的网桥便是docker0

通过以下命令查看:

brctl show

在这里插入图片描述

此时该网桥下没有挂载任何容器,因此interfaces处为空

现在向docker0网桥下挂载一个容器后,再查看该网桥

[root@localhost ~]# docker run -itd --name=busybox --network=bridge busybox
b9edeff14d7d8531196a2315b62b488544d160b8b57f8a39f8320b4321386730
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAMES
b9edeff14d7d   busybox   "sh"      5 seconds ago   Up 4 seconds             busybox
[root@localhost ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242348d6acb	no		veth3b29978
virbr0		8000.52540050602f	yes		virbr0-nic

请添加图片描述

可以看到此时interfaces处出现一个叫veth3b29978的网卡,该网卡就是新创建容器的虚拟网卡

再查看当前容器的信息

docker网络配置_第2张图片

此时Gateway是docker网桥的ip,IPAddress是子容器的ip。在宿主机中向子容器中ping是可用ping得通的。

此时再进子容器中查看子容器中查看网卡

[root@localhost ~]# docker exec -it busybox sh

docker网络配置_第3张图片

可以看到子容器中是有分配ip的。

ps:为什么在宿主机中网卡叫veth3b29978,而在容器内网卡叫eth0

实际上eth0@if34 和veth28c57df 是一对veth pair。 veth pair 是一种成对出现的特殊网络设备,可以把它们想象成由一根虚拟网线连接起来的一对网卡, 网卡的一头(eth0@if34) 在容器中,另一头(veth28c57df) 挂在网桥docker0 上,其效果就是将eth0@if34 也挂在了docker0上。

docker网络配置_第4张图片

参考:Docker网络(host、bridge、none)详细介绍_docker network none_南宫乘风的博客-CSDN博客

自定义网络

除了none、host、bridge网络外,docker支持用户自定义user-defined网络。

dockers提供了三种user-defined的网络驱动:bridge、overlay、macvian。

基本命令

查看所有网络:

docker network ls

创建网络:

docker network create [--参数 参数值] 网络名称
  • --driver:指定网络驱动:bridge、overlay、macvian(默认 “bridge”)。
  • --subnet:指定子网网段(如192.168.0.0/16、172.88.0.0/24)
  • --ip-range :执行容器的IP范围,格式同subnet参数
  • --gateway:子网的IPv4 或 IPv6网关,如(192.168.0.1)

删除网络:

docker network rm 网络名称 [网络名称...]

查看一个或多个网络的详细信息:

docker network inspect [--参数 参数值] 网络名称 [网络名称...]

docker inspect [--参数 参数值] 网络名称 [网络名称...]
  • -f, --format:根据format输出结果

为启动的容器指定网络模式:

docker run/create --network 网络名称

网络连接或断开:

# 连接网络
docker network connect [--参数 参数值] 网络名称 容器名称 
# 断开网络
docker network disconnect [--参数 参数值] 网络名称 容器名称
  • -f, --force:强制断开连接(用于disconnect)

创建自定义网络

现在,为了方便管理容器,我们需要自定义一个网络。

首先,我们需要新增一个网桥,其作用与docker0作用类似

[root@localhost ~]# docker network create  my_net
9edae79796cfd1277064c62d421f438b3caf935e8d9f1ee4fa6dbbab64df6bcf

默认驱动使用bridge

ps:创建时可能会报错:

[root@localhost ~]# docker network create --driver bridge my_net
Error response from daemon: Failed to Setup IP tables: Unable to enable SKIP DNAT rule:  (iptables failed: iptables --wait -t nat -I DOCKER -i br-2913d0b63faa -j RETURN: iptables: No chain/target/match by that name.
 (exit status 1))

此错误说明在docker开启时,防火墙状态发生了改变。要么把防火墙状态还原,要么重启docker。

这里我选择重启docker:

[root@localhost ~]# systemctl restart docker.service

此时再查看当前网络可以看到刚刚创建的网络:

[root@localhost ~]# docker network ls

docker网络配置_第5张图片

通过brctl show也可以看到刚刚配置的网桥:

[root@localhost ~]# brctl show

在这里插入图片描述

其中的br-9edae79796cf是my_net网桥的"br-" + 网桥id

容器要使用新的网络,需要在启动时通过–network指定

[root@localhost ~]# docker run -itd --network=my_net --name=busybox1 busybox
b12e22c6f51c4edba9c2defcf07d8afb37971f4199dccde82f0dfaa90425ec73
[root@localhost ~]# docker run -itd --network=my_net --name=busybox2 busybox
2683f81188f497eed40a2388716c9626ebe81dbb41d315b1e60e156186c81814
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAMES
2683f81188f4   busybox   "sh"      3 seconds ago   Up 2 seconds             busybox2
b12e22c6f51c   busybox   "sh"      6 seconds ago   Up 5 seconds             busybox1

此时容器网络的拓扑结构为:

docker网络配置_第6张图片

此时busybox1与busybox2之间互ping是可以通的。

不同网桥下通讯

此时再创建一个网桥my_net1和容器busybox3:(目的:让busybox2可以同时连通my_net下的busybox1和my_net1下的busybox3)

先创建my_net1网桥:

[root@localhost ~]# docker network create --driver bridge --subnet 172.20.0.0/16 my_net1
321dbffb10c2e87935baa158841d07cbd320b4a46da4d046ef707f3738d275f1
  • --driver bridge:驱动使用bridge
  • --subnet 172.20.0.0/16:网段在172.20.0.0/16,除去172.20.0.0(广播地址)和172.20.0.1(路由地址)外,子容器取值在当前网段下2~16之内。

此时可以看到多出的网络

docker网络配置_第7张图片

再创建容器busybox3,将其挂载在my_net1下:

[root@localhost ~]# docker run -itd --network=my_net1 --name=busybox3 busybox
2b110f97c029d3029a48ab968ac19148c1bd9519dbcc0e2b23aaf73f376c249c

此时可以看到当前容器的IP为:

[root@localhost ~]# docker inspect busybox3

docker网络配置_第8张图片

此时的网络拓扑结构为:

docker网络配置_第9张图片

此时,如果想要busybox2只能通讯busybox1,因为他俩在同一网段下,但是busybox2不能和busybox3通讯。

如果需要将busybox2连通busybox3,需要将busybox2接入my_net1,指令:docker network connect [--参数 参数值] 网络名称 容器名称

[root@localhost ~]# docker network connect my_net1 busybox2

此时通过docker inspect busybox2可以查看到当前容器的网卡

docker网络配置_第10张图片

docker网络配置_第11张图片

进入busybox3容器下验证是否能ping成功:

[root@localhost ~]# docker exec -it busybox2 sh[root@localhost ~]# docker exec -it busybox2 sh
/ # ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.248 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.102 ms
^C
--- 172.18.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.102/0.175/0.248 ms
/ # ping 172.20.0.2
PING 172.20.0.2 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.199 ms
64 bytes from 172.20.0.2: seq=1 ttl=64 time=0.083 ms
^C
--- 172.20.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss

显示能ping成功

此时的拓扑结构为:

docker网络配置_第12张图片

容器通讯

docker在默认情况下可以向外部网络环境进行通讯,同时也可以和同属于当前网段的其他容器进行通讯。

容器间通讯

Docker DNS Server
通过IP访问容器虽然满足了通信的需求,但还是不够灵活。因为在部署应用之前可能无法确定IP,部署之后再指定要访问的IP会比较麻烦。对于这个问题,可以通过docker自带的DNS服务解决。

从Docker 1.10版本开始,docker daemon实现了一个内嵌的DNS server,使容器可以直接1通过“容器名”通信。方法很简单,只要在启动时用-name为容器命名就可以了。

使用docker DNS有个限制:只能在user-defined网络中使用。也就是说,默认的bridge网络是无法使用DNS的。

容器向外通讯

docker容器在默认情况下,是可以向外通讯的。

先新建一个容器:

[root@localhost ~]# docker run -itd --name busybox1 busybox
778c05a4574d1e9842346fb246e16e7b0bda8a96b716c3bf3c67050f8f6bbfea

进入容器:

[root@localhost ~]# docker exec -it busybox1 sh

ping百度:

[root@localhost ~]# docker exec -it busybox1 sh
/ # ping www.baidu.com
PING www.baidu.com (14.119.104.254): 56 data bytes
64 bytes from 14.119.104.254: seq=0 ttl=127 time=26.366 ms

但是,通过ifconfig可以看到,当前的容器ip是172.17.0.2。

/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:656 (656.0 B)  TX bytes:0 (0.0 B)

该ip是由docker0网桥进行发放的,而docker0并不会直接连接外部网络环境。

解释:

如果内部容器想要与外部网络环境进行交互,光是通过自己的网段是肯定不行的,数据包应该是通过宿主机交上去的,所有从子容器到宿主机时一定做了一次IP转换,即NAT。

nat:是将 IP 数据报报头中的 IP 地址转换为另一个 IP 地址的过程,主要用于实现内部网络(私有 IP 地址)访问外部网络(公有 IP 地址)的功能。

先通过以下指令查看nat:

iptables -t nat -S

docker网络配置_第13张图片

其含义是:如果网桥docker0收到来自172.17.0.0/16网段的外出包,把它交给MASQUERADE处理。而且MASQUERADE的处理方式是将包的原地址替换成host的地址发送出去,宿主机做了一次网络地址转换(NAT)

知道了路由转发的规则之后,需要通过以下指令查看路由表,查看当前的默认路由,因为数据包会通过默认路由向外发送。相当于机器的大门。看住大门,就能知道进出的数据包都有哪些。

ip r

路由表:简单点说路由表就是路由器用于指导数据包如何转发的表项,记录了去往目的IP的下一跳去哪里。

目的地 协议 优先级 开销 下一跳 出接口
192.2.0 Static 60 0 10.1.1.2 Ethernet0/0/0

路由表的作用类似于我们生活中的地图,指引我们去往一个目的地该如何走?

推荐视频:路由器是如何路由的?(上集)_哔哩哔哩_bilibili

在这里插入图片描述

默认路由通过ens33发出去,所以我们同时要监控ens33和docker0上的icmp(ping)的数据包。

首先先进入busybox1容器后通过以下命令进行抓包:

tcpdump -i 网卡名称 -n icmp

在这里插入图片描述

此时是:172.17.0.2 ==> www.baidu.com

但再对宿主机的网卡进行抓包时:

在这里插入图片描述

发现此时是通过宿主机的ip发送到baidu.com的。即:192.168.137.128 ==> www.baidu.com

这里ping出去的包源变成了192.168.137.128。

用图表示以上过程:

docker网络配置_第14张图片

向容器内通讯

容器访问外部网络可以通过NAT做转发,但是外部网络访问docker,需要进行端口映射。

端口映射是指:将A主机IP的A端口 映射到 B主机IP的B端口。
docker网络配置_第15张图片

docker可以将对外提供服务的端口映射到宿主机的某个端口,外网通过该端口访问容器。

启动时需要通过-p参数映射端口

[root@localhost ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
busybox      latest    8135583d97fe   41 hours ago   4.86MB
nginx        latest    448a08f1d2f9   2 weeks ago    142MB
[root@localhost ~]# docker run -itd -p 80 --name web nginx
129690c906b777a120ab148fcfe343c79ea7b3b9010a3114b55a6f2863f9aec9

此时通过docker ps -a可以查看当前容器所映射的端口

在这里插入图片描述

映射到外部的端口是32768,访问时需要访问宿主机ip:32768,即:192.168.137.128:32768

docker网络配置_第16张图片

除了映射动态端口,也可在-p中指定映射到host某个特定端口,例如可将80端口映射到host的8080端口

[root@localhost ~]# docker run -itd --name web1 -p 80:80 nginx
75d46481983abbfe4e8b66b57359daaa8901e6569bfa69dfc54fd07f4d497165

此时直接访问192.168.137.128:80也可以访问到nginx的页面。

图示:

docker网络配置_第17张图片

参考:Docker容器访问外部世界_南宫乘风的博客-CSDN博客

你可能感兴趣的:(docker,linux,docker,网络,运维,容器,linux)