[翻译] 理解Docker容器网络

理解Docker容器网络

翻译自Understand Docker container networks

如果你需要创建互相协作并安全的web应用,使用Docker的网络的特性可以帮你解决。定义上,网络为容器了完全的隔离性,所以,控制你的应用程序运行所在的网络很重要。Docker的网络特性变提供了你对网络的控制能力。

这篇文章将提供Docker原生的网络的行为的概览,Docker默认会创建哪些网络,以及创建自定义的自有的网络,以及在单节点或者集群上创建自定义的网络需要哪些资源。

默认网络(Default Networks)

当你安装好Docker之后, 它会自动的创建三个网络,你可以使用docker network ls命令列举这些3个网络:

$ docker network ls
NETWORK ID          NAME                DRIVER
7fca4eb8c647        bridge              bridge
9f904ee27bf5        none                null
cf03ee007fb4        host                host

最初,这3个网络是docker代码实现的一部分,你可以通过指定--net参数来指定容器启动(run)所在的网络。现在这三个网络还是同样可用的。

在所有的Docker安装版本中都会提供默认的bridge网络即docker0网络。如果你不指定docker run --net=<NETWORK>的话,Docker daemon 会默认将容器连接到这个网络。你可以通过ifconfig命令看到这个bridge是存在于宿主机(host)的网络栈中的。

$ ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:47:bc:3a:eb
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:47ff:febc:3aeb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:17 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:1100 (1.1 KB)  TX bytes:648 (648.0 B)

none网络会添加容器到一个容器自己的网络栈,然后这个容器会并没有网络接口。Attach到这样的容器上然后检查他的网络栈,会有这样的结果:

$ docker attach nonenetcontainer

root@0cb243cd1293:/# 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
root@0cb243cd1293:/# ifconfig
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)

root@0cb243cd1293:/#

Note: 你可以通过CTRL-p CTRL-q detach并离开容器终端。

host网络添加一个容器到宿主机(host)的网络栈中,你会发现容器中的网络的配置是和宿主机(host)是一致的。

除了bridge网络,你不需要直接的操作这些默认的网络。你可以查看他们的列表和详情,但你不能移除他们。因为他们是Docker所需要的。不过你可以添加自定义的网络以及当你不需要这个网络是删除自定义的网络。不过在你了解自定义网络之前,可以先稍微了解一下默认的bridge网络。

默认bridge网络详解

在所有的docker主机上都会提供默认的bridge网络。通过docker network inspect命令可以查看关于这个网络的信息:

$ docker network inspect bridge
[
   {
       "Name": "bridge",
       "Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
       "Scope": "local",
       "Driver": "bridge",
       "IPAM": {
           "Driver": "default",
           "Config": [
               {
                   "Subnet": "172.17.0.1/16",
                   "Gateway": "172.17.0.1"
               }
           ]
       },
       "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": "9001"
       }
   }
]

Docker Enging会自动的为这个网络创建SubnetGateway的配置。然后docker run命令会将新的容器添加到这个网络中。

$ docker run -itd --name=container1 busybox
3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c

$ docker run -itd --name=container2 busybox
94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c

启动两个容器之后再通过inspect这个bridge网络可以看到在这个网络中新加入的两个容器。

$ docker network inspect bridge
{[
    {
        "Name": "bridge",
        "Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.17.0.1/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Containers": {
            "3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c": {
                "EndpointID": "647c12443e91faf0fd508b6edfe59c30b642abb60dfab890b4bdccee38750bc1",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c": {
                "EndpointID": "b047d090f446ac49747d3c37d63e4307be745876db7f0ceef7b311cbba615f48",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "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": "9001"
        }
    }
]

上面的docker network inspect会展示这个网络上所有连接的容器以及他们的网络资源,在这个默认网络中的容器可以通过他们的IP互相通信。Docker在默认的bridge网络中不支持自动服务发现(automatic service discovery)。如果你需要在这个默认bridge网络中使用容器名进行通信,你必须通过过时(legacy)的docker run --link选项连接这些容器。

你可以attach到一个运行中的container然后查看他的网络配置:

$ docker attach container1

root@0cb243cd1293:/# ifconfig
ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:16 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:1296 (1.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)

然后使用ping三秒钟测试与这个默认bridge网络中与其他容器的联通。

root@0cb243cd1293:/# ping -w3 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.096 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.080 ms
64 bytes from 172.17.0.3: seq=2 ttl=64 time=0.074 ms

--- 172.17.0.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.074/0.083/0.096 ms

Finally, use the cat command to check the container1 network configuration:
最后,用cat命令检查container1网络的配置:

root@0cb243cd1293:/# cat /etc/hosts
172.17.0.2  3386a527aa08
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

使用CTRL-p CTRL-q detach container1这个容器并保持它后台运行。然后attach到container2并重复上面4个命令。

$ docker attach container2

root@0cb243cd1293:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03
          inet addr:172.17.0.3  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:15 errors:0 dropped:0 overruns:0 frame:0
          TX packets:13 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1166 (1.1 KiB)  TX bytes:1026 (1.0 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: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)

root@0cb243cd1293:/# ping -w3 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.067 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.072 ms

--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.067/0.071/0.075 ms
/ # cat /etc/hosts
172.17.0.3  94447ca47985
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

默认的docker0bridge网络支持用docker run --link允许容器间直接通信,那些在技术设置复杂并易于出现错误。虽然现在在技术上仍然可以使用它们,但是最好避免使用,并使用自定义网络替代这种方案。

用户自定义网络(User-defined networks)

你可以通过创建自定义网络以便更好的容器网络隔离,Docker为创建自定义网络提供了一些默认的 network driver。你可以创建一个新的 bridge network 或者 overlay network。或者你可以编写及创建一个 network plugin 或者 remote network

你也可以创建多个网络,可以把容器连接到不止一个网络中。容器仅可以同网络内的容器进行通信而不能跨网络通信。连接到两个网络中的容器可以分别同两个网络中其他容器进行通信。

下面的几章会非常详细的介绍每个Docker内置的网络驱动。

bridge 网络

最简单的用户自定义网络就是创建一个bridge网络。这个网络类似于之前的,默认的docker0网络。有一些新加的特性以及废弃的老特性。

$ docker network create --driver bridge isolated_nw
1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b

$ docker network inspect isolated_nw
[
    {
        "Name": "isolated_nw",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.21.0.0/16",
                    "Gateway": "172.21.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {}
    }
]

$ docker network ls
NETWORK ID          NAME                DRIVER
9f904ee27bf5        none                null
cf03ee007fb4        host                host
7fca4eb8c647        bridge              bridge
c5ee82f76de3        isolated_nw         bridge

当以创建完网络之后,你可以通过使用docker run --net=<NETWORK>选项指定容器运行在这个网络上。

$ docker run --net=isolated_nw -itd --name=container3 busybox
8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c

$ docker network inspect isolated_nw
[
    {
        "Name": "isolated_nw",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {}
            ]
        },
        "Containers": {
            "8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c": {
                "EndpointID": "93b2db4a9b9a997beb912d28bcfc117f7b0eb924ff91d48cfa251d473e6a9b08",
                "MacAddress": "02:42:ac:15:00:02",
                "IPv4Address": "172.21.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {}
    }
]

这些你在这个网络中启动的容器必须运行在同一个Docker主机上,每个在这个网络中的容器可以直接同其他容器进行通信。不过网络将容器同外部的网络隔离开。

在一个用户自定义网络中,是不支持link的。在这个网络中你可以expose和publish一个容器的端口,这个方案可以让你的自定义网络的一部分供外部网络访问。

如果你希望在单个机器上使用一个相对小的网络,bridge网络是非常有用的。然而,如果你需要一个相对大的网络,可以通过创建overlay的网络。

overlay网络(An overlay network)

Docker的overlay网络驱动提供原生开箱即用(out-of-the-box)的跨主机网络。完成这个支持是基于libnetwork和Docker的libkvlibnetwork是一个内置基于VXLAN overlay网络驱动的一个库。

overlay网络需要一个可用的key-value存储的服务。目前Docker的libkv支持Consul,Etcd,和ZooKepper(分布式存储),在创建网络之前,你必须安装以及配置你所选的key-value存储服务。然后你需要创建网络的Docker机器以及存储服务的机器必须能够互相通信。

网络中的每个宿主机必须运行有Docker engine实例,最简单的创建运行Docker engine实例的方法是使用Docker Machine。

你在主机之间需要打开下面这些端口。

Protocol Port Description
udp 4789 Data plane (VXLAN)
tcp/udp 7946 Control plane

你的Key-value存储服务可能需要额外的一些端口,可以检查服务提供者的文档然后打开需要的端口。

一旦你有很多的机器创建出来,你可以使用Docker Swarm快速的形成一个集群。

为了创建overlay网络,你需要为每台机器上的Docker Engine的daemon配置overlay网络所需的选项。下面就是需要设置的三个选项。

Option Description
--cluster-store=PROVIDER://URL
Describes the location of the KV service.
--cluster-advertise=HOST_IP|HOST_IFACE:PORT
The IP address or interface of the HOST used for clustering.
--cluster-store-opt=KEY-VALUE OPTIONS
Options such as TLS certificate or tuning discovery Timers

在Swarm集群中的一个节点上创建overlay网络

$ docker network create --driver overlay my-multi-host-network

这个的结果就是创建了一个跨越多个节点的网络。一个overlay网络为容器提供了完全的网络隔离。

然后在每台主机上,通过制定网络名启动容器。

$ docker run -itd --net=my-multi-host-network busybox

连接上之后,每个容器便可以可以互相访问这个网络中的其他容器,不管另外的容器是在那一台主机上。

如果你想自己尝试下这个流程的话,可以参考Getting started for overlay.

自定义网络插件(Custom network plugin)

你可以编写自己的网络驱动,驱动是和Docker daemon运行在同一台主机上一个进程,并且由Docker plugin系统调用和使用。

网络插件和其他的Docker插件一样受到一些限制和安装规则。所有的插件使用Plugin API,有自己的生命周期,包含:安装,启动,停止,激活。

当你创建并安装了自定义的网络驱动是,你可以像内置的网络驱动一样使用它,例如:

$ docker network create --driver weave mynet

你可以在这个网络上做查看(inspect),添加删除容器等操作。当然,不同的驱动使用不同的技术和框架,所以自定义网络也会包含很多Docker默认网络没有的特性。如果需要了解更多关于编写插件的内容,可以参考Extending DockerWriting a network driver plugin.

Docker内置DNS服务器(embedded DNS server)

Docker damon 会为每个连接到自定义网络的容器运行一个内置的DNS服务提供自动的服务发现。域名解析的请求会首先被内置的DNS服务器拦截,如果内置的DNS服务器不能够解析这个请求,它才会转发到外部的容器配置的DNS服务器。以便于这个机制,容器的resolv.conf文件会将DNS服务器配置为127.0.0.11,既内置DNS服务器监听的地址。更多关于在自定义网络中的内置DNS服务器可以参考embedded DNS server in user-defined networks

Links

在Docker有这些网络特性之前,你需要使用Docker link的功能让容器间可以互相发现。有了Docker网络特性之后,容器可以通过容器名自动的互相发现。不过你可以继续使用link在自定义网络中,不过这个link的行为会和默认的docker0 bridge网络上的行为不同。关于更多的信息和对比,可以参考:默认的docker0bridge上的Legacy Links,以及在用户自定义网络中的linking containers in user-defined networks

相关链接

想了解更多容器服务的内容,请点击https://www.aliyun.com/product/containerservice

时间: 2024-08-02 12:53:38

[翻译] 理解Docker容器网络的相关文章

理解Docker容器网络之Linux Network Namespace

更多深度文章,请关注:https://yq.aliyun.com/cloud 由于2016年年中调换工作的原因,对容器网络的研究中断过一段时间.随着当前项目对Kubernetes应用的深入,我感觉之前对于容器网络的粗浅理解已经不够了,容器网络成了摆在前面的"一道坎".继续深入理解K8s网络.容器网络已经势在必行.而这篇文章就算是一个重新开始,也是对之前浅表理解的一个补充. 我还是先从Docker容器网络入手,虽然Docker与Kubernetes采用了不同的网络模型:K8s是Conta

10张图带你深入理解Docker容器和镜像

本文讲的是10张图带你深入理解Docker容器和镜像,[编者的话]本文用图文并茂的方式介绍了容器.镜像的区别和Docker每个命令后面的技术细节,能够很好的帮助读者深入理解Docker. 这篇文章希望能够帮助读者深入理解Docker的命令,还有容器(container)和镜像(image)之间的区别,并深入探讨容器和运行中的容器之间的区别. 当我对Docker技术还是一知半解的时候,我发现理解Docker的命令非常困难.于是,我花了几周的时间来学习Docker的工作原理,更确切地说,是关于Doc

Docker容器网络下UDP协议的一个问题

最近在工作中遇到一个 docker 容器下 UDP 协议网络不通的问题,困扰了很久,也比较有意思,所以想写下来和大家分享. 我们有个应用是 UDP 协议的,部署上去发现无法工作,但是换成 TCP 协议是可以的(应用同时支持 UDP.TCP 协议,切换成 TCP 模式发现一切正常).虽然换成 TCP 能解决问题,但是我们还是想知道到底 UDP 协议在网络模式下为什么会出现这个问题,以防止后面其他 UDP 应用会有异常. 这个问题抽象出来是这样的:如果有 UDP 服务运行在主机上(或者运行在网络模型

基础的 Docker 容器网络命令

各位好,今天我们将学习一些Docker容器的基础命令.Docker 是一个开源项目,提供了一个可以打包.装载和运行任何应用的轻量级容器的开放平台.它没有语言支持.框架和打包系统的限制,从小型的家用电脑到高端服务器,在何时何地都可以运行.它可以使部署和扩展web应用程序.数据库和后端服务像搭积木一样容易,而不依赖特定技术栈或提供商.Docker适用于网络环境,它正应用于数据中心.ISP和越来越多的网络服务. 因此,这里有一些你在管理Docker容器的时候会用到的一些命令. 1. 找到Docker接

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

前面已经学习了 Docker 的几种网络方案:none.host.bridge 和 joined 容器,它们解决了单个 Docker Host 内容器通信的问题.本章的重点则是讨论跨主机容器间通信的方案. 跨主机网络方案包括: docker 原生的 overlay 和 macvlan. 第三方方案:常用的包括 flannel.weave 和 calico. docker 网络是一个非常活跃的技术领域,不断有新的方案开发出来,那么要问个非常重要的问题了: 如此众多的方案是如何与 docker 集成

本人对《Docker——容器与容器云(第2版)》的读后感

首先,这本书讲述了Docker 底层实现的原理及细节,语言通俗易懂,对Kubernetes 也进行呢深入的讲解,最近用k8s, 从这本书里学到了很多知识,对k8s 的核心组件进行了深入分析,对实现原理进行了透彻讲解,内容丰富,堪称良心之作,本人也在做云计算,也拜读过第一版本,作为国内最早的Docker技术参考书,收获很大,对于最新技术的发展,在新版本中,有着很好的把握,体现着Docker技术的发展潮流,在保持了第一版架构的同时,对各个章节的内容又进行了大量的扩充,紧紧跟随着Docker以及k8s

在Docker中使用Open vSwitch创建跨主机的容器网络

本文讲的是在Docker中使用Open vSwitch创建跨主机的容器网络,[编者的话]本文介绍了如何使用Open vSwitch为Docker 1.9.0及以后版本提供网络支持.操作前请先确认你已经按照INSTALL.md 编译,或者通过包管理器安装了Open vSwitch.关于如何安装Docker,请参考www.docker.com上提供的介绍. Docker从1.9.0版本之后提供了跨主机的网络支持.通过将Docker和Open vSwitch整合,则可以利用Open vSwitch v

一文搞懂各种 Docker 网络 - 每天5分钟玩转 Docker 容器技术(72)

前面各小节我们先后学习了 Docker Overaly,Macvaln,Flannel,Weave 和 Calico 跨主机网络方案.目前这个领域是百家争鸣,而且还有新的方案不断涌现. 本节将从不同维度比较各种网络方案,大家在选择的时候可以参考.CloudMan 的建议是:没有最好的,只有最适合的,明确自己的需求,通过 PoC 选型. Docker 起初只提供了简单的 single-host 网络,显然这不利于 Docker 构建容器集群并通过 scale-out 方式横向扩展到多个主机上. 在

Docker 手动配置容器网络实例详解_docker

Docker 手动配置容器网络   docker容器的网络是net命名空间与虚拟设备的结合,容器在启动时会创建一对虚拟接口veth pair,这一对接口分别放到本地和容器中,在本地的veth会被分配类似vethxxxx的名称并被桥接到指定网桥的上(默认为docker0),可以通过brctl show命令查看网桥上挂载的接口,在容器中的veth会从网桥获取一个未使用地址,该veth的名称会被更改为eth0并配置默认路由到vethxxxx,docker允许在启动容器的时候通过--net参数指定不同的