Network Configuration

TL;DR

When Docker starts, it creates a virtual interface named docker0 on
the host machine. It randomly chooses an address and subnet from the private range defined by RFC 1918 that are not in use on the
host machine, and assigns it to docker0.
Docker made the choice 172.17.42.1/16 when
I started it a few minutes ago, for example — a 16-bit netmask providing 65,534 addresses for the host machine and its containers.

当rocker启动时,会在主机上创建一个docker0的虚拟网卡。他随机挑选RFC1918私有网络中的一段地址给docker0。

比方172.17.42.1/16,16位掩码的网段能够拥有65534个地址能够使用,这对主机和容器来说应该足够了。

Note: This document discusses advanced networking configuration and options for Docker. In most cases you won't need this information. If you're looking to get
started with a simpler explanation of Docker networking and an introduction to the concept of container linking see the Docker
User Guide
.

注意:本文介绍docker的高级网络定制配置,普通情况下你不须要知道这些也能够使docker正常工作。简单的网络配置和介绍看上面这个链接就能够了。

But docker0 is no ordinary interface.
It is a virtual Ethernet bridge that automatically forwards packets between any other network interfaces that are attached to it. This lets containers communicate both with the host machine and with each other. Every time
Docker creates a container, it creates a pair of “peer” interfaces that are like opposite ends of a pipe — a packet sent on one will be received on the other. It gives one of the peers to the container to become its eth0 interface
and keeps the other peer, with a unique name like vethAQI2QT,
out in the namespace of the host machine. By binding every veth* interface
to the docker0 bridge, Docker creates
a virtual subnet shared between the host machine and every Docker container.

docker0 不是普通的网卡,他是桥接到其它网卡的虚拟网卡。容器使用它来和主机相互通信。当创建一个docker容器的时候,它就创建了一个对接口。当数据包发送到一个接口时,另外一个接口也能够收到同样的数据包,它们是绑在一起一对孪生接口。

这对接口在容器中的那个的名字是eth0。主机上的接口会指定一个唯一的名字。比方vethAQI2QT这种名字,这种接口名字不再主机的命名空间中。全部的veth*的接口都会桥接到docker0。这样docker就创建了在主机和全部容器之间一个虚拟共享网络。

The remaining sections of this document explain all of the ways that you can use Docker options and — in advanced cases — raw Linux networking commands to tweak, supplement, or entirely replace Docker's default networking configuration.

接下来的部分将介绍在高级场景中,docker全部的网络定制配置。linux的原生命令将调整、补充、甚至替换docker默认的网络配置。

Quick Guide to the Options

高速配置指南

Here is a quick list of the networking-related Docker command-line options, in case it helps you find the section below that you are looking for.

以下是一个跟docker网络相关的命令列表。能够让你高速找到你须要的信息。

Some networking command-line options can only be supplied to the Docker server when it starts up, and cannot be changed once it is running:

一些命令选项仅仅有在docker服务启动的时候才干够运行。并且不能立即生效。

  • -b
    BRIDGE
     or --bridge=BRIDGE —
    see Building your own bridge   桥接

  • --bip=CIDR —
    see Customizing docker0   定制docker0

  • -H
    SOCKET...
     or --host=SOCKET... —
    This might sound like it would affect container networking, but it actually faces in the other direction: it tells the Docker server over what channels it should be willing to receive commands like “run container” and “stop container.”这看起来会影响docker的网络。但他实际上是指还有一方面的内容:它告诉docker从哪个通道来接收run
    container  stop container这种命令。

  • --icc=true|false —
    see Communication between containers         容器之间的通信

  • --ip=IP_ADDRESS —
    see Binding container ports        绑定容器端口

  • --ip-forward=true|false —
    see Communication between containers       容器之间的通信

  • --iptables=true|false —
    see Communication between containers  容器之间的通信

  • --mtu=BYTES —
    see Customizing docker0   定制docker0

There are two networking options that can be supplied either at startup or when docker
run
 is invoked. When provided at startup, set the default value that docker
run
 will later use if the options are not specified:

以下2个能够在docker服务启动和docker run运行的时候指定。服务启动的时候指定则会为docker run设定默认值,docker run 后面指定能够覆盖默认值。

Finally, several networking options can only be provided when calling docker
run
 because they specify something specific to one container:

最后这些选项仅仅有在docker run后运行,由于它是针对容器的特性内容。

The following sections tackle all of the above topics in an order that moves roughly from simplest to most complex.

以下是上述列表的具体内容介绍。从简单到复杂。

Configuring DNS

配置DNS

How can Docker supply each container with a hostname and DNS configuration, without having to build a custom image with the hostname written inside? Its trick is to overlay three crucial /etc files
inside the container with virtual files where it can write fresh information. You can see this by running mount inside
a container:

docker没有定制image,是怎么提供容器的主机名和dns配置呢?它的秘诀就是用主机上的3个配置文件来覆盖容器的这3个文件。在容器中使用mount命令能够看到:

$$ mount
...
/dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ...
/dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ...
tmpfs on /etc/resolv.conf type tmpfs ...
...

This arrangement allows Docker to do clever things like keep resolv.conf up
to date across all containers when the host machine receives new configuration over DHCP later. The exact details of how Docker maintains these files inside the container can change from one Docker version to the next, so you should leave the files themselves
alone and use the following Docker options instead.

这样的机制能够让主机在从dhcp更新dns信息后,立即更新全部docker容器的dns配置。

假设要保持docker中这些文件固定不变,你能够不覆盖容器中的这些配置文件。然后使用以下的选项来配置它们。

Four different options affect container domain name services.

4中配置容器dns服务的方法

  • -h
    HOSTNAME
     or --hostname=HOSTNAME —
    sets the hostname by which the container knows itself. This is written into /etc/hostname,
    into /etc/hosts as the name of the
    container's host-facing IP address, and is the name that /bin/bash inside
    the container will display inside its prompt. But the hostname is not easy to see from outside the container. It will not appear in docker
    ps
     nor in the/etc/hosts file
    of any other container.设定容器的主机名,它会被写到/etc/hostname。/etc/hosts中的ip地址自己主动写成分配的ip地址。在/bin/bash中显示该主机名。但它不会在docker ps中显示,也不会在其它的容器的/etc/hosts中显示。

  • --link=CONTAINER_NAME:ALIAS —
    using this option as you run a container
    gives the new container's /etc/hosts an
    extra entry named ALIAS that points
    to the IP address of the container named CONTAINER_NAME.
    This lets processes inside the new container connect to the hostnameALIAS without
    having to know its IP. The --link= option
    is discussed in more detail below, in the section Communication between containers. 这选项会在创建容器的时候加入一个其它容器CONTAINE_NAME的主机名到/etc/hosts文件里。让新容器的进程能够使用主机名ALIAS就能够连接它。

    --link=会在容器之间的通信中更具体的介绍

  • --dns=IP_ADDRESS... —
    sets the IP addresses added as server lines
    to the container's/etc/resolv.conf file.
    Processes in the container, when confronted with a hostname not in/etc/hosts,
    will connect to these IP addresses on port 53 looking for name resolution services. 加入dnsserver到容器的/etc/resolv,conf中,让容器用这ip地址来解析全部不在/etc/hosts中的主机名。

  • --dns-search=DOMAIN... —
    sets the domain names that are searched when a bare unqualified hostname is used inside of the container, by writing search lines
    into the container's/etc/resolv.conf.
    When a container process attempts to access host and
    the search domainexample.com is
    set, for instance, the DNS logic will not only look up host but
    alsohost.example.com.设定容器的搜索域,当设定搜索域为.example.com时。会在搜索一个host主机名时。dns不仅搜索host,还会搜索host.example.com

Note that Docker, in the absence of either of the last two options above, will make /etc/resolv.confinside
of each container look like the /etc/resolv.conf of
the host machine where the dockerdaemon
is running. The options then modify this default configuration.

假设没有上述最后2个选项,docker会用主机上的/etc/resolv.conf来配置容器,它是默认配置。

Communication between containers

容器之间的通信

Whether two containers can communicate is governed, at the operating system level, by three factors.

推断2个容器之间是否可以通信,在操作系统层面,取决于3个因素:

  1. Does the network topology even connect the containers' network interfaces?

    By default Docker will attach all containers to a single docker0 bridge,
    providing a path for packets to travel between them. See the later sections of this document for other possible topologies.网络拓扑是否连接到容器的网络接口?默认docker会将全部的容器连接到docker0这网桥来提供数据包通信。

    其它拓扑结构将在稍后的文档中具体介绍。

  2. Is the host machine willing to forward IP packets? This is governed by the ip_forward system
    parameter. Packets can only pass between containers if this parameter is 1.
    Usually you will simply leave the Docker server at its default setting --ip-forward=true and
    Docker will go setip_forward to 1 for
    you when the server starts up. To check the setting or turn it on manually:主机是否开启ip转发,ip_forward參数为1的时候能够提供数据包转发。通常你仅仅须要为docker 设定 --ip-forward=true,docker 就会在服务启动的时候设定ip_forward參数为1。以下是手工检查并手工设定该參数的方法。

    # Usually not necessary: turning on forwarding,
    # on the host where your Docker server is running $ cat /proc/sys/net/ipv4/ip_forward
    0
    $ sudo echo 1 > /proc/sys/net/ipv4/ip_forward
    $ cat /proc/sys/net/ipv4/ip_forward
    1
  3. Do your iptables allow
    this particular connection to be made? Docker will never make changes to your system iptables rules
    if you set --iptables=false when
    the daemon starts. Otherwise the Docker server will add a default rule to the FORWARD chain
    with a blanket ACCEPT policy if
    you retain the default --icc=true,
    or else will set the policy to DROP if --icc=false.你的iptables是否同意这条特殊的连接被建立?当docker的设定--iptables=false时。docker不会改变系统的iptables设定,否则它会在--icc=true的时候加入一条默认的ACCEPT策略到
    FORWARD链,当--icc=false时。策略为DROP。

Nearly everyone using Docker will want ip_forward to
be on, to at least make communication possible between containers. But it is a strategic question whether to leave --icc=true or
change it to --icc=false (on Ubuntu,
by editing the DOCKER_OPTS variable
in /etc/default/docker and restarting
the Docker server) so that iptables will
protect other containers — and the main host — from having arbitrary ports probed or accessed by a container that gets compromised.

差点儿全部的人会开启ip_forward来启用容器间的通信。当时是否要改变icc-true配置是一个战略问题(在ubuntu中,能够在/etc/default/docker编辑DOCKER_OPTS变量。然后重新启动docker服务来设定),这样iptable就能够防止其它被感染容器特别是主机的恶意port扫描和訪问。

If you choose the most secure setting of --icc=false,
then how can containers communicate in those cases where you want them to provide each other services?

当你选择更安全的设定--icc=false后。怎样保持你希望的容器之间通信呢?

The answer is the --link=CONTAINER_NAME:ALIAS option,
which was mentioned in the previous section because of its effect upon name services. If the Docker daemon is running with both --icc=false and --iptables=true then,
when it sees docker run invoked
with the --link= option, the Docker
server will insert a pair of iptables ACCEPT rules
so that the new container can connect to the ports exposed by the other container — the ports that it mentioned in the EXPOSE lines
of its Dockerfile. Docker has more
documentation on this subject — see the linking Docker containers page for further details.

答案就是--link=CONTAINER_NAME:ALIAS选型。在之前的dns服务设定中提及过。假设docker
使用icc=false and --iptables=true 2个參数,当docker
run使用--link=选型时。docker会为2个容器在iptable中參数一对ACCEPT规则。开放的port取决与dockerfile总的EXPOSE行。docker有更具体的章节来专门讨论这个主题,详见此处(已经翻译完毕)http://blog.csdn.net/smallfish1983/article/details/38636851

Note: The value CONTAINER_NAME in --link= must
either be an auto-assigned Docker name likestupefied_pare or
else the name you assigned with --name= when
you ran docker run. It cannot be
a hostname, which Docker will not recognize in the context of the --link= option.

注意:--link= 中的CONTAINER_NAME 必须是自己主动生成的docker名字比方stupefied_pare,或则你用--name參数指定的名字,主机名在--link中不会被识别。

You can run the iptables command
on your Docker host to see whether the FORWARD chain
has a default policy of ACCEPT or DROP:

你能够使用iptables命令来检查FORWARD链是ACCEPT 还是DROP

# When --icc=false, you should see a DROP rule:当--icc=false时,规则应该是这样

$ sudo iptables -L -n
...
Chain FORWARD (policy ACCEPT)
target prot opt source destination
DROP all -- 0.0.0.0/0 0.0.0.0/0
... # When a --link= has been created under --icc=false,
# you should see port-specific ACCEPT rules overriding
# the subsequent DROP policy for all other packets:当加入了--link后,ACCEPT规则被改写了,加入了新的端口和IP规则 $ sudo iptables -L -n
...
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80
ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80
DROP all -- 0.0.0.0/0 0.0.0.0/0

Note: Docker is careful that its host-wide iptables rules
fully expose containers to each other's raw IP addresses, so connections from one container to another should always appear to be originating from the first container's own IP address.

注意:docker对主机级别的的iptable处理很小心,为了避免全然暴露容器之间的原始ip地址,连接仅现实连接源容器自己的本身的ip。

Binding container ports to the host

绑定一个容器port到主机

By default Docker containers can make connections to the outside world, but the outside world cannot connect to containers. Each outgoing connection will appear to originate from one of the host machine's own IP addresses thanks to an iptables masquerading
rule on the host machine that the Docker server creates when it starts:

默认容器能够建立到外部网络的连接,可是外部网络无法连接到容器。

全部到外部的连接源都会被伪装成主机的ip地址,itables的 masquerading来做到这一点。

# You can see that the Docker server creates a
# masquerade rule that let containers connect
# to IP addresses in the outside world:查看主机的masquerading规则 $ sudo iptables -t nat -L -n
...
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16
...

But if you want containers to accept incoming connections, you will need to provide special options when invoking docker
run
. These options are covered in more detail in the Docker User Guide page. There are two approaches.

当你希望容器接收外部连接时。你须要在docker run运行的时候就指定相应选项,在docker 用户指南页中有具体介绍。2种方法:

First, you can supply -P or --publish-all=true|false to docker
run
 which is a blanket operation that identifies every port with an EXPOSE line
in the image's Dockerfile and maps
it to a host port somewhere in the range 49000–49900. This tends to be a bit inconvenient, since you then have to run other docker sub-commands
to learn which external port a given service was mapped to.

指定-P --publish-all=true|false 选项会映射dockerfile 中expose的全部port。主机port在49000-49900中随机挑选。当你的另外一个容器须要学习这个port时候,非常不方便。

More convenient is the -p SPEC or --publish=SPEC option
which lets you be explicit about exactly which external port on the Docker server — which can be any port at all, not just those in the 49000–49900 block — you want mapped to which port in the container.

更方便的方法是指定-p
SPEC或则 --publish=SPEC,能够指定随意port从主机映射容器内部

Either way, you should be able to peek at what Docker has accomplished in your network stack by examining your NAT tables.

无论用那种办法,你能够通过查看iptable的 nat表来观察docker 在网络层做了什么操作。

# What your NAT rules might look like when Docker
# is finished setting up a -P forward:使用-P时: $ iptables -t nat -L -n
...
Chain DOCKER (2 references)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:172.17.0.2:80 # What your NAT rules might look like when Docker
# is finished setting up a -p 80:80 forward:使用-p 80:80时: Chain DOCKER (2 references)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80

You can see that Docker has exposed these container ports on 0.0.0.0,
the wildcard IP address that will match any possible incoming port on the host machine. If you want to be more restrictive and only allow container services to be contacted through a specific external interface on the host machine, you have two choices. When
you invoke docker run you can use
either -p IP:host_port:container_port or -p
IP::port
 to specify the external interface for one particular binding.

这里你能够看到docker映射了0.0.0.0.意味着接受主机上的全部接口地址,更严格的规则能够通过-p
IP:host_port:container_port
 或则 -p
IP::port
 来指定主机上的ip、接口。

Or if you always want Docker port forwards to bind to one specific IP address, you can edit your system-wide Docker server settings (on Ubuntu, by editing DOCKER_OPTS in /etc/default/docker)
and add the option --ip=IP_ADDRESS.
Remember to restart your Docker server after editing this setting.

或则你希望永久指定须要绑定的主机ip地址,能够 在dcoker 配置中指定--ip=IP_ADDRESS.
记得重新启动服务。

Again, this topic is covered without all of these low-level networking details in the Docker User Guide document if you
would like to use that as your port redirection reference instead.

本节没有介绍0基础的设置,0基础设置请查看用户指南。

Customizing docker0

定制docker0

By default, the Docker server creates and configures the host system's docker0 interface
as an Ethernet bridge inside the Linux kernel that can pass packets back and forth between other physical or virtual network interfaces so that they behave as a single Ethernet network.

docker服务默认会创建一个docker0接口,它在linux内核层面桥接全部物理或则虚拟网卡。这实际上将他们都放到一个物理网络。

Docker configures docker0 with an
IP address and netmask so the host machine can both receive and send packets to containers connected to the bridge, and gives it an MTU — the maximum transmission unitor largest packet length that the interface will allow
— of either 1,500 bytes or else a more specific value copied from the Docker host's interface that supports its default route. Both are configurable at server startup:

docker指定docker0的ip地址和子网掩码,让主机和容器之间能够通过网桥相互通信,它还给出了MTU-接口同意接收的最大传输单元,一般是1500bytes或则主机网络路由上支持的默认值。这2个都是在服务启动的时候配置。

  • --bip=CIDR —
    supply a specific IP address and netmask for the docker0 bridge,
    using standard CIDR notation like 192.168.1.5/24.ip地址加掩码
    使用这样的格式

  • --mtu=BYTES —
    override the maximum packet length on docker0.
    覆盖默认的coker mut配置

On Ubuntu you would add these to the DOCKER_OPTS setting
in /etc/default/docker on your Docker
host and restarting the Docker service.

在ubuntu中你能够配置DOCKER_OPTS,然后重新启动来改变这些參数。

Once you have one or more containers up and running, you can confirm that Docker has properly connected them to the docker0 bridge
by running the brctl command on
the host machine and looking at the interfaces column
of the output. Here is a host with two different containers connected:

当容器启动后,你能够使用brctl来确认他们是否已经连接到docker0网桥。例如以下:

# Display bridge info

$ sudo brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.3a1d7362b4ee no veth65f9
vethdda6

If the brctl command is not installed
on your Docker host, then on Ubuntu you should be able to runsudo
apt-get install bridge-utils
 to install it.

假设brctl命令没安装的话。在ubuntu中你能够使用这个命令来安装。

Finally, the docker0 Ethernet bridge
settings are used every time you create a new container. Docker selects a free IP address from the range available on the bridge each time you docker
run
 a new container, and configures the container's eth0 interface
with that IP address and the bridge's netmask. The Docker host's own IP address on the bridge is used as the default gateway by which each container reaches the rest of the Internet.

最后,docker0 网桥设置会在每次创建新容器的时候被使用。

docker从可用的地址段中选择一个空暇的ip地址给容器的eth0port,子网掩码使用网桥docker0的配置,docker主机本身的ip作为容器的网关使用。

# The network, as seen from a container

$ sudo docker run -i -t --rm base /bin/bash

$$ ip addr show eth0
24: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 32:6f:e0:35:57:91 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::306f:e0ff:fe35:5791/64 scope link
valid_lft forever preferred_lft forever $$ ip route
default via 172.17.42.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3 $$ exit

Remember that the Docker host will not be willing to forward container packets out on to the Internet unless its ip_forward system
setting is 1 — see the section above
on Communication between containers for details.

转发数据包须要在主机上设定ip_forward參数为1,上文介绍过。

Building your own bridge

创建你自己的桥接

If you want to take Docker out of the business of creating its own Ethernet bridge entirely, you can set up your own bridge before starting Docker and use -b
BRIDGE
 or --bridge=BRIDGE to
tell Docker to use your bridge instead. If you already have Docker up and running with its old bridge0 still
configured, you will probably want to begin by stopping the service and removing the interface:

假设你希望全然使用自己的桥接设置,你能够在启动docker服务的时候,使用 -b
BRIDGE
 or --bridge=BRIDGE 来告诉docker使用你的网桥。假设服务已经启动,旧的网桥还在使用中,那须要先停止服务。再删除旧的网桥

# Stopping Docker and removing docker0

$ sudo service docker stop
$ sudo ip link set dev docker0 down
$ sudo brctl delbr docker0

Then, before starting the Docker service, create your own bridge and give it whatever configuration you want. Here we will create a simple enough bridge that we really could just have used the options in the previous section to customize docker0,
but it will be enough to illustrate the technique.

然后在开启服务前。创建你自己希望的网桥接口,这里建立一个足够简单的网桥配置:

# Create our own bridge 创建自己的网桥

$ sudo brctl addbr bridge0
$ sudo ip addr add 192.168.5.1/24 dev bridge0
$ sudo ip link set dev bridge0 up # Confirming that our bridge is up and running 确认网桥启动 $ ip addr show bridge0
4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default
link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff
inet 192.168.5.1/24 scope global bridge0
valid_lft forever preferred_lft forever # Tell Docker about it and restart (on Ubuntu) 告诉docker桥接设置,并启动docker服务(ubuntu上) $ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
$ sudo service docker start

The result should be that the Docker server starts successfully and is now prepared to bind containers to the new bridge. After pausing to verify the bridge's configuration, try creating a container — you will see that its IP address is in your new IP address
range, which Docker will have auto-detected.

结果会是dicker服务启动成功并绑定容器到新的网桥。

之暂停并确认桥接配置之前。新建一个容器,你会看到它的ip是我们的新ip段,docker会自己主动检測到它。

Just as we learned in the previous section, you can use the brctl
show
 command to see Docker add and remove interfaces from the bridge as you start and stop containers, and can run ip
addr
 and ip route inside
a container to see that it has been given an address in the bridge's IP address range and has been told to use the Docker host's IP address on the bridge as its default gateway to the rest of the Internet.

用brctl show能够看到容器启动或则停止后网桥的配置变化。在容器中使用ip a     和ip r  来查看ip地址配置和路由信息。

How Docker networks a container

While Docker is under active development and continues to tweak and improve its network configuration logic, the shell commands in this section are rough equivalents to the steps that Docker takes when configuring networking for each new container.

当docker还处于开发阶段须要调整和改进网络配置逻辑,使用shell命令能够作为简单粗糙的替代docker,来配置新的容器。

Let's review a few basics.

让我们回想一些基础知识。

To communicate using the Internet Protocol (IP), a machine needs access to at least one network interface at which packets can be sent and received, and a routing table that defines the range of IP addresses reachable through that interface. Network interfaces
do not have to be physical devices. In fact, the loloopback
interface available on every Linux machine (and inside each Docker container) is entirely virtual — the Linux kernel simply copies loopback packets directly from the sender's memory into the receiver's memory.

机器须要一个网络接口来使用ip发送和接受数据包。路由表来定义怎样到达哪些地址段。

这里的网络接口能够不是物理接口。其实,每一个linxu机器上的lo环回接口(docker 容器中也有)就是一个全然的linux内核虚拟接口,它直接复制发送缓存中的数据包到接收缓存中。

Docker uses special virtual interfaces to let containers communicate with the host machine — pairs of virtual interfaces called “peers” that are linked inside of the host machine's kernel so that packets can travel between them. They are simple to create, as
we will see in a moment.

docker让主机和容器使用特殊的虚拟接口来通信--通信的2端叫“peers“,他们在主机内核中连接在一起,所以可以相互通信。创建他们非常easy。前面介绍过了。

The steps with which Docker configures a container are:

docker创建容器的过程例如以下:

  1. Create a pair of peer virtual interfaces.创建一对虚拟接口

  2. Give one of them a unique name like veth65f9,
    keep it inside of the main Docker host, and bind it to docker0 or
    whatever bridge Docker is supposed to be using.一端使用一个唯一的名字比方veth65f9,另外一端能够桥接到默认的docker0,或则其他你自己指定的桥接网卡。

  3. Toss the other interface over the wall into the new container (which will already have been provided with an lo interface)
    and rename it to the much prettier name eth0 since,
    inside of the container's separate and unique network interface namespace, there are no physical interfaces with which this name could collide.主机上的veth65f9这样的接口映射到新的新容器中的名称一般是eth0,在容器这个隔离的网络接口命名空间中,它是唯一的,不会有物理接口和它冲突。

  4. Give the container's eth0 a
    new IP address from within the bridge's range of network addresses, and set its default route to the IP address that the Docker host owns on the bridge.从主机桥接地址段中获取一个空暇地址给eth0使用。并设定默认路由到桥接网卡。

With these steps complete, the container now possesses an eth0 (virtual)
network card and will find itself able to communicate with other containers and the rest of the Internet.

完毕这些之后,容器就能够使用这eth0虚拟网卡来连接其它容器和其它网络。

You can opt out of the above process for a particular container by giving the --net= option
to docker run, which takes four
possible values.

你也能够为特殊的容器设定特定的參数,在docker run的时候使用--net。它有4个可选參数:

  • --net=bridge —
    The default action, that connects the container to the Docker bridge as described above.默认选项,连接到指定网桥。

  • --net=host —
    Tells Docker to skip placing the container inside of a separate network stack. In essence, this choice tells Docker to not containerize the container's networking! While container processes will still be confined to their
    own filesystem and process list and resource limits, a quick ip
    addr
     command will show you that, network-wise, they live “outside” in the main Docker host and have full access to its network interfaces. Note that this does not let the container reconfigure the host network stack
    — that would require --privileged=true —
    but it does let container processes open low-numbered ports like any other root process. It also allows the container to access local network services like D-bus. This can lead to processes in the container being able to do unexpected things like restart
    your computer
    . You should use this option with caution.告诉docker不要将容器放到隔离的网络堆栈中。

    从本质上讲,这个选项告诉docker不要容器化容器的网络!

    容器进程还是有自己的文件系统、进程列表和资源限制。

    使用ip addr命令这种容器处于docker 主机的外部,它有全然的主机接口訪问权限。注意它不会让容器又一次配置主机的网络堆栈。除非--privileged=true —
    可是容器进程能够跟其它root进程一样打开低数字的port,能够訪问本地网络服务比方D-bus。

    还能够让容器做一些意想不到的事情,比方重新启动主机。这个选项要很小心的使用。

  • --net=container:NAME_or_ID —
    Tells Docker to put this container's processes inside of the network stack that has already been created inside of another container. The new container's processes will be confined to their own filesystem and process list and resource limits, but will share
    the same IP address and port numbers as the first container, and processes on the two containers will be able to connect to each other over the loopback interface.告诉docker将新容器的进程放到一个已经存在的容器的网络堆栈中,新容器进程有它自己的文件系统、进程列表和资源限制,但它会和那个已经存在的容器共享ip地址和端口。他们之间来能够通过环回接口通信。

  • --net=none —
    Tells Docker to put the container inside of its own network stack but not to take any steps to configure its network, leaving you free to build any of the custom configurations explored in the last few sections of this document.告诉docker将新容器放到自己的网络堆栈中。可是不要配置它的网络。

    这能够让你创建不论什么自己定义的配置。本文最后一段将介绍
    他们。

To get an idea of the steps that are necessary if you use --net=none as
described in that last bullet point, here are the commands that you would run to reach roughly the same configuration as if you had let Docker do all of the configuration:

当使用--net=none时候,怎样配置:

# At one shell, start a container and
# leave its shell idle and running 启动一个/bin/bash 指定--net=none $ sudo docker run -i -t --rm --net=none base /bin/bash
root@63f36fc01b5f:/# # At another shell, learn the container process ID
# and create its namespace entry in /var/run/netns/
# for the "ip netns" command we will be using below 再创建一个容器,查找这容器的进程id,创建 它的命名空间,后面的ip netns会用到 $ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
2778
$ pid=2778
$ sudo mkdir -p /var/run/netns
$ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid # Check the bridge's IP address and netmask 检查桥接网卡的ip和子网掩码 $ ip addr show docker0
21: docker0: ...
inet 172.17.42.1/16 scope global docker0
... # Create a pair of "peer" interfaces A and B,
# bind the A end to the bridge, and bring it up 创建一对”peer“接口A和B,绑定A到网桥,并启用它 $ sudo ip link add A type veth peer name B
$ sudo brctl addif docker0 A
$ sudo ip link set A up # Place B inside the container's network namespace, 将B放到容器的网络命名空间。命名为eth0,配置一个空暇的ip
# rename to eth0, and activate it with a free IP $ sudo ip link set B netns $pid
$ sudo ip netns exec $pid ip link set dev B name eth0
$ sudo ip netns exec $pid ip link set eth0 up
$ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
$ sudo ip netns exec $pid ip route add default via 172.17.42.1

At this point your container should be able to perform networking operations as usual.

到这里。你又能够想寻常一样使用网络了。

When you finally exit the shell and Docker cleans up the container, the network namespace is destroyed along with our virtual eth0 —
whose destruction in turn destroys interface A out
in the Docker host and automatically un-registers it from the docker0 bridge.
So everything gets cleaned up without our having to run any extra commands! Well, almost everything:

当你退出shell后。docker清空容器。容器的eth0随网络命名空间一起被摧毁。A 接口也被自己主动从docker0取消注冊。不用其它命令,全部东西都被清理掉了!

# Clean up dangling symlinks in /var/run/netns

find -L /var/run/netns -type l -delete

Also note that while the script above used modern ip command
instead of old deprecated wrappers likeipconfig and route,
these older commands would also have worked inside of our container. The ip
addr
 command can be typed as ip
a
 if you are in a hurry.

ip 命令替代了旧的ifconfig route  等命令,ip addr 能够用ip a简写。

Finally, note the importance of the ip netns
exec
 command, which let us reach inside and configure a network namespace as root. The same commands would not have worked if run inside of the container, because part of safe containerization is that Docker strips container processes of the right to
configure their own networks. Using ip
netns exec
 is what let us finish up the configuration without having to take the dangerous step of running the container itself with --privileged=true.

最后,注意ip netns exec命令,它能够让我们像root一样配置网络命名空间。但在容器内部无法使用,由于统一的安全策略,docker限制容器进程配置自己的网络。使用ip netns exec 能够让我们不用设置--privileged=true就能够完毕一些可能带来危急的操作。

Tools and Examples

工具和演示样例子

Before diving into the following sections on custom network topologies, you might be interested in glancing at a few external tools or examples of the same kinds of configuration. Here are two:

在介绍自己定义网络拓扑之前,你可能会对一些外部工具和样例感兴趣:

  • Jérôme Petazzoni has created a pipework shell
    script to help you connect together containers in arbitrarily complex scenarios: https://github.com/jpetazzo/pipework Jérôme
    Petazzoni 创建了一个叫pipework的shell脚本来帮助我们在复杂的场景中完毕网络连接

  • Brandon Rhodes has created a whole network topology of Docker containers for the next edition of Foundations of Python Network Programming that includes routing, NAT'd firewalls, and servers that
    offer HTTP, SMTP, POP, IMAP, Telnet, SSH, and FTP: https://github.com/brandon-rhodes/fopnp/tree/m/playground Brandon
    Rhodes创建了一个完整的docker容器网络拓扑。包括 nat 防火墙。服务包括HTTP, SMTP, POP, IMAP, Telnet, SSH, and FTP:

Both tools use networking commands very much like the ones you saw in the previous section, and will see in the following sections.

工具使用的网络命令跟我们之前看到很相似。

Building a point-to-point connection

创建一个点到点连接

By default, Docker attaches all containers to the virtual subnet implemented by docker0.
You can create containers that are each connected to some different virtual subnet by creating your own bridge as shown inBuilding
your own bridge
, starting each container with docker
run --net=none
, and then attaching the containers to your bridge with the shell commands shown in How
Docker networks a container
.

默认docker会将全部容器到由docker0提供的虚拟子网。你也能够使用自己创建的网桥见Building
your own bridge
,使用docker
run --net=none
, 然后连接到自己的网桥见 How
Docker networks a container

But sometimes you want two particular containers to be able to communicate directly without the added complexity of both being bound to a host-wide Ethernet bridge.

但有时候你想要2个特殊的容器能够直连通信,而不用去配置复杂的主机网卡桥接。

The solution is simple: when you create your pair of peer interfaces, simply throw both of them into containers, and configure them as classic point-to-point links. The two containers will then be able to communicate directly
(provided you manage to tell each container the other's IP address, of course). You might adjust the instructions of the previous section to go something like this:

解决的方法非常easy:当你创建一对接口节点,把他们都放进容器中,配置成点到点链路类型。这2个容器就能够直接通信了。配置例如以下:

# Start up two containers in two terminal windows 在2个终端中启动2个容器

$ sudo docker run -i -t --rm --net=none base /bin/bash
root@1f1f4c1f931a:/# $ sudo docker run -i -t --rm --net=none base /bin/bash
root@12e343489d2f:/# # Learn the container process IDs
# and create their namespace entries $ sudo docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a
2989
$ sudo docker inspect -f '{{.State.Pid}}' 12e343489d2f
3004
$ sudo mkdir -p /var/run/netns
$ sudo ln -s /proc/2989/ns/net /var/run/netns/2989
$ sudo ln -s /proc/3004/ns/net /var/run/netns/3004 # Create the "peer" interfaces and hand them out 创建”peer“接口。然后配置路由 $ sudo ip link add A type veth peer name B $ sudo ip link set A netns 2989
$ sudo ip netns exec 2989 ip addr add 10.1.1.1/32 dev A
$ sudo ip netns exec 2989 ip link set A up
$ sudo ip netns exec 2989 ip route add 10.1.1.2/32 dev A $ sudo ip link set B netns 3004
$ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B
$ sudo ip netns exec 3004 ip link set B up
$ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B

The two containers should now be able to ping each other and make connections successfully. Point-to-point links like this do not depend on a subnet nor a netmask, but on the bare assertion made by ip
route
 that some other single IP address is connected to a particular network interface.

如今这2个容器就能够相互ping通,并成功建立连接。点到点链路不须要子网和子网掩码,使用ip route 来连接单个ip地址到指定的网络接口。

Note that point-to-point links can be safely combined with other kinds of network connectivity — there is no need to start the containers with --net=none if
you want point-to-point links to be an addition to the container's normal networking instead of a replacement.

假设没有特殊须要你不须要指定--net=none来创建点到点链路。

A final permutation of this pattern is to create the point-to-point link between the Docker host and one container, which would allow the host to communicate with that one container on some single IP address and thus communicate “out-of-band” of the bridge
that connects the other, more usual containers. But unless you have very specific networking needs that drive you to such a solution, it is probably far preferable to use --icc=false to
lock down inter-container communication, as we explored earlier.

最后。就是创建一个容器仅仅跟主机通信,除非有特殊需求,你能够仅用--icc=false来 限制主机 间的通信。

Docker Network Configuration 高级网络配置的更多相关文章

  1. Sql Server Configuration Manager 网络配置为空,没有实例

    新用户一天内不准提问...Sql Server Configuration Manager 网络配置为空,没有实例无法设置ip和端口进行连接..

  2. 如何解决ubuntu 12.04重启后出现waiting for network configuration和网络标志消失问题

    如何解决ubuntu 12.04重启后出现waiting for network configuration和网络标志消失问题 作为菜鸟的我在学着设置网络后,重启电脑后显示 waiting forne ...

  3. Docker(五):Docker高级网络配置

    1.容器跨主机多子网方案 网络设计如下: 主机1:10.110.52.38 容器1: 192.168.0.1 vlan1 容器2: 192.168.0.2 vlan2 主机2:10.110.52.66 ...

  4. docker学习之network:初识网络配置

    起因 我的开发环境需要一个python代码运行环境.reids服务和mysql服务. 由于以前,我的开发环境是mac,而CI和线上运行环境是centos,偶尔会出项本地单元测试跑不过,而CI可以过.这 ...

  5. (转) docker跨主机 macvlan 网络配置

    原文链接 https://github.com/alfredhuang211/study-docker-doc/blob/master/docker%E8%B7%A8%E4%B8%BB%E6%9C%B ...

  6. DOCKER学习_005:Flannel网络配置

    一 简介 Flannel是一种基于overlay网络的跨主机容器网络解决方案,也就是将TCP数据包封装在另一种网络包里面进行路由转发和通信, Flannel是CoreOS开发,专门用于docker多机 ...

  7. Docker 使用指南 (三)—— 网络配置

    版权声明:本文由田飞雨原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/95 来源:腾云阁 https://www.qclou ...

  8. Linux系统的高级网络配置(bond、team、网桥)

    1.bond接口 Red Hat Enterprise Linux 允许管理员使用 bonding 内核模块和称为通道绑定接口的特殊网络接口将多个网络接口绑定 到一个通道.根据选择的绑定模式 , 通道 ...

  9. 5、Docker网络配置(单机)

    一.概述 以下内容参考:https://docs.docker.com/network/#network-drivers Docker容器和服务如此强大的原因之一是您可以将它们连接在一起,或者将它们连 ...

随机推荐

  1. tinymce原装插件源码分析(二)-link

    link 功能描述如下: 单纯放置光标: 1.如果光标放到了<a>上,读取a标签的内容,并弹框显示,确定的时候,更新当前a标签. 2.否则,就创建弹框,确定的时候,按照参数添加a标签. s ...

  2. C语言手册-read

    名称: pread,read-从文件读 语法: #include <unistd.h> ssize_t pread(int fildes, void *buf, size_t nbyte, ...

  3. vue-cli#2.0项目结构分析

    项目结构 build 构建工具相关的目录 config 配置目录 dist 通过工具打包生成的最终需要上线的目录 node_modules 存放本地开发所有的依赖包的目录 src 源码目录 stati ...

  4. 部署OGG时字符集转换问题--oracle to oracle已验证,其他异构环境应当也适用

    之前在安装OGG总是遇到字符集问题,尤其是多源端对一个目标端时,源端字符集不同,导致出现字符集问题 无法同步数据,查阅了大量的园子资料,都说要设置复制或抽取进程中SETENV (NLS_LANG=AM ...

  5. asp.net C# 获取网页源代码的几种方式

    1 方法 System.Net.WebClient aWebClient = new System.Net.WebClient(); aWebClient.Encoding = System.Text ...

  6. Perfect Rectangle(完美矩形)

    我们有 N 个与坐标轴对齐的矩形, 其中 N > 0, 判断它们是否能精确地覆盖一个矩形区域. 每个矩形用左下角的点和右上角的点的坐标来表示.例如, 一个单位正方形可以表示为 [1,1,2,2] ...

  7. 冒泡,简单选择,直接插入排序(Java版)

    冒泡.简单选择,直接插入这三种排序都是简单排序. 工具类 package Utils; import java.util.Arrays; public class SortUtils { public ...

  8. DNS RR代码和含义

    记录类型 代码 号码 定义的 RFC 描述 功能 A 1 RFC 1035 IP 地址记录 传回一个 32 比特的 IPv4 地址,最常用于映射主机名称到 IP地址,但也用于DNSBL(RFC 110 ...

  9. java9新特性-10-语法改进:UnderScore(下划线)使用的限制

    1.使用说明 在java 8 中,标识符可以独立使用“_”来命名:   但是,在java 9 中规定“_”不再可以单独命名标识符了,如果使用,会报错:    

  10. 集合TreeSet的使用

    集合中的TreeSet是集合体系结构中的底层实现,是Collection的孙子,Set的儿子.TreeSet除拥有父接口的特点外,还有其自身的特点.下面就看看TreeSet的排序是怎么实现的.从它的构 ...