In my use case under Docker, I want to present my containers on several different VLANs.
To do this, my server has two network interfaces:
- eth0: dedicated to server administration, no container will be presented, is connected on a dedicated VLAN for Docker administration
- eth1: connected on a switch port with the desired VLANs tagged
Prerequisites
Have an operational Docker. For Docker installation, refer to the official procedure: https://docs.docker.com/engine/install/debian/
Install the vlan package
apt update && apt install vlanConfigure eth1
For the configuration of the eth1 interface, I created a file in /etc/network/interfaces.d/99-vlans as I am on Debian and do not use netplan. Be careful to declare the interface for VLANs only once and only once. In this example, I will use VLANs 10 and 20. Adapt according to your use case.
# Parent Interface
allow-hotplug eth1
iface eth1 inet manual
up ip link set eth1 up
down ip link set eth1 down
# Vlan 10 Interface
auto eth1.10
iface eth1.10 inet manual
vlan-raw-device eth1
up ip link set eth1.10 up
down ip link set eth1.10 down
# Vlan 20 Interface
auto eth1.20
iface eth1.20 inet manual
vlan-raw-device eth1
up ip link set eth1.20 up
down ip link set eth1.20 downAs you can notice, no IP address is defined in the configuration file. This is because only the containers will be presented on the VLANs. The VLAN interfaces are named <parent>.<vlanid> to give the VLAN ID to use. That is eth1.10 and eth1.20
We then apply the configuration via a restart of the networking service
systemctl restart networking.serviceWe can then verify that the configuration has been taken into account via the ip link command, the new interfaces must be present and in the LOWER_UP status
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 6e:de:8d:cf:52:f3 brd ff:ff:ff:ff:ff:ff
altname enp0s18
altname ens18
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 6d:f3:61:4f:8c:b4 brd ff:ff:ff:ff:ff:ff
altname enp0s19
altname ens19
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 74:03:aa:8b:85:7e brd ff:ff:ff:ff:ff:ff
60: eth1.1202@eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 6d:f3:61:4f:8c:b4 brd ff:ff:ff:ff:ff:ff
61: eth1.3202@eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 6d:f3:61:4f:8c:b4 brd ff:ff:ff:ff:ff:ffCreating Docker networks
We then move on to creating networks, for this we use the macvlan driver, here you will need to replace the subnets with what will be used on each of the VLANs
docker network create -d macvlan \
--subnet=192.168.10.0/24 \
--gateway=192.168.10.1 \
-o parent=eth1.10 \
vlan10
docker network create -d macvlan \
--subnet=192.168.20.0/24 \
--gateway=192.168.20.1 \
-o parent=eth1.20 \
vlan20We can then list the networks to validate that they are present via the following command:
docker network lsNETWORK ID NAME DRIVER SCOPE
xxxxxxxxxxxx bridge bridge local
xxxxxxxxxxxx host host local
xxxxxxxxxxxx none null local
xxxxxxxxxxxx vlan10 macvlan local
xxxxxxxxxxxx vlan20 macvlan localConfiguring a container via compose.yaml
For my container deployment, I chose to go through a compose.yaml file
Below is a generic configuration example to present the container on IP address 192.168.20.15 on VLAN 20
services:
bind9:
image: myimage
container_name: mycontainer
restart: unless-stopped
networks:
vlan20:
ipv4_address: 192.168.20.15
networks:
vlan20:
external: trueNote that here no port is declared, indeed in the case of configuring an IP address all the container’s ports are presented on the destination network.
The external: true allows to indicate that the network already configured on the Docker server should be used, this avoids redeclaring it in each configuration file.