Docker网络原理详解

理解Docker0

查看本机IP

ip addr
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state
UP group default qlen 1000
 link/ether 00:16:3e:30:27:f4 brd ff:ff:ff:ff:ff:ff
 inet 172.17.90.138/20 brd 172.17.95.255 scope global dynamic eth0
   valid_lft 310954997sec preferred_lft 310954997sec
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state
UP group default
 link/ether 02:42:bb:71:07:06 brd ff:ff:ff:ff:ff:ff
 inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
   valid_lft forever preferred_lft forever

有三个网络

lo     127.0.0.1       #本机回环地址
eth0    172.17.90.138  #阿里云的私有IP
docker0   172.18.0.1   #docker网桥

Docker 是如何处理容器网络访问的?

我们实际场景中,我们开发了很多微服务项目,那些微服务项目都要连接数据库,需要指定数据库的url地
址,通过ip。但是我们用Docker管理的话,假设数据库出问题了,我们重新启动运行一个,这个时候数
据库的地址就会发生变化,docker会给每个容器都分配一个ip,且容器和容器之间是可以互相访问的。
我们可以测试下容器之间能不能ping通

启动tomcat01

  docker run -d -P --name tomcat01 tomcat

查看tomcat01的ip地址,docker会给每个容器都分配一个ip!

docker exec -it tomcat01 ip addr
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
122: eth0@if123: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
state UP group default
 link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
 inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0 valid_lft forever preferred_lft forever

思考,我们的linux服务器是否可以ping通容器内的tomcat ?

ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.070 ms  # 可以ping通!

原理

每一个安装了Docker的linux主机都有一个docker0的虚拟网卡。这是个桥接网卡,使用了veth-pair技术!

我们再次查看主机的 ip addr

ip addr

原来我们有三个网络,我们在启动了个tomcat容器之后,多了一个123的网络!

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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state
UP group default qlen 1000
 link/ether 00:16:3e:30:27:f4 brd ff:ff:ff:ff:ff:ff
 inet 172.17.90.138/20 brd 172.17.95.255 scope global dynamic eth0
   valid_lft 310954997sec preferred_lft 310954997sec
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state
UP group default
 link/ether 02:42:bb:71:07:06 brd ff:ff:ff:ff:ff:ff
 inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
   valid_lft forever preferred_lft forever
123: vethc8584ea@if122: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc
noqueue master docker0 state UP group default
 link/ether 0a:4b:bb:40:78:a7 brd ff:ff:ff:ff:ff:ff link-netnsid 0

我们启动了一个tomcat01,主机的ip地址多了一个 123: vethc8584ea@if122
每启动一个容器,linux主机就会多了一个虚拟网卡
然后我们在tomcat01容器中查看容器的ip是 122: eth0@if123
我们再启动一个tomcat02观察

docker run -d -P --name tomcat02 tomcat

然后发现linux主机上又多了一个网卡 125: veth021eeea@if124:

我们看下tomcat02的容器内ip地址是 124: eth0@if125:

 docker exec -it tomcat02 ip addr

观察现象
tomcat — linux主机 vethc8584ea@if122 ---- 容器内 eth0@if123
tomcat — linux主机 veth021eeea@if124 ---- 容器内 eth0@if125
相信到了这里,大家应该能看出点小猫腻了吧!只要启动一个容器,就有一对网卡veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。
正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!
“Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等,以此构建出非常复杂的虚拟网络
结构,比如 OpenStack Neutron。

我们来测试下tomcat01和tomcat02容器间是否可以互相ping通

docker exec -it tomcat02 ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.110 ms

结论:容器和容器之间是可以互相访问的。

Docker0网络模型图

在这里插入图片描述

结论
tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动默认都是docker0网络。
docker默认会给容器分配一个可用ip。

小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
在这里插入图片描述

Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并
让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中
进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容
器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。

容器互联–Link

思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们
能不能使用服务名访问呢?
jdbc:mysql://mysql:3306,这样的话哪怕mysql重启,我们也不需要修改配置了!docker提供了 --link的操作!

我们使用tomcat02,直接通过容器名ping tomcat01,不使用ip

docker exec -it tomcat02 ping tomcat01

发现ping不通

ping: tomcat01: Name or service not known  

我们再启动一个tomcat03,但是启动的时候连接tomcat02

docker run -d -P --name tomcat03 --link tomcat02 tomcat

这个时候,我们就可以使用tomcat03 ping通tomcat02 了

docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.18.0.3): icmp_seq=1 ttl=64 time=0.093 ms
64 bytes from tomcat02 (172.18.0.3): icmp_seq=2 ttl=64 time=0.066 ms

再来测试,tomcat03 是否可以ping tomcat01 失败

docker exec -it tomcat03 ping tomcat01
ping: tomcat01: Name or service not known

再来测试,tomcat02 是否可以ping tomcat03 反向也ping不通

 docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

思考,这个原理是什么呢?我们进入tomcat03中查看下host配置文件

 docker exec -it tomcat03 cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3 tomcat02 b80da266a3ad  # 发现tomcat2直接被写在这里
172.18.0.4 a3a4a17a2b70

所以这里其实就是配置了一个 hosts 地址而已!
原因:–link的时候,直接把需要link的主机的域名和ip直接配置到了hosts文件中了。

–link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式

自定义网络

基本命令查看

在这里插入图片描述

查看所有网络

docker network ls
NETWORK ID     NAME        DRIVER       SCOPE
4eb2182ac4b2    bridge       bridge       local
ae2b6209c2ab    host        host        local
c037f7ec7e57    none        null        local

所有网路模式

网络模式配置说明
bridge模式–net=bridge默认值,在Docker网桥docker0上为容器创建新的网络栈
none模式–net=none不配置网络,用户可以稍后进入容器,自行配置
container模式–net=container:name/id容器和另外一个容器共享Network namespace。kubernetes中的pod就是多个容器共享一个Networknamespace。
host模式–net=host容器和宿主机共享Network namespace
用户自定义–net=自定义网络用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络

查看一个具体的网络的详细信息

docker network inspect 4eb2182ac4b2
[
 {
    "Name": "bridge",
    "Id":
"4eb2182ac4b23487e1eb6e06df56c71ab6f0adc7ccc0962b4747d0eed5ad6690",
    "Created": "2020-05-11T15:44:20.131441544+08:00",
    "Scope": "local",
    "Driver": "bridge",
    "EnableIPv6": false,
    "IPAM": {
      "Driver": "default",
      "Options": null,
      "Config": [
       {
         // 默认docker0是管理这个子网范围内的。0~16,也就是 255*255,去掉0个255,我们有65534可以分配的ip
         // docker0网络默认可以支持创建6万多个容器ip不重复
          "Subnet": "172.18.0.0/16",
          "Gateway": "172.18.0.1"
       }
     ]
   },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
   },
    "ConfigOnly": false,

//自定义网卡
//1、删除原来的所有容器
    "Containers": {
    
 "a3a4a17a2b707766ad4f2bb967ce1d94f658cd4cccef3bb8707395cdc71fa1e7": {
        "Name": "tomcat03",
        "EndpointID":
"5fe62d0be3a1343aa74f6bb77885d3657b191210cafad200e5054e1bdfe56be9",
        "MacAddress": "02:42:ac:12:00:04",
        "IPv4Address": "172.18.0.4/16",
        "IPv6Address": ""
     },
    
 "b80da266a3ad85fcc874c5f0d3c897246ebc40533cb745bb24180237cc3167b1": {
        "Name": "tomcat02",
        "EndpointID":
"6232cac0c4e7fed30c9fa5eebc9238f9fc44f548f257344b5440d6d486825256",
        "MacAddress": "02:42:ac:12:00:03",
        "IPv4Address": "172.18.0.3/16",
        "IPv6Address": ""
     },
    
 "f38239e2b405bccf8c93bd1052f336f661033b9b27ef9b3f99a018c108e06f87": {
        "Name": "tomcat01",
        "EndpointID":
"31dc174b8f3f15f217acdc3ac7e8a235a03d59438f863706c0143b4426772c5e",
        "MacAddress": "02:42:ac:12:00:02",
        "IPv4Address": "172.18.0.2/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": {}
 }
]

自定义网卡

ip addr
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

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state
UP group default qlen 1000
 link/ether 00:16:3e:30:27:f4 brd ff:ff:ff:ff:ff:ff
 inet 172.17.90.138/20 brd 172.17.95.255 scope global dynamic eth0
   valid_lft 310951436sec preferred_lft 310951436sec
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state
DOWN group default
 link/ether 02:42:bb:71:07:06 brd ff:ff:ff:ff:ff:ff
 inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
   valid_lft forever preferred_lft forever

接下来我们来创建容器,但是我们知道默认创建的容器都是docker0网卡的
我们可以让容器创建的时候使用自定义网络

接下来我们来创建容器,但是我们知道默认创建的容器都是docker0网卡的

默认我们不配置网络,也就相当于默认值 --net bridge 使用的docker0

docker run -d -P --name tomcat01 --net bridge tomcat

docker0网络的特点

  • 它是默认的
  • 域名访问不通
  • –link 域名通了,但是删了又不行

我们可以让容器创建的时候使用自定义网络

在这里插入图片描述

自定义创建的默认default “bridge” 自定义创建一个网络网络

docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
docker network ls
NETWORK ID     NAME        DRIVER       SCOPE
4eb2182ac4b2    bridge       bridge       local
ae2b6209c2ab    host        host        local
09bd09d8d3a6    mynet        bridge       local
c037f7ec7e57    none        null        local

查看网络详细信息

docker network inspect mynet
[
 {
    "Name": "mynet",
    "Id":
"09bd09d8d3a6b33e6d19f49643dab551e5a45818baf4d5328aa7320c6dcfc236",

     "Created": "2020-05-13T13:29:33.568644836+08:00",
    "Scope": "local",
    "Driver": "bridge",
    "EnableIPv6": false,
    "IPAM": {
      "Driver": "default",
      "Options": {},
      "Config": [
       {
          "Subnet": "192.168.0.0/16",
          "Gateway": "192.168.0.1"
       }
     ]
   },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
   },
    "ConfigOnly": false,
    "Containers": {},
    "Options": {},
    "Labels": {}
 }
]
# 我们来启动两个容器测试,使用自己的 mynet!
docker run -d -P --name tomcat-net-01 --net mynet tomcat
065f82e947c760c63539ab4c0de0d683787ec7ac6d0dcaa71f64e191319f9fe7
docker run -d -P --name tomcat-net-02 --net mynet tomcat
2e85d71afe87c87166786b0bbae2d90eefb969d716fcd78a21173add5956cb12
docker ps
CONTAINER ID    IMAGE      PORTS           NAMES
2e85d71afe87    tomcat      0.0.0.0:32772->8080/tcp  tomcat-net-02
065f82e947c7    tomcat      0.0.0.0:32771->8080/tcp  tomcat-net-01
# 再来查看下
docker network inspect mynet
[
 {
    "Name": "mynet",
    "Id":
"09bd09d8d3a6b33e6d19f49643dab551e5a45818baf4d5328aa7320c6dcfc236",
   ............
    "Containers": {
    
 "065f82e947c760c63539ab4c0de0d683787ec7ac6d0dcaa71f64e191319f9fe7": {
        "Name": "tomcat-net-01",
        "EndpointID":
"d61cef1bc294d7f10fb6d9b728735fc87bed79e4e02f5298374f0fab3e9b2da6",
        "MacAddress": "02:42:c0:a8:00:02",
        "IPv4Address": "192.168.0.2/16",
        "IPv6Address": ""
     },
    
 "2e85d71afe87c87166786b0bbae2d90eefb969d716fcd78a21173add5956cb12": {
        "Name": "tomcat-net-02",
        "EndpointID":
"adbc37a20526c2985c3589382998a3d106ef722662c7b296a57d8a7c8f449f38",
        "MacAddress": "02:42:c0:a8:00:03",
        "IPv4Address": "192.168.0.3/16",
        "IPv6Address": ""
     }
   },
    "Options": {},
    "Labels": {}
 }
]

我们来测试ping容器名和ip试试,都可以ping通

docker exec -it tomcat-net-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.093 ms

docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64
time=0.063 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64
time=0.066 ms

发现,我们自定义的网络docker都已经帮我们维护好了对应的关系
所以我们平时都可以这样使用网络,不使用–link效果一样,所有东西实时维护好,直接域名 ping通。

聊了这么多,我们现在应该可以深刻理解docker的网络了!

网络连通

在这里插入图片描述

docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离:
大家公司项目部署的业务都非常多,假设我们有一个商城,我们会有订单业务(操作不同数据),会有
订单业务购物车业务(操作不同缓存)。如果在一个网络下,有的程序猿的恶意代码就不能防止了,所
以我们就在部署的时候网络隔离,创建两个桥接网卡,比如订单业务(里面的数据库,redis,mq,全
部业务 都在order-net网络下)其他业务在其他网络。

那关键的问题来了,如何让 tomcat-net-01 访问 tomcat1?

# 启动默认的容器,在docker0网络下
 docker run -d -P --name tomcat01 tomcat
bcd122e0dcf6bf8c861eaa934911f98a5497a4954f3fde9575e496160bd23287
 docker run -d -P --name tomcat02 tomcat
6183aaeca003a3e5a3549a37f9c1040551320ae358807b4aaad547a986afb887
# 查看当前的容器 docker ps
CONTAINER ID    IMAGE        PORTS           NAMES
6183aaeca003    tomcat        0.0.0.0:32774->8080/tcp  tomcat02
bcd122e0dcf6    tomcat        0.0.0.0:32773->8080/tcp  tomcat01
2e85d71afe87    tomcat        0.0.0.0:32772->8080/tcp  tomcat-
net-02
065f82e947c7    tomcat        0.0.0.0:32771->8080/tcp  tomcat-
net-01

我们来查看下network帮助,发现一个命令 connect

docker network --help
Commands:
connect   Connect a container to a network  # 连接一个容器到一个网络
create   Create a network
disconnect Disconnect a container from a network
inspect   Display detailed information on one or more networks
 ls     List networks
prune    Remove all unused networks
 rm     Remove one or more networks

我们来测试一下!打通mynet-docker0

# docker network connect [OPTIONS] NETWORK CONTAINER  
docker network connect mynet tomcat01
//docker network inspect mynet
[
 {
   ......
    "Containers": {
    
 "065f82e947c760c63539ab4c0de0d683787ec7ac6d0dcaa71f64e191319f9fe7": {
        "Name": "tomcat-net-01",
        "EndpointID":
"d61cef1bc294d7f10fb6d9b728735fc87bed79e4e02f5298374f0fab3e9b2da6",
        "MacAddress": "02:42:c0:a8:00:02",
        "IPv4Address": "192.168.0.2/16",
        "IPv6Address": ""
     },
    
 "2e85d71afe87c87166786b0bbae2d90eefb969d716fcd78a21173add5956cb12": {
        "Name": "tomcat-net-02",
        "EndpointID":
"adbc37a20526c2985c3589382998a3d106ef722662c7b296a57d8a7c8f449f38",
        "MacAddress": "02:42:c0:a8:00:03",
        "IPv4Address": "192.168.0.3/16",
        "IPv6Address": ""
     },
     // 发现我们的tomcat01就进来这里了,tomcat01拥有了双ip
    
 "bcd122e0dcf6bf8c861eaa934911f98a5497a4954f3fde9575e496160bd23287": {
        "Name": "tomcat01",
        "EndpointID":
"b2bf2342948e17048d872a4d5603c77e90d0e032439d510e86c10a1acc3928d9",
        "MacAddress": "02:42:c0:a8:00:04",
        "IPv4Address": "192.168.0.4/16",
        "IPv6Address": ""
     }
   },
   ......
 }
]

tomcat01 可以ping通了

docker exec -it tomcat01 ping tomcat-net-01
PING tomcat-net-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=1 ttl=64
time=0.071 ms
64 bytes from tomcat-net-01.mynet (192.168.0.2): icmp_seq=2 ttl=64
time=0.067 ms

tomcat02 依旧ping不通,大家应该就理解了

docker exec -it tomcat02 ping tomcat-net-01
ping: tomcat-net-01: Name or service not known

如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORKCONTAINER 连接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Docker网络原理可以分为四种工作方式:桥接网络、主机网络容器网络和无网络模式。其中,桥接网络是默认的网络模式,Docker守护程序将容器连接到docker0网络,除非使用--network选项指定其他网络模式。主机网络模式允许容器与主机共享网络栈,容器可以直接访问主机的网络资源。容器网络模式则是在容器内部创建一个虚拟网络容器之间可以通过虚拟网络进行通信。无网络模式是指将容器与任何网络隔离,容器之间无法通信也无法访问外部网络。 此外,在Docker的1.8版本中引入了一个称为overlay的新网络模式,它是在1.7版本中对网络部分进行了重构后加入的。这个overlay网络模式可以实现在多个主机上的容器之间进行通信,提供了更高级的网络功能。总的来说,Docker网络原理涵盖了不同的网络模式,可以根据实际需求选择合适的网络配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Docker网络详解——原理篇](https://blog.csdn.net/meltsnow/article/details/94490994)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值