Docker-高级篇(2)-Docker四大网络&自定义网络

导言

  • 两个或者多个之间的容器如何相互通信?
  • 容器重启后IP变化如何解决?
  • 容器内部间如何通过容器名通信?
  • 如何自定义网络,让同属一个服务群的容器都加入到同一个网络?

一、宿主机网络

  1. Docker网络用于处理宿主机和容器内网络通信
    • 容器间的互联和通信以及端口映射
    • 容器IP变动时候可以通过服务名直接网络通信而不受到影响
  2. docker未启动情况下,宿主机的网络情况
    • 系统通过vagrant安装和启动
    • 此时有eth0和lo(local)两个网卡
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.33.10  netmask 255.255.255.0  broadcast 192.168.33.255
        inet6 fe80::a00:27ff:fe29:956c  prefixlen 64  scopeid 0x20<link>
        ether 08:00:27:29:95:6c  txqueuelen 1000  (Ethernet)
        RX packets 204  bytes 20733 (20.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 144  bytes 23742 (23.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 64  bytes 5184 (5.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 64  bytes 5184 (5.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
复制代码
  1. docker启动情况下,宿主机的网络情况
    • 此时宿主机会产生一个名为docker0的虚拟网桥
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:f7:55:5a:bd  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.33.10  netmask 255.255.255.0  broadcast 192.168.33.255
        inet6 fe80::a00:27ff:fe29:956c  prefixlen 64  scopeid 0x20<link>
        ether 08:00:27:29:95:6c  txqueuelen 1000  (Ethernet)
        RX packets 204  bytes 20733 (20.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 144  bytes 23742 (23.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 64  bytes 5184 (5.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 64  bytes 5184 (5.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
复制代码

二、Docker网络

  1. 查看docker网络模式命令
docker network <COMMAND>
复制代码
  1. 可以使用的命令如下
[root@server01 ~]# docker network --help

Usage:  docker network COMMAND

Manage networks

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
复制代码
  1. 查看网卡列表
[root@server01 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
ad11a58c25cc   bridge    bridge    local
1524da0505ee   host      host      local
f4cbc4779eaf   none      null      local
复制代码
  1. 可以看到默认创建3大网络模式
  2. 查看网卡信息
[
  {
    "Name": "bridge",
    "Id": "ad11a58c25cc80747576c2ef7c2ca09b960fe0565b4c6ab7032ed9dfdba94ca2",
    "Created": "2022-03-20T12:41:29.966511242Z",
    "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": {},
    "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",
      # 可以看到bridge用的网桥名称就是docker0
      "com.docker.network.bridge.name": "docker0",
      "com.docker.network.driver.mtu": "1500"
    },
    "Labels": {}
  }
]
复制代码
  1. 创建和删除网卡
# 原始所有网卡信息
[root@server01 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
ad11a58c25cc   bridge    bridge    local
1524da0505ee   host      host      local
f4cbc4779eaf   none      null      local
# 创建网卡
[root@server01 ~]# docker network create my_network
146a5d4683a8ef8256ce5280eabb719c5d7da061f317f03529dedbf4fe8ee2a5
[root@server01 ~]# docker network ls
NETWORK ID     NAME         DRIVER    SCOPE
ad11a58c25cc   bridge       bridge    local
1524da0505ee   host         host      local
# 默认创建的网卡类型是桥接类型
146a5d4683a8   my_network   bridge    local
f4cbc4779eaf   none         null      local
# 删除网卡
[root@server01 ~]# docker network rm my_network
my_network
[root@server01 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
ad11a58c25cc   bridge    bridge    local
1524da0505ee   host      host      local
f4cbc4779eaf   none      null      local
复制代码

三、网络模式

image.png

3.1 bridge模式

  1. Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,将所有容器和本地主机都放到同一个物理网络
  2. Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信
  3. 为每一个容器分配和设置ip,并将容器连接到docker0,虚拟网桥默认为该模式
  4. 使用 --network bridge 指定容器使用的网络模式,默认bridge(docker0)
  5. Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为容器ip(Container-IP),同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信
  6. docker run 的时候,如果没有指定network则默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig可以看到docker0和创建的的networketh0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
  7. 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配
    • 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair
    • 每个容器实例内部同时有一块网卡,每个接口叫eth0
    • docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。 通过配对网卡,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络互通

image.png

  1. 运行alpine(一个微型的linux版本) 容器,进入redis容器内容查看网络信息和宿主机网络信息
    • docker pull alpine
    • docker run -d --name alpine alpine:latest
    • docker exec -it apline bash
    • alpine容器内部
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
# eth0@if11:表示连接到宿主机的11号网卡信息
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
复制代码
  • 宿主机网络信息
# veth02096c1@if10:表示连接到容器内部的10号网卡
11: veth02096c1@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether fe:e5:f2:56:6d:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::fce5:f2ff:fe56:6d07/64 scope link
       valid_lft forever preferred_lft forever
复制代码
  • 对应关系如下

image.png

3.2 host模式

  1. 直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换
  2. 使用--network host指定
  3. 查看host网卡信息
[
    {
        "Name": "host",
        "Id": "1524da0505eef1c3f188e337551fe0259b99c3e00915fd9eafea288aa4ec69c9",
        "Created": "2022-03-06T06:55:13.717636641Z",
        "Scope": "local",
        # 驱动为host
        "Driver": "host",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

复制代码
  1. 容器不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace,不会虚拟出自己的网卡而是使用宿主机的IP和端口

image.png

  1. docker run -d -p ip:ip --network host --name xxx xxxImage
    • 在host模式下无需通过ip来指定端口映射,因为使用的是宿主机的端口和ip
    • docker通过指定--network=host或-net=host启动的容器不能指定端口映射,将会抛出警告
    • 直接执行 docker run -d --network host --name xxx xxxImage 即可

3.3 none模式

  1. 容器有独立的 Network namespace,但并没有对齐进行任何网络设置,如分配veth pair和网卡连接、ip等
  2. 实际中使用较少,因为Docker容器没有网卡、IP、路由等信息,只有一个lo(local表示本地回环),需要我们自己为Docker容器添加网卡、配置IP等
  3. none模式:使用--network none指定
  4. 查看none网卡信息
[
    {
        "Name": "none",
        "Id": "f4cbc4779eafdf5bc4d2fd948ded3e0f8b99c2d2aac425123bda050d58eef0a3",
        "Created": "2022-03-06T06:55:13.712122716Z",
        "Scope": "local",
        # 驱动为空
        "Driver": "null",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
复制代码
  1. 如果容器启动在此模式下,内部将只有lo地址

3.4 container模式

  1. 新建的容器和已经存在的一个容器共享网络ip和配置,而不会创建自己的网卡,配置自己的IP等
  2. 两个容器除了网络方面,其他的如文件系统、进程列表等依然隔离
  3. 使用--network container:NAME 或者容器ID指定
  4. 先运行基础容器
    • docker run -it --name alpine alpine:latest
[root@server01 ~]# docker run -it --name alpine alpine:latest
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
复制代码
  1. 再运行alpine,然后指定基础基础容器
    • docker run -it --network container:alpine --name alpine-01 alpine:latest
[root@server01 ~]# docker run -it --network container:alpine --name alpine-01 alpine:latest
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
复制代码
  1. 关闭基础容器,然后再查看alpine-01
    • 此时只有本地回环地址,共享的网络已经没有了
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
复制代码
  1. 所以基于容器模式网络直接依赖性比较强,基础容器网络中断将会导致所有基于此网络的容器全部受到影响

四、网络IP生产规则

  1. docker容器内部的ip是在容器启动时进行分配,所以ip可能会发生改变
    • docker inspect redis | tail -n 20
"Networks": {
    "bridge": {
        "IPAMConfig": null,
        "Links": null,
        "Aliases": null,
        "NetworkID": "ad11a58c25cc80747576c2ef7c2ca09b960fe0565b4c6ab7032ed9dfdba94ca2",
        "EndpointID": "48f16e0663e908688490e3a1fdc688a1b1c28d706ee631facb0c367e343dce76",
        # 默认的网关就是docker0
        "Gateway": "172.17.0.1",
        # 本次分配的ip
        "IPAddress": "172.17.0.2",
        "IPPrefixLen": 16,
        "IPv6Gateway": "",
        "GlobalIPv6Address": "",
        "GlobalIPv6PrefixLen": 0,
        "MacAddress": "02:42:ac:11:00:02",
        "DriverOpts": null
    }
}
复制代码
  1. 可以关闭此容器,然后重新运行一个新容器,可以返回ip和上面的可能一样,所以ip会变动

五、自定义网络

  • 之前的links技术已经过时

image.png

  1. 在各自容器内部,通过ip可以ping通,但是通过服务名(--name 指定的名称)缺无法ping通
  2. 自定义桥接网络,自定义网络默认使用的是桥接网络bridge
    • docker network create my_network
  3. 新建容器加入上一步新建的自定义网络
    • docker run -d --network my_network --name alpine01 alpine:latest
    • docker run -d --network my_network --name alpine02 alpine:latest
  4. 原理:自定义网络维护好了主机名和ip的对应关系(ip和域名都能通)
  5. 通过将不同容器加入到同一个网络,就可以实现通过容器名称访问,无论容器如何重启都无需改动依赖服务

猜你喜欢

转载自juejin.im/post/7103694519203266567
今日推荐