docker的单主机容器网络

夏冬青 夏冬青     2022-08-17     591

关键词:

作者:杨冬 欢迎转载,也请保留这段声明。谢谢!

出处: https://andyyoung01.github.io/http://andyyoung01.16mb.com/

本篇文章主要探索Docker的单机容器网络,了解一下单个Docker主机上网络的各种模式,从而为后续理解跨主机容器网络打下基础。

Docker默认容器网络的建立和控制是一种结合了network namespace,iptables,Linux网桥及route table等多种技术的综合解决方案,本篇主要针对于如何使用单主机网络的各种模式,对于实现细节不做过多的探索(这篇文章 http://tonybai.com/2016/01/15/understanding-container-networking-on-single-host/ 对于docker单主机网络的实现机制做了详细的探索)。

Docker的网络模式

Docker支持的网络模式主要有如下几种:

技术分享

None

启动容器时,使用了参数 --network="none" 。在此种模式下,容器和外部网络没有连接。在容器中只有loopback的网络接口,但它没有对外的任何路由。

Bridge

启动容器时,使用了参数 --network="bridge" 或者未指定此参数。这是docker默认的网络模式。它允许此主机上的容器彼此进行通信,也允许容器访问主机的外部网络。下图显示了Docker bridge网络的示意图:

技术分享

在主机上,docker创建了一个通常名为docker0的网桥,这里它的ip设置为172.17.0.1.在创建每个容器时,同时创建了一对veth网络接口。接口的一端连接到docker0的网桥上,另一端连接到容器的内部。从容器发起的到外部网络的连接是通过IP forwarding和设置了NAT规则的iptables rules实现的(图中的绿色箭头)。从外部网络到容器内部的连接使用了一条完全不同的路径。如果容器将自身的端口映射到主机上,则docker会启动一个docker-proxy进程来进行监听,通过此proxy将数据转发到容器中(图中的红色箭头)。

默认情况下,同一台docker主机上的容器彼此之间可以通过他们的IP地址进行通信。如果需要通过容器的主机名进行通信,容器之间必须设置了link。

Host

启动容器时,使用了参数 --network="host" 。在这种模式下,容器共享主机的networking namespace,所以主机上的网络接口对容器都可用,同时在bridge模式下docker所做的各种网络设置都被略过,这意味着容器的网络性能和普通的主机网络性能 一样快 。在运行一些对网络性能要求较高的应用时,如负载均衡器或高性能web服务器时,应使用此模式。

但此模式给予容器对本地系统服务的完全访问权限,所以比其它模式的安全性要差。

Container

启动容器时,使用了参数 --network="container:<name|id>" 。这种模式下容器使用了另外一个容器的networking namespace,也就是说它与另外一个容器共享网络栈。

User-defined network

在这种模式下,用户可以使用Docker网络驱动或外部网络驱动plugin来创建自定义的网络。用户可以将多个容器连接到同一个网络上。一旦容器连接到用户自定义的网络后,容器可以使用另外一个容器的ip地址 或名称 来彼此通信。此功能需要Docker 1.10之后的版本。在较新版本的docker daemon中内置了一个DNS服务器,对于任意在创建时指定了name或net-alias或通过link提供了别名的容器,它可以提供内置的 服务发现功能 ,从而无需再使用第三方软件提供的DNS服务(无需再使用文章“ 使用resolvable通过DNS查找容器 ”中提供的方法)。

对于overlay网络或使用了支持多主机连接的插件的容器,连接到同一多主机网络但从不同主机上启动的容器也可以彼此之间以这种方式通信。

Docker的network命令

Docker的network命令既可以用于单主机网络的相关操作,也可以用于多主机overlay网络的操作,本篇主要使用其与单主机网络相关的命令。

创建网络

当在主机上安装docker后,docker引擎自动创建三个网络,可用如下命令列出默认的三个网络:

[[email protected] ~]$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
2a820cde1d0c        bridge              bridge              local               
54be0bc791bf        host                host                local               
8488a8a4ca59        none                null                local

除此之外,用户还可以创建自己的bridge或overlay的网络。如果运行 docker network create 命令并且指定一个网络名称,则此命令为用户创建一个bridge网络:

[[email protected] ~]$ docker network create simple-network
a88875cc258fb24bbf55db67efefd05976dc8d1a8e25a2166a1acbd1dc9e125a
[[email protected] ~]$ docker network inspect simple-network
[
    {
        "Name": "simple-network",
        "Id": "a88875cc258fb24bbf55db67efefd05976dc8d1a8e25a2166a1acbd1dc9e125a",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1/16"
                }
            ]
        },
        "Internal": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

连接容器

可以将容器动态得连接到一个或多个网络上。一旦连接后,容器可以通过其它容器的ip地址或名称进行通信。下面看一下例子:

首先创建两个容器:

[[email protected] ~]$ docker run -itd --name=container1 busybox
bdaadbef1c5b3a53c1cf54ddda70e170e386fc578c815f07b09d21ca2fcd3b20
[[email protected] ~]$ docker run -itd --name=container2 busybox
126cf3af1ddd033a0925ca879e8d744293cb95949d560877ca630a29b4630630

然后创建一个隔离的bridge的网络用于测试:

[[email protected] ~]$ docker network create -d bridge --subnet 172.25.0.0/16 isolated_nw
38159357c0979fdbc6ca0be29475867115e002ef27d8f79fee014b03ffd86b8d

这里通过命令行参数 --subnet 指定了容器使用的子网网段。下面将container2连接到刚才创建的网络上:

[[email protected] ~]$ docker network connect isolated_nw container2

然后启动第三个容器,在启动的同时将其连接到isolated_nw网络上,同时手动指定该容器的ip:

[[email protected] ~]$ docker run --network=isolated_nw --ip=172.25.3.3 -itd --name=container3 busybox
d649491fd218c65fb0dc26aa79cb0d6f43dabac2bdc2f404c515f97042e60206

只要容器连接到一个由用户指定子网网段(通过 --subnet )的网络上时,就可以为容器指定ip地址。

上述命令运行完毕后,整个主机上的网络状态如下图所示:

技术分享

使用docker attach命令连接到运行的container2容器内部并查看其网络栈:

[[email protected] ~]$ docker attach container2
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:05  
        inet addr:172.17.0.5  Bcast:0.0.0.0  Mask:255.255.0.0
        inet6 addr: fe80::42:acff:fe11:5/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:9 errors:0 dropped:0 overruns:0 frame:0
        TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:0 
        RX bytes:718 (718.0 B)  TX bytes:648 (648.0 B)

eth1      Link encap:Ethernet  HWaddr 02:42:AC:19:00:02  
        inet addr:172.25.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
        inet6 addr: fe80::42:acff:fe19:2/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:32 errors:0 dropped:0 overruns:0 frame:0
        TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:0 
        RX bytes:3282 (3.2 KiB)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback  
        inet addr:127.0.0.1  Mask:255.0.0.0
        inet6 addr: ::1/128 Scope:Host
        UP LOOPBACK RUNNING  MTU:65536  Metric:1
        RX packets:0 errors:0 dropped:0 overruns:0 frame:0
        TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:0 
        RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

可见eth0连接到了默认的bridge网络,eth1连接到了用户创建的isolated_nw网络,此网络可以通过docker内置的DNS服务器进行其它容器的名称解析,所以在container2中可以通过名称ping通container3:

/ # ping -w 4 container3
PING container3 (172.25.3.3): 56 data bytes
64 bytes from 172.25.3.3: seq=0 ttl=64 time=0.146 ms
64 bytes from 172.25.3.3: seq=1 ttl=64 time=0.113 ms
64 bytes from 172.25.3.3: seq=2 ttl=64 time=0.100 ms
64 bytes from 172.25.3.3: seq=3 ttl=64 time=0.112 ms

--- container3 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.100/0.117/0.146 ms

然而在默认的bridge网络中,并不是这样。在默认的bridge网络中,Docker并不支持自动的服务发现:

/ #  ping -w 4 container1
ping: bad address ‘container1‘

在默认的bridge网络中,可以使用传统的 docker run --link 命令来启用通过名称的解析。当然,在没有使用 --link 时,可以通过彼此的ip地址进行通信。

退出container2的终端,使用快捷键CTRL-p然后CTRL-q。

在这个示例当中,container2连接到了两个网络上,所以它可以与container1和container3通信。但container1和container3并不在一个网络当中所以它们之间并不能通信。下面连接到container3的控制台然后测试一下(container1的ip为172.17.0.4):

[[email protected] ~]$ docker attach container3
/ # ping 172.17.0.4
PING 172.17.0.2 (172.17.0.2): 56 data bytes
^C
--- 172.17.0.2 ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss

断开容器连接

用户可以通过 docker network disconnect 命令断开容器到某个网络的连接,当断开此连接后,容器就不能通过此网络与其它容器通信了:

[[email protected] ~]$ docker network disconnect isolated_nw container2
[[email protected] ~]$ docker attach container2
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:05  
        inet addr:172.17.0.5  Bcast:0.0.0.0  Mask:255.255.0.0
        inet6 addr: fe80::42:acff:fe11:5/64 Scope:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
        RX packets:17 errors:0 dropped:0 overruns:0 frame:0
        TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:0 
        RX bytes:1222 (1.1 KiB)  TX bytes:1152 (1.1 KiB)

lo        Link encap:Local Loopback  
        inet addr:127.0.0.1  Mask:255.0.0.0
        inet6 addr: ::1/128 Scope:Host
        UP LOOPBACK RUNNING  MTU:65536  Metric:1
        RX packets:16 errors:0 dropped:0 overruns:0 frame:0
        TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
        collisions:0 txqueuelen:0 
        RX bytes:922 (922.0 B)  TX bytes:922 (922.0 B)
/ # ping container3
ping: bad address ‘container3‘

移除一个网络

当一个网络中所有的容器都停止或断开连接后,可以移除该网络:

[[email protected] ~]$ docker network disconnect isolated_nw container3
[[email protected] ~]$ docker network rm isolated_nw
isolated_nw
[[email protected] ~]$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
2a820cde1d0c        bridge              bridge              local               
54be0bc791bf        host                host                local               
8488a8a4ca59        none                null                local               
a88875cc258f        simple-network      bridge              local

Windows下Docker主机网络容器服务访问

】Windows下Docker主机网络容器服务访问【英文标题】:DockerhostnetworkcontainerserviceaccessunderWindows【发布时间】:2020-11-2209:20:56【问题描述】:如果我使用主机网络(--networkhost)运行docker容器,对于在容器中运行的任何服务,它们的暴... 查看详情

docker学习docker容器网络通信原理分析(代码片段)

   概述自从docker容器出现以来,容器的网络通信就一直是大家关注的焦点,也是生产环境的迫切需求。而容器的网络通信又可以分为两大方面:单主机容器上的相互通信,和跨主机的容器相互通信。而本文将分别针对... 查看详情

docker容器网络

参考技术A利用NetNamespace可以为Docker容器创建隔离的网络环境,容器具有完全独立的网络栈,与宿主机隔离。也可以使Docker容器共享主机或者其他容器的网络命名空间,基本可以满足开发者在各种场景下的需要。Docker支持4种网络... 查看详情

docker网络

...、容器之间以及夸主机容器如何通讯呢?这就需要使用到Docker网络。在前面的介绍中我们在Dockerfile中通过EXPOSE参数来设置容器暴露的端口,让在dockerrun中使用-p来设置宿主机端口到容器端口的映射,这只是最简单的宿主机和容器... 查看详情

自定义网络实现跨主机docker通信

...网络之前,主机环境:创建自定义网络,指定网桥名称为docker-br0,当然也可以取其他的名字,指定网桥的网段为172.172.0.0/24:创建网络后,查看当前主机的网络环境,环境中多出了名称为br-760119ea5907的网卡,且docker网络出现刚创... 查看详情

docker容器网络通信原理分析

概述自从docker容器出现以来,容器的网络通信就一直是大家关注的焦点,也是生产环境的迫切需求。而容器的网络通信又可以分为两大方面:单主机容器上的相互通信和跨主机的容器相互通信。而本文将分别针对这两方面,对容... 查看详情

docker技术剖析--docker网络docker宿主机之间容器互通

http://hongge.blog.51cto.com/多台物理主机之间的容器互联(暴露容器到真实网络中)650)this.width=650;"title="clip_image002"style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-le 查看详情

主机和docker容器的区别

】主机和docker容器的区别【英文标题】:differencebetweenhostanddockercontainer【发布时间】:2018-01-2807:47:44【问题描述】:我一直在尝试训练具有特定架构的3DCNN网络。我想创建一个dockerfile,其中包含使网络正常工作所需的所有步骤。... 查看详情

跨主机网络概述-每天5分钟玩转docker容器技术(48)

前面已经学习了Docker的几种网络方案:none、host、bridge和joined容器,它们解决了单个DockerHost内容器通信的问题。本章的重点则是讨论跨主机容器间通信的方案。跨主机网络方案包括:docker原生的overlay和macvlan。第三方方案:常用... 查看详情

docker网络(代码片段)

Docker网络概况                              用一张图来说明Docker网络的基本概况:四种单节点网络模式                              bridge模式    ... 查看详情

【swarm】docker跨主机网络:overlay

参考技术ADocker早期版本中,是不支持跨主机通信网络驱动的,也就是说明如果容器部署在不同的节点上面,只能通过暴露端口到宿主机上,再通过宿主机之间进行通信。随着dockerswarm集群的推广,docker也有了自家的跨主机通信网... 查看详情

--networkhost所有容器和主机互通

参考技术Adocker默认每个容器的网络都是独立的,不互通的,和宿主机也是隔离的。如何互通呢?容器之间可以通过--network设置相同名称网络,来实现互通,如所有容器都run--networkmynet123。你服务器上安装了mysql,docker里有容器redi... 查看详情

docker网络-2(代码片段)

...减,通常用于本地调试,容器性能的衰减主要来自网络。dockerdaemon一旦停止,所有容器将退出;dockerd启动docker0虚拟网桥默认分配172.17.0.1/16网络,可修改配置文件:"bip":"192.168.1.1/24"修改docker0默认配置/etc/docker/daemo... 查看详情

在同一主机上的不同网络中的 Docker 容器之间进行通信

】在同一主机上的不同网络中的Docker容器之间进行通信【英文标题】:CommunicatingbetweenDockercontainersindifferentnetworksonthesamehost【发布时间】:2016-07-0207:52:22【问题描述】:是否有可能使同一主机内不同网络中的容器进行通信?请注... 查看详情

docker初学乍练之单主机网络(代码片段)

一、DockerbridgenetworkDocker桥接网络使用软件桥接,该软件桥接允许连接到同一桥网的容器进行通信,同时提供与未连接到该桥网络的容器的隔离。Docker桥接驱动程序会自动在主机中安装规则,以便不同桥接网络上的容器不能直接相互... 查看详情

docker怎么把宿主机的文件拷贝到运行的容器中

docker跟宿主机交互的是通过原生网络实现的。当Docker进程启动之后,它会配置一个虚拟的网桥叫docker0在宿主机上。这个接口允许Docker去分配虚拟的子网给即将启动的容器们。这个网桥在容器内的网络和宿主机网络之间将作为接... 查看详情

单一docker主机网络

一.容器网络模型:Docker定义了一个非常简单的网络模型,叫做containernetworkmodel(CNM).如下图所示:CNM模型有三个元素---sandbox,endpoint,和networksandbox:不允许从外面的网络连接到容器,实现了完美的隔离功能。Endpoint:终端节点可以认... 查看详情

docker从容器中怎么访问宿主机

例如你的docker环境的虚拟IP是192.168.99.100,那么宿主机同样会托管一个和192.168.99.100同网段的虚拟IP,并且会是主IP:192.168.99.1,那么就简单了,在容器中访问192.168.99.1这个地址就等于访问宿主机。注意,通过192.168.99.1访问宿主机... 查看详情