My first encounter with a container was when I performed load testing on an application using JMeter. So, rather than installing JMeter on multiple Virtual Machines (VMs), I ended up deploying them on multiple containers on a single VM. I still remember that I was curious to understand how a container can manage to keep applications isolated. I was interested in understanding the networking part specifically. When I searched, a lot of terms were coined around. Like veth, bridges, Linux Namespaces, and cgroups. I had a lot of queries in my mind too. How does a network packet traverse from Host to container and vice-versa? How do containers maintain separate network space for themselves? Post installing docker, I see docker0 device in ip a command output. What is its use? Post creating a container, I see eth0@if5 device in the container, whereas veth6e6a37e@if4 device is on the Host. Are they related to docker0 device? And many more… After a lot of readings (yes, it took me some time), I understood a few of the stuff that I would like to share in this blog series. I assume the reader has a basic understanding of Linux, Virtualization, and Containerization on a high level. Topics to Cover I have broken down this blog post into the following parts Part One: Virtual Ethernet Part Two: Network Namespaces and Network Bridges Part Three: Container (docker) Networking Setup I am going to use Vagrant VM on the Ubuntu host with Oracle VirtualBox v7.0. The biggest advantage of using Vagrant VM is it provides a clean slate to play with. One can destroy, create, duplicate, and share it very easily. Here is the Vagrant File: cat <<EOF >> Vagrantfile # -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "ubuntu/jammy64" config.vm.box_version = "20241002.0.0" config.vm.synced_folder "./shared-with-vm", "/shared-with-host" config.vm.hostname = "cnd" # Container Networking Demo config.vm.provider "virtualbox" do |vb| # Display the VirtualBox GUI when booting the machine # vb.gui = true # Customize the amount of memory on the VM: vb.memory = "2048" vb.cpus = 2 vb.name = "Container Networking Demo" end end EOF Create a directoryshared-with-vm in the same location where Vagrantfile resides. This helps to share the data between the host and the VM. mkdir shared-with-vm Start the VM, and log into it. vagrant up vagrant ssh Install a few utilities. agrant@cnd:~$ sudo apt update vagrant@cnd:~$ sudo apt install -y net-tools vim curl git tree traceroute make dos2unix bind9-dnsutils tshark ethtool python3 python3-pip python3-scapy iputils-ping iproute2 # Note: you may need to restart few services. Do as it pops up vagrant@cnd:~$ systemctl restart networkd-dispatcher.service unattended-upgrades.service Last thing (optional, just to advertise my older blog post 😛), you can set the aliases. I do it this way. agrant@cnd:~$ wget https://raw.githubusercontent.com/simplyatul/bin/master/setaliases.sh vagrant@cnd:~$ source setaliases.sh All set, let us jump to Part One. My first encounter with a container was when I performed load testing on an application using JMeter . So, rather than installing JMeter on multiple Virtual Machines (VMs), I ended up deploying them on multiple containers on a single VM. JMeter JMeter I still remember that I was curious to understand how a container can manage to keep applications isolated. I was interested in understanding the networking part specifically. When I searched, a lot of terms were coined around. Like veth , bridges , Linux Namespaces , and cgroups . I had a lot of queries in my mind too. veth bridges Linux Namespaces cgroups How does a network packet traverse from Host to container and vice-versa? How do containers maintain separate network space for themselves? Post installing docker, I see docker0 device in ip a command output. What is its use? Post creating a container, I see eth0@if5 device in the container, whereas veth6e6a37e@if4 device is on the Host. Are they related to docker0 device? And many more… How does a network packet traverse from Host to container and vice-versa? How do containers maintain separate network space for themselves? Post installing docker, I see docker0 device in ip a command output. What is its use? docker0 ip a Post creating a container, I see eth0@if5 device in the container, whereas veth6e6a37e@if4 device is on the Host. Are they related to docker0 device? eth0@if5 veth6e6a37e@if4 docker0 And many more… After a lot of readings (yes, it took me some time), I understood a few of the stuff that I would like to share in this blog series. I assume the reader has a basic understanding of Linux, Virtualization, and Containerization on a high level. Topics to Cover I have broken down this blog post into the following parts Part One: Virtual Ethernet Part Two: Network Namespaces and Network Bridges Part Three: Container (docker) Networking Part One : Virtual Ethernet Part One Part Two : Network Namespaces and Network Bridges Part Two Part Three : Container (docker) Networking Part Three Setup I am going to use Vagrant VM on the Ubuntu host with Oracle VirtualBox v7.0. The biggest advantage of using Vagrant VM is it provides a clean slate to play with. One can destroy, create, duplicate, and share it very easily. Oracle VirtualBox Here is the Vagrant File: cat <<EOF >> Vagrantfile # -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "ubuntu/jammy64" config.vm.box_version = "20241002.0.0" config.vm.synced_folder "./shared-with-vm", "/shared-with-host" config.vm.hostname = "cnd" # Container Networking Demo config.vm.provider "virtualbox" do |vb| # Display the VirtualBox GUI when booting the machine # vb.gui = true # Customize the amount of memory on the VM: vb.memory = "2048" vb.cpus = 2 vb.name = "Container Networking Demo" end end EOF cat <<EOF >> Vagrantfile # -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "ubuntu/jammy64" config.vm.box_version = "20241002.0.0" config.vm.synced_folder "./shared-with-vm", "/shared-with-host" config.vm.hostname = "cnd" # Container Networking Demo config.vm.provider "virtualbox" do |vb| # Display the VirtualBox GUI when booting the machine # vb.gui = true # Customize the amount of memory on the VM: vb.memory = "2048" vb.cpus = 2 vb.name = "Container Networking Demo" end end EOF Create a directory shared-with-vm in the same location where Vagrantfile resides. This helps to share the data between the host and the VM. shared-with-vm mkdir shared-with-vm mkdir shared-with-vm Start the VM, and log into it. vagrant up vagrant ssh vagrant up vagrant ssh Install a few utilities. agrant@cnd:~$ sudo apt update vagrant@cnd:~$ sudo apt install -y net-tools vim curl git tree traceroute make dos2unix bind9-dnsutils tshark ethtool python3 python3-pip python3-scapy iputils-ping iproute2 # Note: you may need to restart few services. Do as it pops up vagrant@cnd:~$ systemctl restart networkd-dispatcher.service unattended-upgrades.service agrant@cnd:~$ sudo apt update vagrant@cnd:~$ sudo apt install -y net-tools vim curl git tree traceroute make dos2unix bind9-dnsutils tshark ethtool python3 python3-pip python3-scapy iputils-ping iproute2 # Note: you may need to restart few services. Do as it pops up vagrant@cnd:~$ systemctl restart networkd-dispatcher.service unattended-upgrades.service Last thing (optional, just to advertise my older blog post 😛), you can set the aliases. I do it this way . way agrant@cnd:~$ wget https://raw.githubusercontent.com/simplyatul/bin/master/setaliases.sh vagrant@cnd:~$ source setaliases.sh agrant@cnd:~$ wget https://raw.githubusercontent.com/simplyatul/bin/master/setaliases.sh vagrant@cnd:~$ source setaliases.sh All set, let us jump to Part One . Part One