Docker(七)---docker网络(原生&自定义网络、容器通信)

Docker(七)—docker网络(原生&自定义网络、容器通信)

1.Docker原生网络

安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 和host。

docker network ls

在这里插入图片描述

docker网络模式功能
host容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
Container(Joined)创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。
None该模式关闭了容器的网络功能。
Bridge此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及Iptables nat表配置与宿主机通信。

运行容器的时候指定网络模式:

模式参数
host模式使用 --net=host(–network host) 指定。
none模式使用 --net=none 指定。
bridge模式使用 --net=bridge 指定,默认设置。
container模式使用 --net=container:NAME_or_ID 指定。

bridge网桥模式

bridge模式下容器没有一个公有ip,只有宿主机可以直接访问,外部主机是不可见的。
容器通过宿主机的NAT规则后可以访问外网。

在这里插入图片描述
docker安装时会创建一个名为docker0的linux bridge,新建的容器会自动桥接到这个接口

docker run -d --name nginx nginx
brctl show
ip addr show	#添加了veth638a7a8@if41

可以发现,当挂起一个容器时,就会出现相对应的网桥接口:
在这里插入图片描述
这时,我们的容器就通过docker0网桥与宿主机建立通信了:

docker inspect nginx
ping 172.17.0.2
curl 172.17.0.2

在这里插入图片描述
再运行一个容器:

docker run -d --name nginx2 nginx
brctl show

可以看到docker0上又接了一个接口:
在这里插入图片描述

ip addr show

又出现了vethad38eee@if43:
在这里插入图片描述
不仅如此,只要宿主机做了NAT,我们同时在容器中做好dns解析,就能与外网通信:

docker run -it --rm busybox
ip addr show
vi /etc/resolv.conf
ping baidu.com

在这里插入图片描述

sysctl -a | grep ip_forward

在这里插入图片描述

host模式

相当于使用了Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址。
在这里插入图片描述
一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

host模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性。

做此过程之前删除上一步骤中运行的所有容器

netstat -antlp	#先查看宿主机的端口情况
docker run -d --name nginx  --network host nginx
netstat -antlp	#再次查看宿主机的端口情况(80端口打开了)
brctl show

我们可以看到它并不像bridge模式那样,没有在docker0下桥接接口,而是与宿主机共用一个网络:
在这里插入图片描述
在这里插入图片描述
用外部主机访问,可以看到nginx默认发布页面

curl 172.25.254.1

在这里插入图片描述

docker run -it --rm --network host busybox
ip addr

可以看到与宿主机的网络一模一样:
在这里插入图片描述

如果此时我们再开一个nginx:

dockedocker run -d --name nginx2  --network host nginx
docker ps	#开启成功
docker ps	#其中一个nginx消失
docker ps -a	#可以看到被停掉的nginx

这是因为两个nginx的端口和ip冲突了
在这里插入图片描述

none模式

none模式是指禁用网络功能,只有lo接口,在容器创建时使用–network none

none模式关闭了容器的网络功能,但是在以下两种情况下是有用的:

  • 容器并不需要网络(例如只需要写磁盘卷的批处理任务)。
  • overlay:在docker1.7代码进行了重构,单独把网络部分独立出来编写,所以在docker1.8新加入的一个overlay网络模式。
docker run -it --rm --network none busybox
ip addr

可以看到只有lo接口:
在这里插入图片描述

docker run -d --name nginx nginx
docker ps
docker inspect nginx | grep Pid
cd /proc/9206
cd ns
ll

查看到网络是不可以使用的:
在这里插入图片描述

2.Docker自定义网络

原生网络是docker安装后自动创建的,真正需要配置的是自定义网络。

Docker 提供三种 user-defined 网络驱动:bridge, overlay 和 macvlan。

  • bridge驱动类似默认的bridge网络模式,但增加了一些新的功能
  • overlay 和 macvlan 用于创建跨主机的网络

创建自定义网络mynet1:

docker network ls
docker network create -d bridge mynet1
docker network ls
docker network inspect mynet1

可以看到Docker自动分配IP网段是172.18.0.0/16:
在这里插入图片描述
在这里插入图片描述
使用自定义的网络mynet1运行容器:

docker run -it --name demo --network mynet1  busybox
ping demo	#可以看到自动分配的ip为172.18.0.2

在这里插入图片描述
查看当前 host 的网络结构变化:

ip addr

在这里插入图片描述
创建自定义网络mynet2:

docker network create -d bridge mynet2
docker network ls

在这里插入图片描述

查看当前 host 的网络结构变化:

ip addr

可以看到mynet2的网段为172.19.0.1/16
在这里插入图片描述

brctl show

可以看到mynet1上有demo这个接口,而mynet2是一个没有接口的bridge:
在这里插入图片描述
使用自定义的网络mynet2运行容器:

docker run -it --name test --network mynet2 busybox	#按ctrl+pq退出

可以看到给他分配的ip为172.19.0.2:
在这里插入图片描述
使用自定义的网络mynet2运行容器test2:

docker run -it --name test2 --network mynet2 busybox

可以看到给他分配的ip为172.19.0.3,它可以和test通信,但不能和demo通信,因为他们不在同一网段,使用的是不同的自定义网络
在这里插入图片描述
那么你可能会有疑问,在容器中通信时为什么要用容器名,而不用ip地址呢?
我们通过一个实验来理解这个问题

docker run -it --name vm1 --network mynet1 busybox
ip addr

按ctrl+d退出
我们可以看到它自动分配的ip为172.18.0.2/16
在这里插入图片描述
此时再运行一个容器:

docker run -it --name vm2 --network mynet1 busybox
ip addr

按ctrl+pq退出
我们可以看到它自动分配的ip为172.18.0.2/16,是刚才vm1的ip,所以说当一个容器停掉后,它的ip会被释放,如果有别的容器运行,就会分配给其他容器。
在这里插入图片描述
此时再启动vm1:

docker start vm1
docker inspect vm1 | grep IPAddress

我们可以看到它自动分配的ip为172.18.0.3。说明如果再次启动被停掉的容器,docker会给他自动分配一个其他的ip。如果我们用ip来进行容器之间的通信,显然是不合理的,因为它的ip会随着容器的启动和停止重新分配
在这里插入图片描述
连接到vm1:

docker attach vm1

我们可以看到,使用容器名通信时,它会自动帮我们连接到对应的容器,它内部的dns可以自动更新容器的ip
在这里插入图片描述

除此之外,我们也可以自己指定 IP 网段:
需要在创建网络时指定 --subnet 和 --gateway 参数

我们先将之前的网络和容器删除:
在这里插入图片描述
创建自定义网络mynet1:

docker network create --subnet 192.168.1.0/24 --gateway 192.168.1.1 mynet1
ip addr

可以看到它创建的网络网段为192.168.1.1/24:
在这里插入图片描述
运行容器使用自定义网络:

docker run -it --name vm1 --network mynet1 busybox

容器分配到的IP为192.168.1.2:
在这里插入图片描述

容器的IP都是docker自动从subnet中分配,我们能否指定一个静态IP呢?
当然可以,通过–ip指定,你必须指定该网络模式的网段ip,否则会报错:

docker run -it --name vm2 --network mynet1 --ip 192.168.1.100 busybox

注意:只有使用 --subnet 创建的网络才能指定静态IP

在这里插入图片描述

3.Docker容器间通信

通过上面的实验我们可以知道,使用同一自定义网络(即同一网段)运行的容器是可以相互通信的,那么如果两个容器不在同一网段,但我们也想让它通信,怎么办?

首先我们删除之前创建的网络和容器并且新建两个自定义网络:

docker network create -d bridge mynet1
docker network create -d bridge mynet2
ip addr

可以看到他们的网段分别为172.20.0.1/16和172.21.0.1/16
在这里插入图片描述

开启两个容器基于不同的docker网络:

docker run -it --name vm1 --network mynet1 busybox
docker run -it --name vm2 --network mynet2 busybox

按ctrl+pq退出!
在这里插入图片描述

如何让他们之间通信呢?

方法1:使用connect方法给vm2添加一块mynet1网卡

docker network connect mynet1 vm2
docker attach vm2
ip addr	#我们可以看到这里多出了一个网卡eth1@if81,ip为172.20.0.3
ping vm1	#可以通信

方法2:joined

在容器创建时使用–network container:vm1指定(vm1指在运行的容器)

container模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。

docker run -it --name vm3 --network container:vm1 busybox
ip addr

可以发现,和vm1网络完全一致,使用相同的网络name space:
在这里插入图片描述

方法3:使用–link连接容器

格式:–link :alias
name和id是源容器的,alias是源容器在link下的别名

首先删除之前使用的容器

运行容器vm1:

docker run -d --name vm1 nginx

在这里插入图片描述
使用link连接vm1,别名为nginx:

docker run -it --link vm1:nginx busybox
env	#可以看到ip为172.17.0.2
ping vm1
ping nginx

在这里插入图片描述
此时我们再开一个shell:

docker inspect vm1 | grep IPAddress

查看到vm1的ip为172.17.0.2,说明nginx连接vm1时使用的是vm1的网络资源
在这里插入图片描述

docker stop vm1

停掉以后我们在link连接的nginx中ping不通nginx和vm1了:
在这里插入图片描述

docker start vm1

启动vm1后又可以ping通了,说明网络又可以用了:
在这里插入图片描述
停掉vm1并且创建容器vm2:

docker stop vm1
docker run -d --name vm2 nginx
docker inspect vm2 | grep IPAddress

可以看到vm2占用了vm1之前使用的ip地址:
在这里插入图片描述
此时再启动vm1:

docker start vm1

可以看到nginx中的ip地址也随着vm1的改变而改变:
在这里插入图片描述
但是env查看变量,这里面的ip地址没有改变
在这里插入图片描述

4.容器是如何访问外网的?

容器与外网通信是通过iptables的SNAT实现的:
在这里插入图片描述
容器发送数据包到外网时,通过地址伪装

iptables -t nat -nL

在postrouting中进行伪装
在这里插入图片描述

5.外网是如何访问容器的?

是通过端口映射访问的-p host端口:容器内端口

docker run -d --name web -p 80:80 nginx
iptables -t nat -nL

在这里插入图片描述

外网访问容器使用到了docker-proxy和iptables的DNAT:

  • 宿主机host访问本机容器使用的是iptables DNAT
  • 外部主机访问容器内部或者容器之间的访问是docker-proxy实现的
    在这里插入图片描述
netstat -antlp | grep 80
ps ax | grep docker-proxy

在这里插入图片描述

6.Docker跨主机的容器网络

docker跨主机的网络方式:

docker原生的overlay和macvlan
第三方的flannel、weave、calico

如何与docker集成?

使用libnetwork:docker网络库
CNM(container network model)模型:对容器网络进行抽象

CNM(container network model)模型

三类组件作用
Sandbox容器网络栈(namespace)
Endpoint将sandbox接入network(veth)
Network包含一组endpoint,同一network的endpoint可以通信

使用macvlan实现Docker容器跨主机网络

macvlan特点:

  • 使用linux内核提供的一种网卡虚拟化技术
  • 性能好:因为无需使用桥接,直接使用宿主机物理网口。

具体步骤:
step1 为各自docker宿主机各添加一块网卡,打开网卡混杂模式:

scp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth1
vim /etc/sysconfig/network-scripts/ifcfg-eth1
BOOTPROTO=none
DEVICE=eth1
ONBOOT=yes
scp /etc/sysconfig/network-scripts/ifcfg-eth1 server2:/etc/sysconfig/network-scripts/ifcfg-eth1

在这里插入图片描述
在server1和server2中:

ifup eth1	#激活网卡:
ip link set eth1 promisc on  #在eth1网卡上打开混杂模式(开启子接口,会有多个ip地址)

step2 在两台docker宿主机各自创建macvlan网络:
在宿主机server1上:
建立macvlan的docker网络:

docker network create -d macvlan --subnet 172.20.0.0/24 --gateway 172.20.0.1 -o parent=eth1 mynet1
docker network ls

运行一个基于该网络模式的容器:

docker run -it --rm --name vm1 --network mynet1 busybox
ip addr

在这里插入图片描述
在宿主机server2上:
建立macvlan的docker网络:

docker network create -d macvlan --subnet 172.20.0.0/24 --gateway 172.20.0.1 -o parent=eth1 mynet1

运行一个基于该网络模式的容器:

docker run -it --name vm2 --rm --network mynet1 --ip 172.20.0.100 busybox
ip addr

测试:

ping 172.20.0.2

在这里插入图片描述

分析macvlan

  • 网络结构:没有新建桥接,容器的接口直接与宿主机网卡连接,不需要NAT或者端口映射
brctl show

在这里插入图片描述
macvlan会独占网卡,但是可以使用vlan的子接口实现多macvlan网络,最多可以将物理二层网络划分成4094各逻辑网络,且彼此隔离。

解决macvlan独占宿主机网卡:

docker network create -d macvlan --subnet 172.21.0.0/24 --gateway 172.21.0.1 -o parent=eth1.1 mynet2

macvlan网络在物理网络二层是隔离的,无法直接通信,但是可以在三层上(即容器内部)通过网关将macvlan网络连通起来。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值