小哥之哥 小哥之哥
首页
    • Prometheus
    • Kubertenes
    • Docker
    • MySQL
  • Go
  • Python
  • Vue
  • Jenkins
  • ELK
  • LDAP
  • 随笔
  • 最佳实践
  • 博客搭建
  • 问题杂谈
关于
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

小哥之哥

运维扫地僧
首页
    • Prometheus
    • Kubertenes
    • Docker
    • MySQL
  • Go
  • Python
  • Vue
  • Jenkins
  • ELK
  • LDAP
  • 随笔
  • 最佳实践
  • 博客搭建
  • 问题杂谈
关于
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Kubertenes

  • Prometheus

  • Docker

    • Docker实战

    • Docker杂谈

      • Namespace和Cgroups
      • Docker网络
        • Docker 存储引擎
    • 数据库

    • 运维利器

    • 运维
    • Docker
    • Docker杂谈
    tchua
    2023-02-16
    目录

    Docker网络

    # 一、Docker网络模式

    Docker网络模式有四种模式(其实也可以说5种):

    • bridge(默认):容器使用独立net namespace,会为每一个容器分配,设置IP等,并将容器连接到一个docker0 的虚拟网桥,通过docker 0 网桥以及iptables nat 表配置与宿主机通信。
    • host: 和宿主机公用同一个net namespace,容器中的网络环境和宿主机一模一样。
    • container: 创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP,端口范围。
    • none: :对于此容器,禁用所有联网。通常与自定义网络驱动程序一起使用。
    • 自定义(Macvlan):Macvlan网络允许您为容器分配MAC地址,使其在网络上显示为物理设备。Docker守护程序通过其MAC地址将流量路由到容器。在处理希望直接连接到物理网络而不是通过Docker主机的网络堆栈进行路由的旧应用程序时,使用macvlan驱动程序有时是最佳选择。

    总结

    其实,Docker这几种网络模式也可以理解为,是否跟宿主机或者是否跟其它容器共享Network namespace而延伸出来的网络模式。

    # 二、网络模式应用场景

    # 2.1 bridge 模式

    bridge 模式是Docker默认网络驱动模式,容器使用独立的NetWork NameSpace。 Docker进程启动时,会在宿主机上创建一个名为docker0的虚拟网卡,同一个宿主机上的容器,都会连接到这个虚拟网卡上面,通过此网卡进行与外部或者与其它容器通信。

    启动的容器都会从 docker0 子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关,在主机上创建一堆虚拟网卡 veth pair 设备,veth pair 是一种成对出现的特殊网络设备,可以把他们想象成由一根虚拟网线连接起来的一对网卡,网卡的一头(eth0)在容器中,另一头(veth**)挂在网桥 docker0 上。具体的原理参考下面网络通信原理。

    拓扑

    image-20230216144018883

    示例

    # 启动三个容器 默认就是bridge模式
    [root@localhost ~]# docker run -d --name nginx-b1 nginx:latest
    [root@localhost ~]# docker run -d --name nginx-b2 nginx:latest
    [root@localhost ~]# docker run -d --name nginx-b3 nginx:latest
    # 通过ip a可以看到创建的veth虚拟网络设备
    [root@localhost ~]# ip a
    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: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
        link/ether 00:50:56:a4:78:54 brd ff:ff:ff:ff:ff:ff
        inet 10.66.31.130/24 brd 10.66.31.255 scope global noprefixroute ens192
           valid_lft forever preferred_lft forever
        inet6 fe80::1a49:7ad8:da9b:d0b4/64 scope link tentative noprefixroute dadfailed 
           valid_lft forever preferred_lft forever
        inet6 fe80::f3f0:e911:6ed:35db/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:e1:fc:20:ef 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:e1ff:fefc:20ef/64 scope link 
           valid_lft forever preferred_lft forever
    21: vethaad56ba@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether 9a:b1:5b:f5:ee:e4 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet6 fe80::98b1:5bff:fef5:eee4/64 scope link 
           valid_lft forever preferred_lft forever
    23: veth8dd5b8a@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether ee:12:83:d0:7a:34 brd ff:ff:ff:ff:ff:ff link-netnsid 1
        inet6 fe80::ec12:83ff:fed0:7a34/64 scope link 
           valid_lft forever preferred_lft forever
    25: veth90ba14f@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether 2a:27:bb:f2:3c:b1 brd ff:ff:ff:ff:ff:ff link-netnsid 2
        inet6 fe80::2827:bbff:fef2:3cb1/64 scope link 
           valid_lft forever preferred_lft forever
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    # 2.2 host 模式

    host模式,指的是跟宿主机共享同一个Network Namespace,使用宿主机的IP地址,和宿主机共享端口范围,使用参数--net=host指定。

    示例:

    # 以host模式启动容器
    [root@localhost ~]# docker run -d --name nginx-h1 --net=host nginx:latest
    1a3f2958b84d3987106c3ea1ada3c2cd29f83f51e4c85f531080768f3c80b829
    # 通过查看运行的容器,可以看到PORTS也是没有端口映射的
    [root@localhost ~]# docker ps
    CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS        PORTS     NAMES
    1a3f2958b84d   nginx:latest   "/docker-entrypoint.…"   2 seconds ago   Up 1 second             nginx-h1
    
    1
    2
    3
    4
    5
    6
    7

    访问Nginx:

    image-20230216104231088

    注意

    host模式虽然网络性能比较好(不用docker0转发),使用起来比较方便,但是因为与宿主机共享IP、端口,所以如果运行容器较多,没有合理规范,会导致端口冲突,隔离性不好,也不安全。

    # 2.3 container 模式

    container模式指的是新创建的容器和已经存在的一个容器共享一个Network Namespace,Docker不会给容器分配IP,两个容器除了网络方面一样,其它诸如文件系统,pid等都是隔离的,两个容器网络通信直接是lo网卡通信。

    拓扑:

    image-20230216135236332

    示例:

    # 先启动Container01 
    [root@localhost ~]# docker run -d -it --name busybox-c1  busybox:latest /bin/sh
    # 查看容器IP
    [root@localhost ~]# docker exec busybox-c1 ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
    18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
        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
    
    # 启动Container02
    [root@localhost ~]# docker run -d -it --name busybox-c2 --net=container:busybox-c1  busybox:latest /bin/sh
    # 查看Container02容器IP
    [root@localhost ~]# docker exec busybox-c2 ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
    18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
        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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    可以看到两个容器IP是一样的,其实就类似于在宿主机直接启动2个应用,我们还可以通过查看容器的network namespace是否一样

    image-20230216141444658

    注意

    这种模式比host模式其实多了一层转发,但是隔离性比较好,有一个问题就是跟host模式一样,端口是公用的所以,使用的时候,需要提前规范化应用端口,避免端口冲突。

    # 2.4 none 模式

    --net=none指定

    none模式下,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。容器只有回环地址lo,因为无法联网与外部通信,所以此模式安全性比较好,一般不会使用。

    # 2.5 自定义模式

    我们知道,对于Docker默认的网络模式bridge,是没有办法指定容器IP的,只能有docker0虚拟网卡随机分配,要想自己定义容器网段,指定容器IP,并且在同一个宿主机下面,容器之间通过主机名也是无法ping通。对于自定义网络模式这些都是可以实现。

    创建自定义网络

    # 创建自定义网络
    [root@localhost ~]# docker network create -d bridge --gateway 172.10.0.1 --subnet 172.10.0.0/16 mynet
    # 查看创建的网卡
    [root@localhost ~]# docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    310f2cda0917   bridge    bridge    local
    6da2e1705162   host      host      local
    39b86b0c1cbf   mynet     bridge    local
    a64d2d84fda0   none      null      local
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    • -d: 指网络桥接模式 默认也是bridge
    • --gateway: 网关
    • --subnet: 网络网段
    • mynet: 自定义网络名称

    image-20230216151057648

    使用自定义网络创建容器

    # 创建容器busybox-c1 指定IP 为172.10.0.10
    [root@localhost ~]# docker run -d -it --net mynet --ip 172.10.0.10 --name busybox-c1 --hostname busybox-c1 busybox:latest /bin/sh
    # 查看容器busybox-c1 IP
    # ## 容器IP为我们配置的IP地址
    [root@localhost ~]# docker inspect busybox-c1 -f '{{ .NetworkSettings.Networks.mynet.IPAddress }}'
    172.10.0.10
    
    # 创建容器busybox-c2
    [root@localhost ~]# docker run -d -it --net mynet --name busybox-c2 --hostname busybox-c2 busybox:latest /bin/sh
    # 查看容器busybox-c2 IP
    # ## 如果不知道IP,则会随机分配
    [root@localhost ~]# docker inspect busybox-c2 -f '{{ .NetworkSettings.Networks.mynet.IPAddress }}'
    172.10.0.2
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    测试主机名通信

    image-20230216152601577

    # 2.6 Docker网络命令
    # 查看docker网络列表
    [root@localhost ~]# docker network ls
    NETWORK ID     NAME      DRIVER    SCOPE
    310f2cda0917   bridge    bridge    local
    6da2e1705162   host      host      local
    39b86b0c1cbf   mynet     bridge    local
    a64d2d84fda0   none      null      local
    
    # 查看网络详细
    [root@localhost ~]# docker network inspect 39b86b0c1cbf
    [
        {
            "Name": "mynet",
            "Id": "39b86b0c1cbffe813c5b290942eb12a27ba3f71aaaa5488d1bffe3e7db94e424",
            "Created": "2023-02-16T15:09:23.879290158+08:00",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": {},
                "Config": [
                    {
                        "Subnet": "172.10.0.0/16",
                        "Gateway": "172.10.0.1"
                    }
                ]
            },
            "Internal": false,
            "Attachable": false,
            "Ingress": false,
            "ConfigFrom": {
                "Network": ""
            },
            "ConfigOnly": false,
            "Containers": {
                "86c20e829811ec3a87c6b665cac9e9220775a610b4c4b4275411afcd52384370": {
                    "Name": "busybox-c1",
                    "EndpointID": "05cdb7011c4eda1907cb8aa21bb55fe8c3e844d20dd211ab9084897fd952c986",
                    "MacAddress": "02:42:ac:0a:00:0a",
                    "IPv4Address": "172.10.0.10/16",
                    "IPv6Address": ""
                },
                "8e1bee9cbd3c6f7acbbc5409b133f9bfcd551ae3456f1b559d196e181d30e167": {
                    "Name": "busybox-c2",
                    "EndpointID": "c85b84ee6bc9bc3d88edaac95651e3bd9ef44fa689e1603dd3a0681271aa4170",
                    "MacAddress": "02:42:ac:0a:00:02",
                    "IPv4Address": "172.10.0.2/16",
                    "IPv6Address": ""
                }
            },
            "Options": {},
            "Labels": {}
        }
    ]
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55

    # 三、网络通信原理{#index}

    说明

    上面介绍了Docker的几种网络模式,这几种模式其实归类起来,就两种情况,一种是容器共享同一个网络命名空间(host、container),另一种是容器独立网络空间(bridge、none)。

    # 3.1 同网络命名空间

    这种模式其实很好理解,因为不同的容器都属于一个网络命名空间,等于网络、端口都是共享使用,看到的网络设备是一样的,都可以看到Loopback设备可以理解为在同一个host主机模式上,不同应用之间访问,直接使用lo地址即可。

    # 3.2 不同网络命名空间

    Docker在启动时,会在宿主机创建一个虚拟的网桥docker0,Docker创建容器时,会根据docker0定义的网段为容器随机分配一个IP地址。该docker0网桥也是这些容器的网关,由于同一个宿主机内的容器IP都是由docker0分配IP,并且都接入到同一个网桥,因此,这些容器之间通信直接使用容器IP即可。

    查看默认网桥

    [root@localhost ~]# ifconfig 
    docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
            inet6 fe80::42:e1ff:fefc:20ef  prefixlen 64  scopeid 0x20<link>
            ether 02:42:e1:fc:20:ef  txqueuelen 0  (Ethernet)
            RX packets 5901  bytes 319886 (312.3 KiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 6256  bytes 9299137 (8.8 MiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 10.66.31.130  netmask 255.255.255.0  broadcast 10.66.31.255
            inet6 fe80::1a49:7ad8:da9b:d0b4  prefixlen 64  scopeid 0x20<link>
            inet6 fe80::f3f0:e911:6ed:35db  prefixlen 64  scopeid 0x20<link>
            ether 00:50:56:a4:78:54  txqueuelen 1000  (Ethernet)
            RX packets 176158  bytes 215680246 (205.6 MiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 132485  bytes 14988051 (14.2 MiB)
            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 44  bytes 5381 (5.2 KiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 44  bytes 5381 (5.2 KiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28

    与外部通信

    # 因为docker网桥是虚拟网络设备,所以对于外部来说,Docker容器IP对外是不可见的,如果想要被外部访问,可以把应用端口通过-p的方式映射到宿主机上
    # ## 这样我们直接访问宿主机的80端口也就可以访问到容器中的内容
    # ## -P 如果使用大P则,无需知道端口映射,会随机映射到宿主机的一个端口
    [root@localhost ~]# docker run -d --name nginx-b1 -p 80:80 nginx:latest
    
    1
    2
    3
    4

    端口映射,背后的原理其实就是DNAT转换,我们可以看下iptable规则


    image-20230216162336923

    总结


    image-20230216163212253

    笔记

    • Docker将 veth pair设备的一端放在新创建的容器中,并命名为eth0 (容器的网卡),另一端放在主机中,以veth*这样类似的名字命名,并将这个网络设备映射加入到docker0 网桥中。

    • 对于同一个容器中docker创建的这对网络设备,无论在哪一端发送消息对端都可以收到,因此eth0与veth可以无障碍通信

    • 对于容器之间通信(也就是不同veth之间通信),通过虚拟网桥转发通信,通过arp协议得到目标IP地址的mac地址,通过mac地址进行转发

    • 对于容器与外部,通过docker0与宿主机eth0通过DNAT进行转发通信

    编辑 (opens new window)
    上次更新: 2023/03/13, 16:47:57
    Namespace和Cgroups
    Docker 存储引擎

    ← Namespace和Cgroups Docker 存储引擎→

    最近更新
    01
    cert-manager自动签发Lets Encrypt
    09-05
    02
    Docker构建多架构镜像
    08-02
    03
    Prometheus数据迁移至VMstorage
    08-01
    更多文章>
    Theme by Vdoing | Copyright © 2023-2024 |豫ICP备2021026650号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式