Hands on – Docker Networking and Namespaces
In addition to my theoretical post on Container Networking – Docker & Kubernetes, the following hands-on series examines Linux Namespaces and Docker Networking.
The advent of Docker makes is easy to isolate Linux process so they don’t interfere with one another. As a result, users can run a range of different applications and dependencies on a single Linux machine, all sharing the same Linux kernel. This type of abstraction is made possible by the use of Linux Namespaces.
There are 6 namespaces implemented in the Linux kernel. The following diagram displays per process isolation – IPC, MNT, NET, PID, USER, and UTS. The number on the right in the square brackets is the unique proc inode number of each namespace. In order to implement namespaces in the Linux kernel, a structure called nsproxy was added. As the name suggests, it’s a namespace proxy. To support namespace, we have a number of userspace packages – util-linux, iproute2, ethtool and wireless iw. This hands-on series we will focus on iproute2 userspace allowing management of the network namespace (NET) with the IP NETNS and IP LINK commands.
Docker, which is essentially a namespacing tool, has the ability to isolate processes into small containers. Containers are different to VMs that emulate a hardware layer on top of the operating system. They use features of the operating system, such as namespaces, to provide similar isolation without emulating the hardware layer. Each namespace has an individual and isolated view allowing the sharing of the same host but with individual routing tables and interfaces.
Users may create namespaces, assign ports, and connect for external connectivity. A virtual interface type known as virtual Ethernet (veth) interfaces are assigned to namespaces. They act as pairs and have the similar analogy of an isolated tube – what comes in one end must go back out the other end. The pairing enables namespace connectivity. Users may also connect namespaces using Open vSwitch. The following screenshot displays the creation of namespace called NAMESPACE, a veth pair, and adding a veth interface to the newly created namespace. As discussed, the IP NET and IP LINK commands enable interaction with the network namespace.
The following screenshot displays IP specific parameters for the previously created namespace. The routing table will only show specific namespace parameters and not information from other namespaces. The following ip route list command does not display the 192.168.1.1/24 interface assigned to the NAMESPACE-A. This is because the ip route list command is looking into the global namespace and not the routing table assigned to the new namespace. The command will show different route table entries including different default gateways for each namespace.
When you install Docker, it creates three networks that can be viewed by issuing the docker network ls command: bridge, host, and null. Running containers with specific –net flag highlight the network you want to run the container in. The “none” flag puts the container is no network, so it’s completely isolated. The “host” flag puts the container in the host’s network. Leaving the defaults places the container into the bridge default network. The default docker bridge is what you will probably use most of the time. Any containers connected to the default bridge can communicate freely, it’s like a flat VLAN. The following displays the networks created and any containers attached. Currently no containers are attached.
The image below displays the initiation of the default ubuntu image pulled from the Docker public registry. There are plenty of images up there that are free to pull down. As you can see, Docker automatically creates a subnet and a gateway. The docker run command starts the container in the default network. With this setup, if you don’t use crtl+p + ctrl +q to exit the container, it will stop running. Running containers are viewed with the docker ps command and users can connect to a container with the docker attach command.
Communication between containers can be restricted with IPTables. The Linux kernel uses different IPtables according to the protocol in use:
IPtables for IPv4 – net/ipv4/netfliter/ip_tables.c
IP6table for IPv6 -net/ipv6/netfliter/ip6_tables.c
arptables for ARP -net/ipv4/netfliter/arp_tables.c
ebtables for Ethernet – net/bridge/netfilter/ebtables.c
They are essentially a Linux firewall in front of the netfliter, providing a management layer for adding and deleting netfliter rules and displaying statistics. The netfilter performs various operations on packets traversing the network stack. Check the FORWARD chain, it either has a default policy of ACCEPT or DROP. All packets reach this hook point after a lookup in the routing system. The following screenshot shows permit all sources the container. If you want to narrow this down, you could restrict only source IP 18.104.22.168 access to the containers with the following command – iptables -I DOCKER -i ext_if ! -s 22.214.171.124 -j DROP
In addition, to the default networks creating during Docker installation users may create user-defined networks. User defined networks come in two forms – Bridge and Overlay network. Bridge network support single host connectivity and containers connected to an overlay network may reside on multiple hosts. The user defined bridge network is similar to the docker0 bridge. An overlay network allows containers to span multiple hosts, enabling multi-host connectivity model. It has some prerequisites such as a valid data store.