Docker-基础006-Docker网络

学习内容总结来自B站UP主"遇见狂神说"的Docker教学视频: https://www.bilibili.com/video/BV1og4y1q7M4

Docker网络

理解Docker0

在宿主机linux上, 运行ip addr, 查看当前的网卡信息

(root@Aliyun-Alex:/home/alex)# ip addr
# 打印结果
# 第一个 lo 为回环IP 127.0.0.1
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
# 第二个 eth0 为阿里云内网IP 172.19.67.12
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:16:3e:10:69:3c brd ff:ff:ff:ff:ff:ff
    inet 172.19.67.12/20 brd 172.19.79.255 scope global dynamic noprefixroute eth0
       valid_lft 310946826sec preferred_lft 310946826sec
    inet6 fe80::216:3eff:fe10:693c/64 scope link 
       valid_lft forever preferred_lft forever
# 第三个 docker0 为Docker使用的IP 172.17.0.1
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:92:a2:eb:c6 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
    inet6 fe80::42:92ff:fea2:ebc6/64 scope link 
       valid_lft forever preferred_lft forever

在宿主机安装了docker后, 就会新增一个名为docker0的网卡

启动一个容器

现在运行一个tomcat容器, 尝试linux宿主机ping一下tomcat容器, 看是否能ping通

docker run -d -P --name tomcat01 tomcat

查看tomcat容器中的ip地址信息

docker exec -it tomcat01 ip addr
# 可以看到也有两个地址
# 第一个 lo 为回环IP 127.0.0.1
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
# 第二个 eth0@if161 为容器的IP 172.17.0.2
160: eth0@if161: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

发现容器内的IP地址172.17.0.2和宿主机的docker0172.17.0.1属于同一网段, 那么两者就是能ping通的

(root@Aliyun-Alex:/home/alex)# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.077 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.069 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=3.02 ms
64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.060 ms
^C
--- 172.17.0.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 63ms
rtt min/avg/max/mdev = 0.059/0.656/3.016/1.180 ms

再次回到宿主机linux执行ip addr, 发现又多了个网卡 161: veth8dd219c@if160

161: veth8dd219c@if160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 16:71:2b:b0:4c:f2 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::1471:2bff:feb0:4cf2/64 scope link 
       valid_lft forever preferred_lft forever

再启动一个容器

docker run -d -P --name tomcat02 tomcat

在容器中查看ip addr

(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat02 ip addr
# 同样有一个容器内部的IP 162: eth0@if163
162: eth0@if163: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

在宿主机linux执行ip addr, 发现又多了个网卡 163: veth98c33bb@if162

163: veth98c33bb@if162: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether fa:a3:7c:12:d1:a9 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::f8a3:7cff:fe12:d1a9/64 scope link 
       valid_lft forever preferred_lft forever

可以看出规律, 每启动一个容器, 就会给容器分配一个IP, 同时宿主机也多一个IP地址, 且这两个IP地址是有对应关系的

在宿主机的网卡名为宿主机IP序号: vethxxx@if容器IP序号

在容器内的网卡名为容器IP序号: eth0@if宿主机IP序号

这就是veth-pair技术, 就是一对虚拟设备接口, 他们都是成对出现的, 一端连着协议, 一端彼此相连, veth-pair可以充当一个桥梁, 连接各种虚拟网络设备

如OpenStack, OVS, 和Docker容器之间的连接, 都是使用的veth-pair技术

由于这两个容器的IP都是在同一网段内(172.17.0.0), 所以可以相互ping通

(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat01 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.100 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.082 ms

Docker网络桥接图

Docker使用的是Linux的桥接, 宿主机中的docker01是容器间的网桥

只要删除容器, 对应的网桥一对就没了

容器间ping时或连接时, 可否直接通过名字连接, 而不是通过固定写死的ip地址, 即若某个容器的ip地址换了, 不修改连接设置, 依然可以进行连接

可以类比为url的反向解析, 不是直接写死url, 而是给url一个名字, 通过访问名字来访问url, 即使该名字对应的url地址发生了变化, 通过名字也依然可以访问到变化后的url地址

直接使用容器名称, 在容器01中ping容器02, 发生报错

(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat01 ping tomcat02
ping: tomcat02: Name or service not known

通过--link可以解决这个问题

再启动一个容器 tomcat03, 使用 --link 连接 tomcat01

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

进入tomcat03容器中, 直接使用ping tomcat01, 可以ping通

(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat03 ping tomcat01
PING tomcat01 (172.17.0.2) 56(84) bytes of data.
64 bytes from tomcat01 (172.17.0.2): icmp_seq=1 ttl=64 time=0.113 ms
64 bytes from tomcat01 (172.17.0.2): icmp_seq=2 ttl=64 time=0.072 ms
64 bytes from tomcat01 (172.17.0.2): icmp_seq=3 ttl=64 time=0.073 ms
^C
--- tomcat01 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 72ms
rtt min/avg/max/mdev = 0.072/0.086/0.113/0.019 ms

但是反向在 tomcat01 容器中, 直接使用ping tomcat03, 却不能ping通

(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat01 ping tomcat03
ping: tomcat03: Name or service not known

查看tomcat03容器信息, 可以看到 Links 属性, 连接了tomcat01

docker inspect tomcat03
# 在输出结果中可以看到 Links 属性, 连接了tomcat01
"Links": [
	"/tomcat01:/tomcat03/tomcat01"
],

查看tomcat03的/etc/hosts文件也可以看到关联了tomcat01, 这就是--link的实质操作, 在host中添加一个连接信息

(root@Aliyun-Alex:/home/alex)# 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.17.0.2      tomcat01 db68ef67ca80
172.17.0.4      340afdc0bb53

但是现在官方已经不建议使用 --link了, 更加高级的做法是使用自定义网络

自定义网络

查看所有docker网络docker network ls

(root@Aliyun-Alex:/home/alex)# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
35b249810e67        bridge              bridge              local
de155dd42929        host                host                local
c8ffb814685e        none                null                local

网络连接模式

  • bridge(桥接模式): docker0就是docker容器间的桥梁
  • none: 不配置网络
  • host: 和宿主机共享网络

当直接启动容器时, 默认使用的一个参数是 --net bridge, 这个bridge就是docker0网卡

docker run -d -P tomcat
# 即为
docker run -d -P --net bridge tomcat

我们可以不使用bridge(docker0) ,而是自己创建一个网络

创建网络

# --driver bridge 网络连接模式, 默认为bridge, 因此这里也可以不写这个参数
# --subnet 子网
# --getway 网关
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
# 查看网络
docker network ls
# 结果多了mynet
NETWORK ID          NAME                DRIVER              SCOPE
35b249810e67        bridge              bridge              local
de155dd42929        host                host                local
8e7819b11d29        mynet               bridge              local
c8ffb814685e        none                null                local

查看mynet具体网络信息

(root@Aliyun-Alex:/home/alex)# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "8e7819b11d292e30e36a38095dc4b30f310affc9841b4500f5851c670a7f9b48",
        "Created": "2020-07-30T17:41:46.204861397+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": {}
    }
]

使用自定义网络, 启动容器

启动两个容器 tomcat01 和 tomcat02

docker run -d -P --name tomcat01 --net mynet tomcat
docker run -d -P --name tomcat02 --net mynet tomcat

再次查看mynet具体网络信息, 可以看到关联的容器

(root@Aliyun-Alex:/home/alex)# docker network inspect mynet 

                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "282a1cd78979de4afcfb24b10fd9c322e21f1eb01879cf5e02918a7dfc9945a4": {
                "Name": "tomcat01",
                "EndpointID": "2eccabd1b12d555cdbc4fd0a66e9618a3f0df40f6dd7199c94f01caa2b6c1d15",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            },
            "680e66da888e5c18cff7aae19f51c5189127405a54547925f4482b955a604e79": {
                "Name": "tomcat02",
                "EndpointID": "7ce54ee89ba6332ce67920ba687c9af83ba1fd5407aca4e91fcf9e5c23cb5959",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

容器间使用容器名相互ping通

之前使用容器名来ping是ping不同的, 且就算使用了--link也只能单向使用容器名ping通

现在双向都使用容器名ping通试试看

  • 在容器 tomcat01 中ping 容器 tomcat02, 发现可以ping通
(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat01 ping tomcat02
PING tomcat02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.118 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.076 ms
64 bytes from tomcat02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.093 ms
^C
--- tomcat02 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 8ms
rtt min/avg/max/mdev = 0.076/0.095/0.118/0.020 ms
  • 在容器 tomcat02 中ping 容器 tomcat01, 发现也可以ping通
(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat02 ping tomcat01
PING tomcat01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.101 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.095 ms
^C
--- tomcat01 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 3ms
rtt min/avg/max/mdev = 0.095/0.098/0.101/0.003 ms

发现通过自定义网络比docker0使用起来更加方便, 推荐使用自定义网络

网络连通

在前面的步骤中, mynet网络上连接了两个容器, 分别是tomcat01和tomcat02, 他们的网段是192.168.0.0

我们现在使用默认的网络docker0再创建两个容器tomcat03和tomcat04, 他们的网段是172.17.0.0

docker run -d -P --name tomcat03 tomcat
docker run -d -P --name tomcat04 tomcat

现在的网络结构如下:

(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

直接尝试连接, 发现tomcat02并不能ping通03

但是我们可以做一个操作, 如果将tomcat02能与Docker0连接, 那么就能和tomcat03和tomcat04连接

docker network命令中有一个connect命令

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

Run 'docker network COMMAND --help' for more information on a command.

这个命令可以将一个网络连接入一个容器中

(root@Aliyun-Alex:/home/alex)# docker network connect --help

Usage:  docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

Options:
      --alias strings           Add network-scoped alias for the container
      --driver-opt strings      driver options for the network
      --ip string               IPv4 address (e.g., 172.30.100.104)
      --ip6 string              IPv6 address (e.g., 2001:db8::33)
      --link list               Add link to another container
      --link-local-ip strings   Add a link-local address for the container

将网络docker0连接容器tomcat02

docker network connect bridge tomcat02

查看tomcat02的信息, 找到网络属性, 发现该容器有两个网络属性(mynetbridge)和两个IP(192.168.0.3172.17.0.4)

docker inspect tomcat02
# 打印结果
"bridge": {                                                                                                            
    ...
    "NetworkID": "35b249810e679e94e48b0dce387ad422fe4241c3335f82355cf919a56d96bc0c",                                   
    "EndpointID": "cf79813e3322df01cd9e693a0e42d803a26d0f2bf29762e82c5d28c9fa900710",
    "Gateway": "172.17.0.1",
    "IPAddress": "172.17.0.4",
    ...
},
"mynet": {
    ...
    "NetworkID": "8e7819b11d292e30e36a38095dc4b30f310affc9841b4500f5851c670a7f9b48",
    "EndpointID": "7ce54ee89ba6332ce67920ba687c9af83ba1fd5407aca4e91fcf9e5c23cb5959",
    "Gateway": "192.168.0.1",
    "IPAddress": "192.168.0.3",
    ...
}

或者查看网络 docker0 的信息, 可以看到有三个容器连接上了, tomcat02/tomcat03/tomcat04

docker inspect bridge
# 打印结果
"Containers": {                                                                                                                
        "1152c9fa07e21798589e2f36de0dc9529b104b65f95fe4749b54b557cf51fa0c": {                                                   
            "Name": "tomcat03",
            ...
            "IPv4Address": "172.17.0.2/16",
	},
    "680e66da888e5c18cff7aae19f51c5189127405a54547925f4482b955a604e79": {
        "Name": "tomcat02",
        ...
        "IPv4Address": "172.17.0.4/16",
	},
    "daf280a8066191e42a4e80168ecb0bc285e9ef92a01723c3d862a0b18b2d38f8": {
        "Name": "tomcat04",
        ...
        "IPv4Address": "172.17.0.3/16",
	}
}

此时网络结构如下:

现在测试tomcat02去ping容器tomcat03或者tomcat04

(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known

发现依然ping不通, 回想一下, 想起了之前说过了Docker0这个网卡默认情况不支持直接通过容器名去ping

那么测试用tomcat02去ping容器tomcat03的IP地址172.17.0.2或者tomcat04的IP地址172.17.0.3, 发现可以ping通

(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat02 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.134 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.080 ms
^C
--- 172.17.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 48ms
rtt min/avg/max/mdev = 0.080/0.107/0.134/0.027 ms

那么反过来, 我们将tomcat03连接到mynet网络下, 在自定义的网络中, 是可以实现通过容器名去ping的

docker network connect mynet tomcat03

现在网络结构如下:

在测试用tomcat03去ping容器tomcat01, 发现可以ping通

(root@Aliyun-Alex:/home/alex)# docker exec -it tomcat03 ping tomcat01
PING tomcat01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.112 ms
64 bytes from tomcat01.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.091 ms
^C
--- tomcat01 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 2ms
rtt min/avg/max/mdev = 0.091/0.101/0.112/0.014 ms

那么结论就是:

想要不同网段的容器间连接, 需要通过docker network connect network_name docker_name将容器加入到目标网络中即可, 且目标网络最好是自定义的网络, 在自定义的网络中才能直接使用容器名ping通, 而默认的网络docker0(bridge)中只能使用IP地址ping通

原文地址:https://www.cnblogs.com/gcxblogs/p/13410600.html