$ ip netns 6e9269a3edd8 (id: 1) 332acf6a7ea2 (id: 0) $ ip netns exec 6e9269a3edd8 ip addr 1: lo: 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 validlft forever preferredlft forever 6: eth0@if7: mtu 1500 qdisc noqueue state UP group. 前言此篇博文是笔者所总结的 Docker 系列之一; 本文为作者的原创作品,转载需注明出处; 概述本章节主要是描述 docker 的 network namespace; docker 的隔离网络环境是通过 linux network namespace 实现的。 docker 的网络实现docker 的网络实现一共有四种模式,bridge、host、container 以及 none 模式 br. Expected behaviour Faster response loading time Actual behaviour Network connection load response time is well above 1min in most cases Information Diagnostic ID: 8527377B-F84E-4E32-8661-0A677D5A24DF Docker for Mac: 1.12.0-a (Build 11213.
Nets Docker For Mac Download
Update (2018-03-22) Since I wrote this document back in 2014,Docker has developed the macvlan networkdriver. That gives you asupported mechanism for direct connectivity to a local layer 2network. I’ve written an article about working with the macvlandriver.
This article discusses four ways to make a Docker container appear ona local network. These are not suggested as practical solutions, butare meant to illustrate some of the underlying network technologyavailable in Linux.
If you were actually going to use one of these solutions as anythingother than a technology demonstration, you might look to the pipework script, which can automate many of these configurations.
Goals and Assumptions
In the following examples, we have a host with address 10.12.0.76 onthe 10.12.0.0/21 network. We are creating a Docker container that wewant to expose as 10.12.0.117.
I am running Fedora 20 with Docker 1.1.2. This means, in particular,that my
utils-linux
package is recent enough to include thensenter command. If you don’t have that handy, there is aconvenient Docker recipe to build it for you at jpetazzo/nsenteron GitHub.A little help along the way
In this article we will often refer to the PID of a docker container.In order to make this convenient, drop the following into a scriptcalled
docker-pid
, place it somewhere on your PATH
, and make itexecutable:This allows us to conveniently get the PID of a docker container byname or ID:
In a script called
docker-ip
, place the following:And now we can get the ip address of a container like this:
Using NAT
This uses the standard Docker network model combined with NAT rules onyour host to redirect inbound traffic to/outbound traffic from theappropriate IP address.
Assign our target address to your host interface:
Start your docker container, using the
-p
option to bind exposedports to an ip address and port on the host:With this command, Docker will set up the standard network model:
- It will create a veth interface pair.
- Connect one end to the
docker0
bridge. - Place the other inside the container namespace as
eth0
. - Assign an ip address from the network used by the
docker0
bridge.
Because we added
-p 10.12.0.117:80:80
to our command line, Dockerwill also create the following rule in the nat
table DOCKER
chain (which is run from the PREROUTING
chain):This matches traffic TO our target address (
-d 10.12.0.117/32
) notoriginating on the docker0
bridge (! -i docker0
) destined fortcp
port 80
(-p tcp -m tcp --dport 80
). Matching traffic hasit’s destination set to the address of our docker container (-j DNAT --to-destination 172.17.0.4:80
).From a host elsewhere on the network, we can now access the web serverat our selected ip address:
If our container were to initiate a network connection with anothersystem, that connection would appear to originate with ip address ofour host. We can fix that my adding a
SNAT
rule to thePOSTROUTING
chain to modify the source address:Note here the use of
-I POSTROUTING
, which places the rule at thetop of the POSTROUTING
chain. This is necessary because, bydefault, Docker has already added the following rule to the top of thePOSTROUTING
chain:Because this
MASQUERADE
rule matches traffic from any container, weneed to place our rule earlier in the POSTROUTING
chain for it tohave any affect.With these rules in place, traffic to 10.12.0.117 (port 80) isdirected to our
web
container, and traffic originating in the webcontainer will appear to come from 10.12.0.117.With Linux Bridge devices
The previous example was relatively easy to configure, but has a fewshortcomings. If you need to configure an interface using DHCP, or ifyou have an application that needs to be on the same layer 2 broadcastdomain as other devices on your network, NAT rules aren’t going towork out.
This solution uses a Linux bridge device, created using
brctl
, toconnect your containers directly to a physical network.Start by creating a new bridge device. In this example, we’ll createone called
br-em1
:We’re going to add
em1
to this bridge, and move the ip address fromem1
onto the bridge.WARNING: This is not something you should do remotely, especiallyfor the first time, and making this persistent varies fromdistribution to distribution, so this will not be a persistentconfiguration.
Look at the configuration of interface
em1
and note the existing ipaddress:Look at your current routes and note the default route:
Now, add this device to your bridge:
Configure the bridge with the address that used to belong to
em1
:And move the default route to the bridge:
If you were doing this remotely; you would do this all in one linelike this:
At this point, verify that you still have network connectivity:
Start up the web container:
This will give us the normal
eth0
interface inside the container,but we’re going to ignore that and add a new one.Create a veth interface pair:
Add the
web-ext
link to the br-eth0
bridge:And add the
web-int
interface to the namespace of the container:Next, we’ll use the nsenter command (part of the
util-linux
package) to run some commands inside the web
container. Start by bringing up the link inside the container:Assign our target ip address to the interface:
And set a new default route inside the container:
Again, we can verify from another host that the web server isavailable at 10.12.0.117:
Note that in this example we have assigned a static ip address, but wecould just have easily acquired an address using DHCP. After running:
We can run:
With Open vSwitch Bridge devices
![Nets Nets](https://pic2.zhimg.com/v2-9d46184b6b3d385f37f872575f693ed9_r.jpg)
This process is largely the same as in the previous example, but weuse Open vSwitch instead of the legacy Linux bridge devices.These instructions assume that you have already installed and startedOpen vSwitch on your system.
Create an OVS bridge using the
ovs-vsctl
command:And add your external interface:
And then proceed as in the previous set of instructions.
The equivalent all-in-one command is:
Once that completes, your openvswitch configuration should look likethis:
To add the
web-ext
interface to the bridge, run:Instead of:
WARNING: The Open vSwitch configuration persists between reboots.This means that when your system comes back up,
em1
will still be amember of br-em
, which will probably result in no networkconnectivity for your host.Before rebooting your system, make sure to
ovs-vsctl del-port br-em1 em1
.With macvlan devices
This process is similar to the previous two, but instead of using abridge device we will create a macvlan, which is a virtual networkinterface associated with a physical interface. Unlike the previoustwo solutions, this does not require any interruption to your primarynetwork interface.
Start by creating a docker container as in the previous examples:
Create a
macvlan
interface associated with your physical interface:This creates a new
macvlan
interface named em1p0
(but you canname it anything you want) associated with interface em1
. We aresetting it up in bridge
mode, which permits all macvlan
interfacesto communicate with eachother.Add this interface to the container’s network namespace:
Bring up the link:
And configure the ip address and routing:
And demonstrate that from another host the web server is availableat 10.12.0.117:
But note that if you were to try the same thing on the host, you wouldget:
The host is unable to communicate with
macvlan
devices via theprimary interface. You can create anothermacvlan
interface onthe host, give it an address on the appropriate network, and then setup routes to your containers via that interface:Update (2018-03-22) Since I wrote this document back in 2014,Docker has developed the macvlan networkdriver. That gives you asupported mechanism for direct connectivity to a local layer 2network. I’ve written an article about working with the macvlandriver.
This article discusses four ways to make a Docker container appear ona local network. These are not suggested as practical solutions, butare meant to illustrate some of the underlying network technologyavailable in Linux.
If you were actually going to use one of these solutions as anythingother than a technology demonstration, you might look to the pipework script, which can automate many of these configurations.
Goals and Assumptions
In the following examples, we have a host with address 10.12.0.76 onthe 10.12.0.0/21 network. We are creating a Docker container that wewant to expose as 10.12.0.117.
I am running Fedora 20 with Docker 1.1.2. This means, in particular,that my
utils-linux
package is recent enough to include thensenter command. If you don’t have that handy, there is aconvenient Docker recipe to build it for you at jpetazzo/nsenteron GitHub.A little help along the way
In this article we will often refer to the PID of a docker container.In order to make this convenient, drop the following into a scriptcalled
docker-pid
, place it somewhere on your PATH
, and make itexecutable:This allows us to conveniently get the PID of a docker container byname or ID:
In a script called
docker-ip
, place the following:And now we can get the ip address of a container like this:
Using NAT
This uses the standard Docker network model combined with NAT rules onyour host to redirect inbound traffic to/outbound traffic from theappropriate IP address.
Assign our target address to your host interface:
Start your docker container, using the
-p
option to bind exposedports to an ip address and port on the host:![Nets Nets](https://www.programmersought.com/images/316/ffa3c9ad90bb0e280437d352e1dc7424.png)
With this command, Docker will set up the standard network model:
- It will create a veth interface pair.
- Connect one end to the
docker0
bridge. - Place the other inside the container namespace as
eth0
. - Assign an ip address from the network used by the
docker0
bridge.
Because we added
-p 10.12.0.117:80:80
to our command line, Dockerwill also create the following rule in the nat
table DOCKER
chain (which is run from the PREROUTING
chain):This matches traffic TO our target address (
-d 10.12.0.117/32
) notoriginating on the docker0
bridge (! -i docker0
) destined fortcp
port 80
(-p tcp -m tcp --dport 80
). Matching traffic hasit’s destination set to the address of our docker container (-j DNAT --to-destination 172.17.0.4:80
).From a host elsewhere on the network, we can now access the web serverat our selected ip address:
If our container were to initiate a network connection with anothersystem, that connection would appear to originate with ip address ofour host. We can fix that my adding a
SNAT
rule to thePOSTROUTING
chain to modify the source address:Note here the use of
-I POSTROUTING
, which places the rule at thetop of the POSTROUTING
chain. This is necessary because, bydefault, Docker has already added the following rule to the top of thePOSTROUTING
chain:Because this
MASQUERADE
rule matches traffic from any container, weneed to place our rule earlier in the POSTROUTING
chain for it tohave any affect.With these rules in place, traffic to 10.12.0.117 (port 80) isdirected to our
web
container, and traffic originating in the webcontainer will appear to come from 10.12.0.117.With Linux Bridge devices
The previous example was relatively easy to configure, but has a fewshortcomings. If you need to configure an interface using DHCP, or ifyou have an application that needs to be on the same layer 2 broadcastdomain as other devices on your network, NAT rules aren’t going towork out.
This solution uses a Linux bridge device, created using
brctl
, toconnect your containers directly to a physical network.Start by creating a new bridge device. In this example, we’ll createone called
br-em1
:We’re going to add
em1
to this bridge, and move the ip address fromem1
onto the bridge.WARNING: This is not something you should do remotely, especiallyfor the first time, and making this persistent varies fromdistribution to distribution, so this will not be a persistentconfiguration.
Look at the configuration of interface
em1
and note the existing ipaddress:Look at your current routes and note the default route:
Now, add this device to your bridge:
Configure the bridge with the address that used to belong to
em1
:And move the default route to the bridge:
If you were doing this remotely; you would do this all in one linelike this:
At this point, verify that you still have network connectivity:
Start up the web container:
This will give us the normal
eth0
interface inside the container,but we’re going to ignore that and add a new one.Create a veth interface pair:
Add the
web-ext
link to the br-eth0
bridge:And add the
web-int
interface to the namespace of the container:Next, we’ll use the nsenter command (part of the
util-linux
package) to run some commands inside the web
container. Start by bringing up the link inside the container:Assign our target ip address to the interface:
And set a new default route inside the container:
Again, we can verify from another host that the web server isavailable at 10.12.0.117:
Note that in this example we have assigned a static ip address, but wecould just have easily acquired an address using DHCP. After running:
We can run:
With Open vSwitch Bridge devices
This process is largely the same as in the previous example, but weuse Open vSwitch instead of the legacy Linux bridge devices.These instructions assume that you have already installed and startedOpen vSwitch on your system.
Create an OVS bridge using the
ovs-vsctl
command:And add your external interface:
And then proceed as in the previous set of instructions.
The equivalent all-in-one command is:
Once that completes, your openvswitch configuration should look likethis:
To add the
web-ext
interface to the bridge, run:Instead of:
WARNING: The Open vSwitch configuration persists between reboots.This means that when your system comes back up,
em1
will still be amember of br-em
, which will probably result in no networkconnectivity for your host.Before rebooting your system, make sure to
ovs-vsctl del-port br-em1 em1
.Nets Docker For Mac Installer
With macvlan devices
This process is similar to the previous two, but instead of using abridge device we will create a macvlan, which is a virtual networkinterface associated with a physical interface. Unlike the previoustwo solutions, this does not require any interruption to your primarynetwork interface.
Start by creating a docker container as in the previous examples:
Create a
macvlan
interface associated with your physical interface:This creates a new
macvlan
interface named em1p0
(but you canname it anything you want) associated with interface em1
. We aresetting it up in bridge
mode, which permits all macvlan
interfacesto communicate with eachother.Nets Docker For Mac Catalina
Add this interface to the container’s network namespace:
Bring up the link:
And configure the ip address and routing:
Nets Docker For Mac Os
And demonstrate that from another host the web server is availableat 10.12.0.117:
But note that if you were to try the same thing on the host, you wouldget:
The host is unable to communicate with
macvlan
devices via theprimary interface. You can create anothermacvlan
interface onthe host, give it an address on the appropriate network, and then setup routes to your containers via that interface: