【Docker笔记05】【网络模式】

一、前言

本系列是根据 B 站 尚硅谷 Docker 视频 学习记录笔记。因为没有视频课件,部分内容摘自 https://www.yuque.com/tmfl/cloud/dketq0

本系列仅为自身学习笔记记录使用,记录存在偏差,推荐阅读原视频内容或本文参考笔记。


系列文章:
【Docker笔记01】【基础内容】
【Docker笔记02】【常用软件安装】
【Docker笔记03】【MySQL 与 Redis的主从安装】
【Docker笔记04】【Dockerfile】
【Docker笔记05】【网络模式】
【Docker笔记06】【容器编排】
【Docker笔记07】【容器监控】


其他推荐文章:

  1. 浅谈容器网络原理

二、简单介绍

docker安装并启动服务后,会在宿主机中添加一个虚拟网卡。

在Docker服务启动前,使用 ifconfig 或 ip addr 查看网卡信息:

  • ens33或eth0:本机网卡
  • lo:本机回环网络网卡
  • 可能有virbr0(CentOS安装时如果选择的有相关虚拟化服务,就会多一个以网桥连接的私网地址的virbr0网卡,作用是为连接虚拟网卡提供NAT访问外网的功能。如果要移除该服务,可以使用 yum remove libvirt-libs.x86_64)

使用 systemctl start docker启动Docker服务后,会多出一个 docker0 网卡。

作用:

  • 容器间的互联和通信以及端口映射
  • 容器IP变动时候可以通过服务名直接网络通信而不受到影响

Docker容器的网络隔离,是通过Linux内核特性 namespace和 cgroup 实现的。


Docker 启动后会产生一个 docker0 的虚拟网桥,如下图:
在这里插入图片描述

四、基本命令

  1. 查看docker 网络模式

    # 查看 docker 网络
    [root@localhost jdk]# docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    434c8b2478c5   bridge    bridge    local
    9a997978179d   host      host      local
    505d72cea94b   none      null      local
    # 查看 network 命令帮助
    [root@localhost jdk]# 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@localhost jdk]# docker network create a_network
    0321393ceb8b7ffe1de1bb658ec683e7dba0f8403a0c474ee72c2bd896cf7438
    [root@localhost jdk]# docker network ls
    NETWORK ID     NAME        DRIVER    SCOPE
    0321393ceb8b   a_network   bridge    local
    434c8b2478c5   bridge      bridge    local
    9a997978179d   host        host      local
    505d72cea94b   none        null      local
    # 删除网络
    [root@localhost jdk]# docker network rm a_network 
    a_network
    [root@localhost jdk]# docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    434c8b2478c5   bridge    bridge    local
    9a997978179d   host      host      local
    505d72cea94b   none      null      local
    
    # 查看网络源数据
    [root@localhost jdk]# docker network inspect bridge 
    [
        {
            "Name": "bridge",
            "Id": "434c8b2478c521bcbd14e1bdbd9b9e0d6c393c0fc9039b878891ef130f813cb2",
            "Created": "2024-03-28T17:20:21.900870152+08:00",
            "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",
                "com.docker.network.bridge.name": "docker0",
                "com.docker.network.driver.mtu": "1500"
            },
            "Labels": {}
        }
    ]
    
    
  2. Docker network 作用 :

    1. 容器间的互联和通信以及端口映射
    2. 容器IP变动时候可以通过服务名直接网络通信而不受影响。

五、网络分类

1. 简介

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

2. 网络模式的作用

Docker 容器内的IP会改变,当启动多个 Docker 容器后,如果其中一个容器关闭或删除后,新启动的容器可能会占用原容器的IP。

如下:新建u1、u2 两个容器后,将u2 容器移除后新建u3 容器,u3 容器会占用 u2 容器原先的ip

# 启动两个容器 u1 和 u2
[root@192 ~]# docker run --name u1 -it ubuntu /bin/bash
root@a40f76b02f32:/# [root@192 ~]# 
[root@192 ~]# docker run --name u2 -it ubuntu /bin/bash
root@28f1845f8908:/# [root@192 ~]# 
[root@192 ~]# 
[root@192 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS          PORTS     NAMES
28f1845f8908   ubuntu    "/bin/bash"   4 seconds ago    Up 3 seconds              u2
a40f76b02f32   ubuntu    "/bin/bash"   11 seconds ago   Up 10 seconds             u1
[root@192 ~]# 
# 查看 u2 容器的 ip 信息 : 172.17.0.3
[root@192 ~]# docker inspect 28f1845f8908 | tail -n 20
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:03",
                    "NetworkID": "dd2946f2d5feb529b371f4106d068184117ae41117470754225e28e8403ed46b",
                    "EndpointID": "fdd0c6a54e4af8f5636cafe71d07baa870579503e83af1ecec6595e210f6240d",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DriverOpts": null,
                    "DNSNames": null
                }
            }
        }
    }
]
# 查看 u1 容器的 ip 信息 : 172.17.0.2
[root@192 ~]# docker inspect a40f76b02f32 | tail -n 20
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:02",
                    "NetworkID": "dd2946f2d5feb529b371f4106d068184117ae41117470754225e28e8403ed46b",
                    "EndpointID": "c01654faf05f3bc8e509ce057f6671a439d6615499f4cfdea74808d50f89948f",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DriverOpts": null,
                    "DNSNames": null
                }
            }
        }
    }
]
# 移除 u2 容器
[root@192 ~]# docker rm -f u2
u2
# 新建 u3 容器
[root@192 ~]# docker run --name u3 -it ubuntu /bin/bash
root@cdb7a6902
[root@192 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS          PORTS     NAMES
cdb7a69023b0   ubuntu    "/bin/bash"   21 seconds ago   Up 19 seconds             u3
a40f76b02f32   ubuntu    "/bin/bash"   3 minutes ago    Up 3 minutes              u1
# u3 容器ip已经占用了 u2 容器ip
[root@192 ~]# docker inspect cdb7a69023b0 | tail -n 20
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:03",
                    "NetworkID": "dd2946f2d5feb529b371f4106d068184117ae41117470754225e28e8403ed46b",
                    "EndpointID": "f8374d1ad6e676d80592d0333b53b53c3ec2bdb17176156ff4a38d1798598709",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DriverOpts": null,
                    "DNSNames": null
                }
            }
        }
    }
]

3. 详细介绍

3.1 bridge 模式

  1. Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一个宿主机内的容器接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
  2. docker run的时候,没有指定–network的话,默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig就可以看到docker0和自己create的network
  3. 网桥docker0创建一对对等虚拟设备接口,一个叫veth,另一个叫eth0,成对匹配:
    1. 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫 veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫做 veth pair)。
    2. 每个容器实例内部也有一块网卡,容器内的网卡接口叫做eth0。
    3. docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。

在这里插入图片描述


如下,可以得知,宿主机的 eth0@if21veth1138365@if20 是一一对应关系, 即上面途中中 eth0 和 veth 的映射关系:

宿主机 通过 ip addr | tail -n 4 命令可以看到 21: veth1138365@if20 内容, 如下

[root@192 ~]# ip addr | tail -n 4
21: veth1138365@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether da:b9:2f:97:a3:b0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::d8b9:2fff:fe97:a3b0/64 scope link 
       valid_lft forever preferred_lft forever

容器中通过 ip addr 命令可以看到 20: eth0@if21: 的内容,

[root@192 ~]# docker run -it tomcat:7 /bin/bash
root@47ea54bf9136:/usr/local/tomcat# 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
20: eth0@if21: <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

3.2 host 模式

  1. 直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行 NAT 转换。
  2. 容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network space。
  3. 容器将不会虚拟出自己的网卡,而是直接使用宿主机的 IP 和端口。

在这里插入图片描述


如下:

# 使用 host 模式启用 tomcat,可以直接通过宿主机IP + 8080 端口访问 tomcat
[root@192 ~]# docker run -d --network host --name tom_host tomcat:7 

需要注意:

  1. 通过 docker inspect tom_host 命令查看通过 host 模式启动的容器,可以看到其网络模式为 host,并且因为容器使用的主机的网络IP(可以直接通过宿主机IP + 8080 端口访问 tomcat) ,所以 Gateway、IPAddress 都为空

    在这里插入图片描述

  2. 如果在 docker run 命令中同时使用了 --network host 和 -p端口映射,则会出现如下警告:

    [root@192 ~]# docker run -d -p 8083:8080 --network host --name tom_host1 tomcat:7 
    WARNING: Published ports are discarded when using host network mode
    1f16087c5322ed824f4ae9068788064dec16fe652f2429e3deb811b659735b3a
    

    因为此时已经使用了host模式,本身就是直接使用的宿主机的IP和端口,此时的-p端口映射就没有了意义,也不会生效,端口号还是会以主机端口号为主。

    正确做法是:不再进行-p端口映射,或者改用bridge模式

3.3 none 模式

none 模式会禁用网络功能。在none模式下,并不为docker容器进行任何网络配置。进入容器内,使用 ip addr查看网卡信息,只能看到 lo(本地回环网络127.0.0.1网卡)。

如下:

[root@192 ~]# docker run -d --network none --name tom_none tomcat:7 
e41b460b6c11a032f97e4ae8172a434a8832dda98673beb366112c400862a3d1
[root@192 ~]# 
[root@192 ~]# 
[root@192 ~]# docker ps
CONTAINER ID   IMAGE      COMMAND             CREATED          STATUS          PORTS     NAMES
e41b460b6c11   tomcat:7   "catalina.sh run"   3 seconds ago    Up 2 seconds              tom_none
19929b93c3c1   tomcat:7   "catalina.sh run"   10 minutes ago   Up 10 minutes             tom_host
[root@192 ~]# 
[root@192 ~]# 
[root@192 ~]# 
[root@192 ~]# docker exec -it tom_none /bin/bash
root@e41b460b6c11:/usr/local/tomcat# 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

3.4 container 模式

新建的容器和已经存在的一个容器共享网络IP配置,而不是和宿主机共享。

新创建的容器不会创建自己的网卡、IP,而是和一个指定的容器共享IP、端口范围。两个容器除了网络共享,其他的如文件系统、进程列表依然是隔离的。
在这里插入图片描述

[root@192 ~]# docker run -it --name alpine_bridge alpine /bin/sh

# 指定和 alpine_bridge 容器共享网络
[root@192 ~]# docker run -it --network container:alpine_bridge --name alpine_container alpine /bin/sh
/ # [root@192 ~]# 
[root@192 ~]# 
[root@192 ~]# docker ps
CONTAINER ID   IMAGE      COMMAND             CREATED          STATUS          PORTS      NAMES
5c43081ef94c   alpine     "/bin/sh"           3 seconds ago    Up 3 seconds               alpine_container
4f6f1d00e4ca   alpine     "/bin/sh"           35 seconds ago   Up 34 seconds              alpine_bridge

此时使用 ip addr查看两台容器的网络,会发现两台容器的eth0网卡内的IP等信息完全相同。

如果关掉了alpine_bridge 容器,因为alpine_container的网络使用的alpine_bridge 共享网络,所以关掉 alpine_bridge 后,alpine_container的eth0网卡也随之消失了。


需要注意:

  1. 如下:因为 container 模式下两个容器公用 IP 端口信息,因此启用第二个容器时因为 8080 端口被占用导致启动失败。
    [root@192 ~]# docker run -d  --name tom_bridge tomcat:7 
    67e7f5ae6f9ed22f535b975f096dc3d1553c5a6ec1c2e1f5dd8562f83361a987
    [root@192 ~]# 
    [root@192 ~]# docker ps
    CONTAINER ID   IMAGE      COMMAND             CREATED          STATUS          PORTS      NAMES
    67e7f5ae6f9e   tomcat:7   "catalina.sh run"   3 seconds ago    Up 3 seconds    8080/tcp   tom_bridge
    e41b460b6c11   tomcat:7   "catalina.sh run"   3 minutes ago    Up 3 minutes               tom_none
    19929b93c3c1   tomcat:7   "catalina.sh run"   13 minutes ago   Up 13 minutes              tom_host
    [root@192 ~]# docker run -d -p 8081:8080 --network container:tom_bridge --name tom_container tomcat:7 
    docker: Error response from daemon: conflicting options: port publishing and the container type network mode.
    See 'docker run --help'.
    

3.5 自定义网络模式

# 创建两个容器
[root@192 ~]# docker run -d --name tom1 tomcat:7 
b1bfe74b3fb47974159ce1c5be9e98a87dfca7467bb0c585b566ae36417ddb64
[root@192 ~]# docker run -d --name tom2 tomcat:7 
3c7bd1ccfbc636a48127af15b759eda4858057e9c6f73346d59a34d3b0fb0dbd
[root@192 ~]# docker ps
CONTAINER ID   IMAGE      COMMAND             CREATED          STATUS          PORTS      NAMES
3c7bd1ccfbc6   tomcat:7   "catalina.sh run"   54 seconds ago   Up 53 seconds   8080/tcp   tom2
b1bfe74b3fb4   tomcat:7   "catalina.sh run"   58 seconds ago   Up 57 seconds   8080/tcp   tom1
[root@192 ~]# docker exec -it  tom1 /bin/bash
# 通过 容器名无法互相 ping 通,如果通过固定IP则容器的固定IP会变化
root@b1bfe74b3fb4:/usr/local/tomcat# ping tom1
ping: tom1: Name or service not known

# 1. 自定义网络模式,默认使用的是桥接模式
[root@192 ~]# docker network create kingfish_network
0e49e8d8480d630ef3d97caf5eec330c9a11a249211f53b49609eeecc2a7ad81
[root@192 ~]# docker network ls
NETWORK ID     NAME               DRIVER    SCOPE
dd2946f2d5fe   bridge             bridge    local
9a997978179d   host               host      local
0e49e8d8480d   kingfish_network   bridge    local
505d72cea94b   none               null      local

# 使用自定义的网络模式创建容器
[root@192 ~]# docker run -d --network kingfish_network --name tom_1 tomcat:7 
5492cafbe433e4e47fc0f95a182954eb6a0213dd9838f16df054ff6009e54937
[root@192 ~]# docker run -d --network kingfish_network --name tom_2 tomcat:7 
da0cd3f3641aaca58adb2c464f4f1d43e059aec7dcd151fe03aae901f95ab1d5
# 进入其中一个容器
[root@192 ~]# docker exec -it tom_1 /bin/bash
# 可以通过容器名称 PING 通服务
root@5492cafbe433:/usr/local/tomcat# ping tom_2
PING tom_2 (172.18.0.3) 56(84) bytes of data.
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=2 ttl=64 time=0.043 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=3 ttl=64 time=0.142 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=4 ttl=64 time=0.213 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=5 ttl=64 time=0.061 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=6 ttl=64 time=0.059 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=7 ttl=64 time=0.063 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=8 ttl=64 time=0.178 ms
64 bytes from tom_2.kingfish_network (172.18.0.3): icmp_seq=9 ttl=64 time=0.637 ms

需要注意:

  1. docker中还有一个 --link 进行容器网络互联,但是已经被标记为过时的,可能会在将来的版本中移除这个功能,推荐使用自定义网络替换link。Link 命令的使用如下:
    # 启动一台mysql容器
    # --name 为容器指定一个别名
    docker run --name mysql-matomo -p 3308:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.28
    
    # 启动另一个容器,通过--link连接到mysql容器
    # --link 容器名称:本容器连接对方时的别名
    docker run -d -p 8888:80 --link mysql-matomo:db --name matomo matomo:4.9.0
    
    # 此时,在matomo容器中,便可以通过 db 这个hostname连接到mysql-matomo容器,而无须再通过ip
    # 连接地址:db:3306
    

六、补充

下面内容来源于 浅谈容器网络原理, 本篇仅做记录使用:

在 Docker 中,管理容器的网络的是Docker 守护进程(daemon)。在桥接网络模式下,Docker 守护进程会执行以下主要任务:

  1. 创建和管理虚拟网络桥(docker0):Docker 守护进程在启动时会创建 docker0 虚拟网络桥,守护进程负责管理这个网桥的配置和状态,确保容器能够正常通过这个网桥进行通信。

  2. 分配容器的虚拟网络接口和 IP 地址:当用户创建一个新的容器时,Docker 守护进程会为该容器创建一对虚拟的网络接口,并为其容器中的一端分配一个唯一的 IP 地址,另一端连接到docker0 网桥。

    在Linux下,我们通过“ifconfig”命令就可以看到,宿主机出现了以下网络接口,他们就是docker0网桥以及容器“插在”docker0网桥上的veth设备。

  3. 执行网络地址转换(NAT):当容器需要与外部网络通信时,Docker 守护进程会执行网络地址转换。NAT 允许容器使用宿主机的 IP 地址访问外部网络,同时也允许外部网络访问容器提供的服务。

    为什么要进行NAT呢?让我们考虑一种场景:假如容器要访问百度首页,百度的Server要返回给容器数据,如果百度的Server将目的地址设置为容器的IP,由于容器的IP在外部是不可见的,就会导致结果的数据包无法返回,所以在发送请求给百度Server时需要将源IP转换为宿主机的IP。

  4. 管理端口映射(Port Mapping):Docker 守护进程负责管理容器内部端口与宿主机上的端口之间的映射关系。当用户定义了端口映射规则时,守护进程会在宿主机的网络命名空间中设置相应的转发规则,以实现外部网络与容器内部服务的通信。

    为什么要进行端口映射呢?因为容器内部的端口在外部也是无法访问的,需要将宿主机的端口与之进行映射。

七、参考内容

B 站 尚硅谷 Docker 视频
https://www.yuque.com/tmfl/cloud/dketq0
浅谈容器网络原理

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫吻鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值