Update vlan-networks.md

Some small changes to get the examples so that they run without error for me.
Improve consistency of presentation of the examples.
Fix some typos

Signed-off-by: kevinfeyrer <kevin.feyrer@btinternet.com>

Update vlan-networks.md

Restore "ip" accidentally removed

Signed-off-by: kevinfeyrer <kevin.feyrer@btinternet.com>

Update vlan-networks.md

Change prompt from container "$$" to host "$"

Signed-off-by: kevinfeyrer <kevin.feyrer@btinternet.com>

Update vlan-networks.md

Some changes suggested by cpuguy83 and thaJeztah

Signed-off-by: kevinfeyrer <kevin.feyrer@btinternet.com>
This commit is contained in:
kevinfeyrer 2017-02-26 23:37:59 +00:00 committed by Tibor Vass
parent 2fcb361c55
commit dd34522fa8
1 changed files with 76 additions and 72 deletions

View File

@ -6,7 +6,7 @@ The Ipvlan driver is currently in experimental mode in order to incubate Docker
Ipvlan is a new twist on the tried and true network virtualization technique. The Linux implementations are extremely lightweight because rather than using the traditional Linux bridge for isolation, they are simply associated to a Linux Ethernet interface or sub-interface to enforce separation between networks and connectivity to the physical network.
Ipvlan offers a number of unique features and plenty of room for further innovations with the various modes. Two high level advantages of these approaches are, the positive performance implications of bypassing the Linux bridge and the simplicity of having less moving parts. Removing the bridge that traditionally resides in between the Docker host NIC and container interface leaves a very simple setup consisting of container interfaces, attached directly to the Docker host interface. This result is easy access for external facing services as there is no port mappings in these scenarios.
Ipvlan offers a number of unique features and plenty of room for further innovations with the various modes. Two high level advantages of these approaches are, the positive performance implications of bypassing the Linux bridge and the simplicity of having fewer moving parts. Removing the bridge that traditionally resides in between the Docker host NIC and container interface leaves a simple setup consisting of container interfaces, attached directly to the Docker host interface. This result is easy access for external facing services as there is no need for port mappings in these scenarios.
### Pre-Requisites
@ -21,14 +21,14 @@ Ipvlan offers a number of unique features and plenty of room for further innovat
### Ipvlan L2 Mode Example Usage
The ipvlan `L2` mode example is like the following image. The driver is specified with `-d driver_name` option. In this case `-d ipvlan`.
An example of the ipvlan `L2` mode topology is shown in the following image. The driver is specified with `-d driver_name` option. In this case `-d ipvlan`.
![Simple Ipvlan L2 Mode Example](images/ipvlan_l2_simple.png)
The parent interface in the next example `-o parent=eth0` is configured as followed:
```
ip addr show eth0
$ ip addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0
```
@ -39,14 +39,14 @@ Create the ipvlan network and run a container attaching to it:
```
# Ipvlan (-o ipvlan_mode= Defaults to L2 mode if not specified)
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o ipvlan_mode=l2 \
-o parent=eth0 db_net
# Start a container on the db_net network
docker run --net=db_net -it --rm alpine /bin/sh
$ docker run --net=db_net -it --rm alpine /bin/sh
# NOTE: the containers can NOT ping the underlying host interfaces as
# they are intentionally filtered by Linux for additional isolation.
@ -62,47 +62,47 @@ The following will create the exact same network as the network `db_net` created
```
# Ipvlan (-o ipvlan_mode= Defaults to L2 mode if not specified)
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.1.0/24 \
-o parent=eth0 db_net_ipv
# Start a container with an explicit name in daemon mode
docker run --net=db_net_ipv --name=ipv1 -itd alpine /bin/sh
$ docker run --net=db_net_ipv --name=ipv1 -itd alpine /bin/sh
# Start a second container and ping using the container name
# to see the docker included name resolution functionality
docker run --net=db_net_ipv --name=ipv2 -it --rm alpine /bin/sh
ping -c 4 ipv1
$ docker run --net=db_net_ipv --name=ipv2 -it --rm alpine /bin/sh
$ ping -c 4 ipv1
# NOTE: the containers can NOT ping the underlying host interfaces as
# they are intentionally filtered by Linux for additional isolation.
```
The drivers also support the `--internal` flag that will completely isolate containers on a network from any communications external to that network. Since network isolation is tightly coupled to the network's parent interface the result of leaving the `-o parent=` option off of a network create is the exact same as the `--internal` option. If the parent interface is not specified or the `--internal` flag is used, a netlink type `dummy` parent interface is created for the user and used as the parent interface effectively isolating the network completely.
The drivers also support the `--internal` flag that will completely isolate containers on a network from any communications external to that network. Since network isolation is tightly coupled to the network's parent interface the result of leaving the `-o parent=` option off of a `docker network create` is the exact same as the `--internal` option. If the parent interface is not specified or the `--internal` flag is used, a netlink type `dummy` parent interface is created for the user and used as the parent interface effectively isolating the network completely.
The following two `docker network create` examples result in identical networks that you can attach container to:
```
# Empty '-o parent=' creates an isolated network
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.10.0/24 isolated1
# Explicit '--internal' flag is the same:
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.11.0/24 --internal isolated2
# Even the '--subnet=' can be left empty and the default
# IPAM subnet of 172.18.0.0/16 will be assigned
docker network create -d ipvlan isolated3
$ docker network create -d ipvlan isolated3
docker run --net=isolated1 --name=cid1 -it --rm alpine /bin/sh
docker run --net=isolated2 --name=cid2 -it --rm alpine /bin/sh
docker run --net=isolated3 --name=cid3 -it --rm alpine /bin/sh
$ docker run --net=isolated1 --name=cid1 -it --rm alpine /bin/sh
$ docker run --net=isolated2 --name=cid2 -it --rm alpine /bin/sh
$ docker run --net=isolated3 --name=cid3 -it --rm alpine /bin/sh
# To attach to any use `docker exec` and start a shell
docker exec -it cid1 /bin/sh
docker exec -it cid2 /bin/sh
docker exec -it cid3 /bin/sh
$ docker exec -it cid1 /bin/sh
$ docker exec -it cid2 /bin/sh
$ docker exec -it cid3 /bin/sh
```
### Ipvlan 802.1q Trunk L2 Mode Example Usage
@ -119,7 +119,7 @@ For the driver to add/delete the vlan sub-interfaces the format needs to be `int
The option to use either existing parent vlan sub-interfaces or let Docker manage them enables the user to either completely manage the Linux interfaces and networking or let Docker create and delete the Vlan parent sub-interfaces (netlink `ip link`) with no effort from the user.
For example: `eth0.10` to denote a sub-interface of `eth0` tagged with vlan id `10`. The equivalent `ip link` command would be `ip link add link eth0 name eth0.10 type vlan id 10`.
For example: use `eth0.10` to denote a sub-interface of `eth0` tagged with the vlan id of `10`. The equivalent `ip link` command would be `ip link add link eth0 name eth0.10 type vlan id 10`.
The example creates the vlan tagged networks and then start two containers to test connectivity between containers. Different Vlans cannot ping one another without a router routing between the two networks. The default namespace is not reachable per ipvlan design in order to isolate container namespaces from the underlying host.
@ -129,14 +129,14 @@ In the first network tagged and isolated by the Docker host, `eth0.20` is the pa
```
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.20.0/24 \
--gateway=192.168.20.1 \
-o parent=eth0.20 ipvlan20
# in two separate terminals, start a Docker container and the containers can now ping one another.
docker run --net=ipvlan20 -it --name ivlan_test1 --rm alpine /bin/sh
docker run --net=ipvlan20 -it --name ivlan_test2 --rm alpine /bin/sh
$ docker run --net=ipvlan20 -it --name ivlan_test1 --rm alpine /bin/sh
$ docker run --net=ipvlan20 -it --name ivlan_test2 --rm alpine /bin/sh
```
**Vlan ID 30**
@ -145,21 +145,21 @@ In the second network, tagged and isolated by the Docker host, `eth0.30` is the
```
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged.
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.30.0/24 \
--gateway=192.168.30.1 \
-o parent=eth0.30 \
-o ipvlan_mode=l2 ipvlan30
# in two separate terminals, start a Docker container and the containers can now ping one another.
docker run --net=ipvlan30 -it --name ivlan_test3 --rm alpine /bin/sh
docker run --net=ipvlan30 -it --name ivlan_test4 --rm alpine /bin/sh
$ docker run --net=ipvlan30 -it --name ivlan_test3 --rm alpine /bin/sh
$ docker run --net=ipvlan30 -it --name ivlan_test4 --rm alpine /bin/sh
```
The gateway is set inside of the container as the default gateway. That gateway would typically be an external router on the network.
```
$ ip route
$$ ip route
default via 192.168.30.1 dev eth0
192.168.30.0/24 dev eth0 src 192.168.30.2
```
@ -169,14 +169,14 @@ Example: Multi-Subnet Ipvlan L2 Mode starting two containers on the same subnet
Secondary addresses on network routers are common as an address space becomes exhausted to add another secondary to an L3 vlan interface or commonly referred to as a "switched virtual interface" (SVI).
```
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.114.0/24 --subnet=192.168.116.0/24 \
--gateway=192.168.114.254 --gateway=192.168.116.254 \
-o parent=eth0.114 \
-o ipvlan_mode=l2 ipvlan114
docker run --net=ipvlan114 --ip=192.168.114.10 -it --rm alpine /bin/sh
docker run --net=ipvlan114 --ip=192.168.114.11 -it --rm alpine /bin/sh
$ docker run --net=ipvlan114 --ip=192.168.114.10 -it --rm alpine /bin/sh
$ docker run --net=ipvlan114 --ip=192.168.114.11 -it --rm alpine /bin/sh
```
A key takeaway is, operators have the ability to map their physical network into their virtual network for integrating containers into their environment with no operational overhauls required. NetOps simply drops an 802.1q trunk into the Docker host. That virtual link would be the `-o parent=` passed in the network creation. For untagged (non-VLAN) links, it is as simple as `-o parent=eth0` or for 802.1q trunks with VLAN IDs each network gets mapped to the corresponding VLAN/Subnet from the network.
@ -210,7 +210,7 @@ Ipvlan L3 mode drops all broadcast and multicast traffic. This reason alone make
- Unlike ipvlan l2 modes, different subnets/networks can ping one another as long as they share the same parent interface `-o parent=`.
```
ip a show eth0
$$ ip a show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:39:45:2e brd ff:ff:ff:ff:ff:ff
inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0
@ -224,20 +224,20 @@ The following example does not specify a parent interface. The network drivers w
```
# Create the Ipvlan L3 network
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.214.0/24 \
--subnet=10.1.214.0/24 \
-o ipvlan_mode=l3 ipnet210
# Test 192.168.214.0/24 connectivity
docker run --net=ipnet210 --ip=192.168.214.10 -itd alpine /bin/sh
docker run --net=ipnet210 --ip=10.1.214.10 -itd alpine /bin/sh
$ docker run --net=ipnet210 --ip=192.168.214.10 -itd alpine /bin/sh
$ docker run --net=ipnet210 --ip=10.1.214.10 -itd alpine /bin/sh
# Test L3 connectivity from 10.1.214.0/24 to 192.168.212.0/24
docker run --net=ipnet210 --ip=192.168.214.9 -it --rm alpine ping -c 2 10.1.214.10
$ docker run --net=ipnet210 --ip=192.168.214.9 -it --rm alpine ping -c 2 10.1.214.10
# Test L3 connectivity from 192.168.212.0/24 to 10.1.214.0/24
docker run --net=ipnet210 --ip=10.1.214.9 -it --rm alpine ping -c 2 192.168.214.10
$ docker run --net=ipnet210 --ip=10.1.214.9 -it --rm alpine ping -c 2 192.168.214.10
```
@ -245,9 +245,9 @@ Notice there is no `--gateway=` option in the network create. The field is ignor
```
# Inside an L3 mode container
$ ip route
$$ ip route
default dev eth0
192.168.120.0/24 dev eth0 src 192.168.120.2
192.168.214.0/24 dev eth0 src 192.168.214.10
```
In order to ping the containers from a remote Docker host or the container be able to ping a remote host, the remote host or the physical network in between need to have a route pointing to the host IP address of the container's Docker host eth interface. More on this as we evolve the Ipvlan `L3` story.
@ -260,19 +260,21 @@ In order to ping the containers from a remote Docker host or the container be ab
```
# Create a v6 network
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=2001:db8:abc2::/64 --gateway=2001:db8:abc2::22 \
-o parent=eth0.139 v6ipvlan139
# Start a container on the network
docker run --net=v6ipvlan139 -it --rm alpine /bin/sh
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh
```
View the container eth0 interface and v6 routing table:
```
eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
# Inside the IPv6 container
$$ ip a show eth0
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
@ -281,7 +283,7 @@ View the container eth0 interface and v6 routing table:
inet6 2001:db8:abc2::1/64 scope link nodad
valid_lft forever preferred_lft forever
root@5c1dc74b1daa:/# ip -6 route
$$ ip -6 route
2001:db8:abc4::/64 dev eth0 proto kernel metric 256
2001:db8:abc2::/64 dev eth0 proto kernel metric 256
default via 2001:db8:abc2::22 dev eth0 metric 1024
@ -290,9 +292,11 @@ default via 2001:db8:abc2::22 dev eth0 metric 1024
Start a second container and ping the first container's v6 address.
```
# Test L2 connectivity over IPv6
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh
root@b817e42fcc54:/# ip a show eth0
# Inside the second IPv6 container
$$ ip a show eth0
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.3/16 scope global eth0
@ -302,7 +306,7 @@ root@b817e42fcc54:/# ip a show eth0
inet6 2001:db8:abc2::2/64 scope link nodad
valid_lft forever preferred_lft forever
root@b817e42fcc54:/# ping6 2001:db8:abc2::1
$$ ping6 2001:db8:abc2::1
PING 2001:db8:abc2::1 (2001:db8:abc2::1): 56 data bytes
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=0 ttl=64 time=0.044 ms
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=1 ttl=64 time=0.058 ms
@ -316,7 +320,7 @@ The next example with setup a dual stack IPv4/IPv6 network with an example VLAN
Next create a network with two IPv4 subnets and one IPv6 subnets, all of which have explicit gateways:
```
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.140.0/24 --subnet=192.168.142.0/24 \
--gateway=192.168.140.1 --gateway=192.168.142.1 \
--subnet=2001:db8:abc9::/64 --gateway=2001:db8:abc9::22 \
@ -327,9 +331,9 @@ docker network create -d ipvlan \
Start a container and view eth0 and both v4 & v6 routing tables:
```
docker run --net=v6ipvlan139 --ip6=2001:db8:abc2::51 -it --rm alpine /bin/sh
$ docker run --net=ipvlan140 --ip6=2001:db8:abc2::51 -it --rm alpine /bin/sh
root@3cce0d3575f3:/# ip a show eth0
$ ip a show eth0
78: eth0@if77: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
inet 192.168.140.2/24 scope global eth0
@ -339,11 +343,11 @@ root@3cce0d3575f3:/# ip a show eth0
inet6 2001:db8:abc9::1/64 scope link nodad
valid_lft forever preferred_lft forever
root@3cce0d3575f3:/# ip route
$$ ip route
default via 192.168.140.1 dev eth0
192.168.140.0/24 dev eth0 proto kernel scope link src 192.168.140.2
root@3cce0d3575f3:/# ip -6 route
$$ ip -6 route
2001:db8:abc4::/64 dev eth0 proto kernel metric 256
2001:db8:abc9::/64 dev eth0 proto kernel metric 256
default via 2001:db8:abc9::22 dev eth0 metric 1024
@ -352,7 +356,7 @@ default via 2001:db8:abc9::22 dev eth0 metric 1024
Start a second container with a specific `--ip4` address and ping the first host using IPv4 packets:
```
docker run --net=ipvlan140 --ip=192.168.140.10 -it --rm alpine /bin/sh
$ docker run --net=ipvlan140 --ip=192.168.140.10 -it --rm alpine /bin/sh
```
**Note**: Different subnets on the same parent interface in Ipvlan `L2` mode cannot ping one another. That requires a router to proxy-arp the requests with a secondary subnet. However, Ipvlan `L3` will route the unicast traffic between disparate subnets as long as they share the same `-o parent` parent link.
@ -368,7 +372,7 @@ The primary difference you will see is that L3 mode does not create a default ro
```
# Create an IPv6+IPv4 Dual Stack Ipvlan L3 network
# Gateways for both v4 and v6 are set to a dev e.g. 'default dev eth0'
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.110.0/24 \
--subnet=192.168.112.0/24 \
--subnet=2001:db8:abc6::/64 \
@ -378,19 +382,19 @@ docker network create -d ipvlan \
# Start a few of containers on the network (ipnet110)
# in separate terminals and check connectivity
docker run --net=ipnet110 -it --rm alpine /bin/sh
$ docker run --net=ipnet110 -it --rm alpine /bin/sh
# Start a second container specifying the v6 address
docker run --net=ipnet110 --ip6=2001:db8:abc6::10 -it --rm alpine /bin/sh
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::10 -it --rm alpine /bin/sh
# Start a third specifying the IPv4 address
docker run --net=ipnet110 --ip=192.168.112.50 -it --rm alpine /bin/sh
$ docker run --net=ipnet110 --ip=192.168.112.30 -it --rm alpine /bin/sh
# Start a 4th specifying both the IPv4 and IPv6 addresses
docker run --net=ipnet110 --ip6=2001:db8:abc6::50 --ip=192.168.112.50 -it --rm alpine /bin/sh
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::50 --ip=192.168.112.50 -it --rm alpine /bin/sh
```
Interface and routing table outputs are as follows:
```
root@3a368b2a982e:/# ip a show eth0
$$ ip a show eth0
63: eth0@if59: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
inet 192.168.112.2/24 scope global eth0
@ -401,11 +405,11 @@ root@3a368b2a982e:/# ip a show eth0
valid_lft forever preferred_lft forever
# Note the default route is simply the eth device because ARPs are filtered.
root@3a368b2a982e:/# ip route
$$ ip route
default dev eth0 scope link
192.168.112.0/24 dev eth0 proto kernel scope link src 192.168.112.2
root@3a368b2a982e:/# ip -6 route
$$ ip -6 route
2001:db8:abc4::/64 dev eth0 proto kernel metric 256
2001:db8:abc6::/64 dev eth0 proto kernel metric 256
default dev eth0 metric 1024
@ -421,51 +425,51 @@ docker: Error response from daemon: Address already in use.
**Vlan ID 40**
If a user does not want the driver to create the vlan sub-interface it simply needs to exist prior to the `docker network create`. If you have sub-interface naming that is not `interface.vlan_id` it is honored in the `-o parent=` option again as long as the interface exists and us up.
If a user does not want the driver to create the vlan sub-interface it simply needs to exist prior to the `docker network create`. If you have sub-interface naming that is not `interface.vlan_id` it is honored in the `-o parent=` option again as long as the interface exists and is up.
Links if manually created can be named anything you want. As long as the exist when the network is created that is all that matters. Manually created links do not get deleted regardless of the name when the network is deleted with `docker network rm`.
Links, when manually created, can be named anything as long as they exist when the network is created. Manually created links do not get deleted regardless of the name when the network is deleted with `docker network rm`.
```
# create a new sub-interface tied to dot1q vlan 40
ip link add link eth0 name eth0.40 type vlan id 40
$ ip link add link eth0 name eth0.40 type vlan id 40
# enable the new sub-interface
ip link set eth0.40 up
$ ip link set eth0.40 up
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.40.0/24 \
--gateway=192.168.40.1 \
-o parent=eth0.40 ipvlan40
# in two separate terminals, start a Docker container and the containers can now ping one another.
docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh
```
**Example:** Vlan sub-interface manually created with any name:
```
# create a new sub interface tied to dot1q vlan 40
ip link add link eth0 name foo type vlan id 40
$ ip link add link eth0 name foo type vlan id 40
# enable the new sub-interface
ip link set foo up
$ ip link set foo up
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
docker network create -d ipvlan \
$ docker network create -d ipvlan \
--subnet=192.168.40.0/24 --gateway=192.168.40.1 \
-o parent=foo ipvlan40
# in two separate terminals, start a Docker container and the containers can now ping one another.
docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh
```
Manually created links can be cleaned up with:
```
ip link del foo
$ ip link del foo
```
As with all of the Libnetwork drivers, they can be mixed and matched, even as far as running 3rd party ecosystem drivers in parallel for maximum flexibility to the Docker user.