Docker的网络

本文最后更新于 2024年12月5日

Docker的网络用于容器间的互联和通信,以及宿主机端口映射,容器IP变动的时候可以设置网络直接使用服务名进行网络通信而不受影响。类似于虚拟机软件分配IP地址给各个安装的虚拟机以及物理机,虚拟机之间以及虚拟机和物理机之间可以相互通信。

1.查看容器的网络

1.查看容器网络类型

docker inspect命令查看关于Networks的部分

docker inspect 容器ID

当前容器是bridge网络,网关是172.17.0.1, IP是172.17.0.2

"Networks": {
              "bridge": {
                  "IPAMConfig": null,
                  "Links": null,
                  "Aliases": null,
                  "NetworkID": "2def63006d0705d822ebd7269baf1512be0fc886c40e9047f35635ef21585b33",
                  "EndpointID": "4fd79243a84032b34a57a39b0ffc03136bef175498980abdc097117e17f135fe",
                  "Gateway": "172.17.0.1",
                  "IPAddress": "172.17.0.2",
                  "IPPrefixLen": 16,
                  "IPv6Gateway": "",
                  "GlobalIPv6Address": "",
                  "GlobalIPv6PrefixLen": 0,
                  "MacAddress": "02:42:ac:11:00:02",
                  "DriverOpts": null
              }
          }

2.查看当前有多少个docker网络

docker network ls
[root@localhost ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
2def63006d07        bridge              bridge              local
f8b834999d26        host                host                local
fd9dc003ef95        lzjnet              bridge              local
2ca13d3f5552        none                null                local

3.查看网络的情况

docker network inspect 网络名

网络lzjnet的网络类型是bridge,还有IP等信息

[
    {
        "Name": "lzjnet",
        "Id": "fd9dc003ef956e7b3f01d74b81f5fc6cc04c76ce5144beadc9707dd4a7a41134",
        "Created": "2024-11-26T23:12:55.276879774+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

2.Docker的网络类型

几种常见的网络类型

网络模式 简介
bridge 默认为该模式,为每一个容器分配和设置IP,并将容器连接到默认的虚拟网桥docker0
host 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
none 容器有独立的network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接,IP等
container 新创建的容器不会自动创建自己的网卡和配置IP,而是和一个指定的容器共享IP和端口范围等

2.1 bridge网络

1.主机和容器联网

Docker服务默认会创建一个网桥(上有一个docker0的内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker默认指定了docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥相互通信。

2.容器之间联网

Docker启动一个容器时会根据docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关,因为在同一宿主机内的容器都接入同一网桥,这样容器之间就可以通过容器的Container-IP直接通信。

3.bridge网络的分配机制

docker run的时候,没有指定network的话,默认使用的网桥模式就是bridge(docker0)。在宿主机ifconfig就可以看见docker0和自己创建的网络(eth0, eth1…..),lo代表127.0.0.1。

网桥docker0创建一对对等的虚拟设备接口,一个叫veth,另一个叫eth0,成对匹配。

整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair)

每个容器内部也有一块网卡,每个接口叫eth0,docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。

验证veth-pair:

查看正在运行的Docker容器

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
38188376416b        tomcat              "catalina.sh run"   About a minute ago   Up About a minute   8080/tcp            inspiring_austin

宿主机执行ip addr查看宿主机的网络情况

[root@localhost ~]# 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:44:65:de brd ff:ff:ff:ff:ff:ff
    inet 192.168.228.104/24 brd 192.168.228.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::2ac6:ec4:9411:4da8/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ff:ca:bc:ec 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:ffff:feca:bcec/64 scope link 
       valid_lft forever preferred_lft forever
15: vethc5f3f03@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 26:9a:2e:de:95:5a brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::249a:2eff:fede:955a/64 scope link 
       valid_lft forever preferred_lft forever

进入容器,一般需要先更新tomcat容器的yum,再安装工具iproute2

sudo apt-get update

sudo apt-get upgrade

apt-get install -y iproute2

然后,在容器内执行ip addr查看容器的网络情况

root@38188376416b:/# 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
14: eth0@if15: <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

然后可见宿主机的网卡 15: vethc5f3f03@if14 和容器网卡 14: eth0@if15两两匹配,互互相同

2.2 host网络

直接使用宿主机的IP地址与外界通信,不需要额外进行NAT转换。

容器将不再获得一个独立的网络名称空间,而是和宿主机共用一个网络名称空间,容器将不会虚拟出自己的网卡,而是使用宿主机的IP和端口,容器没有自己的IP。

这种模式下,使用-p端口映射是无效的,也是没有任何意义的。

2.3 none网络

等同于禁用网络功能,不为容器进行任何网络配置,容器没有网卡,路由等信息,只有一个本地回环网卡lo

2.4 container网络

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

需要注意的是:

1.继承和被继承的容器的容器内端口不能是相同的,否则会导致冲突,因为两个容器共享网段和IP

验证:先启动一个tomcat容器tomcat86,该容器内的程序会占用容器的8080,在启动另一个tomcat容器tomcat87和前者共享网络,因为也是基于tomcat镜像,所以同样会占用容器的8080,两个容器端口范围是共享的,导致报错Error response from daemon: conflicting options: port publishing and the container type network mode.

docker run -d --privileged=true -p 8086:8080  --name tomcat86    tomcat

docker run -d --privileged=true -p 8086:8080 --network container:tomcat86  --name tomcat87    tomcat
[root@localhost ~]# docker run -d --privileged=true -p 8086:8080  --name tomcat86    tomcat
c8464b5448296b51bc5b4e4598acce709513aa6ac7fac6ef335e5a39e8a785f3
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
c8464b544829        tomcat              "catalina.sh run"   4 seconds ago       Up 2 seconds        0.0.0.0:8086->8080/tcp   tomcat86
0bad9102a5a7        alpine              "/bin/sh"           11 minutes ago      Up 11 minutes                                alpine1
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# 
[root@localhost ~]# docker run -d --privileged=true -p 8086:8080 --network container:tomcat86  --name tomcat87    tomcat
docker: Error response from daemon: conflicting options: port publishing and the container type network mode.
See 'docker run --help'.

2.被继承的容器结束运行后,继承它的容器也会失去网络功能,只剩下一个回环网卡lo

验证:先运行一个精简版Linux容器alpine1,在运行一个同样的容器alpine2,指定和alpine1共享网络,查看容器内网络可见网卡名称和IP地址都是完全一样的

docker run -it --name alpine1   alpine /bin/sh
[root@localhost ~]# docker run -it --name alpine1   alpine /bin/sh
/ # 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
16: eth0@if17: <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
docker run -it --name alpine2 --network container:alpine1   alpine /bin/sh
[root@localhost ~]# docker run -it --name alpine2 --network container:alpine1   alpine /bin/sh
/ # 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
16: eth0@if17: <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

关闭容器alpine1,进入容器alpine2查看IP,发现eth网卡跟着消失了,只剩下lo

[root@localhost ~]# docker stop alpine1
alpine1
[root@localhost ~]# docker exec -it alpine2 /bin/sh
/ # 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

2.5 自定义网络

为什么要自定义网络?

1.容器间的互联和通信以及端口映射
2.bridge模式网络分配给容器的IP是可能随着容器的启动关闭而导致分配的地址发生变动的,但是Docker自带的bridge网络比较简单,没有内置DNS功能,自定义网络后,容器IP变动的时候可以通过服务名直连网络而不受影响,当用户创建自定义网络时,Docker自动配置了一个内置DNS服务器,这个DNS服务器会根据容器的名称自动解析对应的IP地址。

自定义网络默认也是采用桥接模式bridge,只是功能比默认的那个更强,自然就维护好了容器名和IP的映射关系(DNS)

验证:

创建一个网络lzjnet

docker network create lzjnet

创建容器tomcat1 tomcat2,指定我们自己创建的网络,然后互PING

docker run -it --privileged=true  --network lzjnet   --name alpine81    alpine

docker run -it --privileged=true  --network lzjnet   --name alpine82    alpine
[root@localhost ~]# docker attach alpine81
/ # ping alpine82
PING alpine82 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.889 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.195 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.181 ms
64 bytes from 172.18.0.3: seq=3 ttl=64 time=0.167 ms
64 bytes from 172.18.0.3: seq=4 ttl=64 time=0.547 ms
^C
--- alpine82 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.167/0.395/0.889 ms
[root@localhost ~]# docker attach alpine82
/ # ping alpine81
PING alpine81 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.079 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.133 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.169 ms
64 bytes from 172.18.0.2: seq=3 ttl=64 time=0.186 ms
64 bytes from 172.18.0.2: seq=4 ttl=64 time=0.663 ms
64 bytes from 172.18.0.2: seq=5 ttl=64 time=0.260 ms
64 bytes from 172.18.0.2: seq=6 ttl=64 time=0.176 ms
^C
--- alpine81 ping statistics ---
7 packets transmitted, 7 packets received, 0% packet loss
round-trip min/avg/max = 0.079/0.238/0.663 ms

可以发现可以使用容器名相互PING通

3.总结

Docker可以使用4种网络模式来实现容器之间以及和宿主机的网络通信,自己实现自定义的网络桥接模式功能更强。


Docker的网络
https://blog.liuzijian.com/post/1c03a9f4-ae21-423a-07be-795390034f15.html
作者
Liu Zijian
发布于
2024年1月24日
更新于
2024年12月5日
许可协议