Virtual Networking: From Basics to Docker and Beyond

vikash kumarvikash kumar
11 min read

Hey , fellow tech enthusiasts!

If you're diving into the world of Kubernetes, you probably know that networking is a crucial component. But what if you're not quite familiar with the nuts and bolts of networks? Don't worry! This guide is here to help you build a solid foundation in virtual networking, which will be essential for our upcoming article on Kubernetes networking.

If you've been following along, you might remember our deep dive into Linux networking in the previous article. If you haven't checked it out yet, I highly recommend giving it a read here. It lays down the foundational concepts that we'll be building upon in this article.

In this article, we'll walk through the process of creating a virtual network using Linux commands. We'll do this step-by-step, in a conversational style, so it's easy to follow along. Let's get started!

Why Virtual Networks?

Before we jump into the commands, let's understand why we need virtual networks. In the world of containers and Kubernetes, networking allows containers to communicate with each other, with services, and with the outside world. Virtual networks simulate this environment, making it easier to test and understand network configurations without affecting your actual network setup.

Step-by-Step Guide to Creating a Virtual Network

Step 1: Setting Up Virtual Ethernet (veth) Pairs

Virtual Ethernet pairs (veth pairs) are like two connected network cables. These are also referred to as virtual interfaces. Whatever you send through one end comes out the other. Let's create a veth pair:

sudo ip link add veth-red type veth peer name veth-blue

This command creates two virtual interfaces: veth-red and veth-blue. Think of them as two ends of a virtual cable.

Common Error: If you encounter a "Permission denied" error, ensure you're running the command with sudo privileges.

Step 2: Creating Network Namespaces

Network namespaces are isolated network environments within a single host. They provide isolation, ensuring that changes in one namespace do not affect others. This is particularly useful in multi-tenant environments or when you want to test different network configurations without interfering with each other.

Let's create two namespaces:

sudo ip netns add red
sudo ip netns add blue

Troubleshooting Tip: If you get an error saying the namespace already exists, you can delete it first using sudo ip netns del <namespace_name> and then recreate it.

Step 3: Assigning veth Pairs to Namespaces

Now, we assign each end of the veth pair to a namespace:

sudo ip link set veth-red netns red
sudo ip link set veth-blue netns blue

This step connects our virtual interfaces to their respective network namespaces, allowing isolated network environments.

Error Handling: If you get "Cannot find device" error, make sure you've created the veth pairs and namespaces correctly in the previous steps.

Step 4: Assigning IP Addresses

Next, we'll assign IP addresses to the virtual interfaces within their respective namespaces:

sudo ip netns exec red ip addr add 192.168.15.1/24 dev veth-red
sudo ip netns exec blue ip addr add 192.168.15.2/24 dev veth-blue

These commands assign IP addresses to our virtual interfaces, allowing them to communicate using IP protocol. The /24 in the IP address is the subnet mask, which defines the network and host portions of the IP address.

Common Mistake: Ensure you're using different IP addresses for each namespace to avoid conflicts.

Step 5: Bringing Up the Interfaces

Just like physical network interfaces, we need to bring these virtual interfaces up:

sudo ip netns exec red ip link set veth-red up
sudo ip netns exec blue ip link set veth-blue up

This step activates our virtual interfaces, making them ready for communication.

Troubleshooting: If the interfaces don't come up, check for any error messages in the system logs (the dmesg command can be helpful).

Step 6: Testing the Connection

Finally, let's test the connection between the two namespaces. We'll use the ping command to check if red can reach blue:

sudo ip netns exec red ping 192.168.15.2

If everything is set up correctly, you should see successful ping responses.

Error Handling:

  • If ping fails, ensure that:

    1. IP addresses are correctly assigned

    2. Interfaces are up

    3. There are no firewall rules blocking the traffic

Congratulations! You've just created and tested a virtual network.

Step 7: Checking ARP Tables

Before we move forward, let's understand how network namespaces know each other through ARP (Address Resolution Protocol). When you ping 192.168.15.2 from the red namespace, it sends an ARP request to resolve the IP address to a MAC address. Let's check the ARP tables:

In the red namespace:

sudo ip netns exec red arp -n

In the blue namespace:

sudo ip netns exec blue arp -n

You'll notice that each namespace knows the other, but if you check the ARP table on the host, it doesn't have any entry for these virtual networks:

arp -n

This is because the host doesn't interact directly with the virtual networks within the namespaces.

Enabling Host-to-Virtual Network Communication

What if our host wants to communicate with a virtual network? The host uses virtual interfaces to interact with the namespaces. Here's how you can achieve this:

  1. Create a veth pair connecting the host and the namespace.

  2. Assign one end of the veth pair to the host.

  3. Assign an IP address to the host-side veth interface.

  4. Add routing rules to enable communication.

For example:

sudo ip link add veth-host type veth peer name veth-ns
sudo ip link set veth-ns netns red
sudo ip addr add 192.168.15.10/24 dev veth-host
sudo ip link set veth-host up
sudo ip netns exec red ip addr add 192.168.15.1/24 dev veth-ns
sudo ip netns exec red ip link set veth-ns up

Now, the host can ping the namespace:

ping 192.168.15.1

Troubleshooting: If ping fails, check your routing table and ensure there are no conflicting routes.

Facilitating Namespace Container-to-Server Communication

If a container (or namespace) needs to communicate with an external server, it will use the host interface as a gateway. This requires setting up appropriate routing and NAT (Network Address Translation) rules:

  1. Enable IP forwarding on the host:
sudo sysctl -w net.ipv4.ip_forward=1
  1. Set up NAT rules using iptables:
sudo iptables -t nat -A POSTROUTING -s 192.168.15.0/24 -o eth0 -j MASQUERADE

Here, eth0 is the host's network interface connected to the external network. This setup allows containers to communicate with external servers.

Common Error: If iptables command fails, ensure you have iptables installed and you're running the command with sudo privileges.

Configuring External Network Access to Containers

For external networks to access containers, we need to set up port forwarding on the host. For example, to forward port 8080 on the host to port 80 in the container:

sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.15.1:80
sudo iptables -A FORWARD -p tcp -d 192.168.15.1 --dport 80 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

This configuration allows external clients to access the container's service running on port 80 via port 8080 on the host.

Troubleshooting Tip: If port forwarding doesn't work, check your firewall settings and ensure the service in the container is actually running and listening on the specified port.

Connecting Multiple Namespaces with a Bridge

In real-world scenarios, we often need to connect multiple namespaces so they can communicate as if they were connected by a switch. We use a Linux bridge to achieve this. A Linux bridge is a virtual network device that behaves like a network switch. Let's see how to set it up:

Step 8: Creating Network Namespaces Again

Recreate the namespaces:

sudo ip netns add red
sudo ip netns add blue

Step 9: Setting Up veth Pairs for the Bridge

Create new veth pairs and assign them to the namespaces:

sudo ip link add veth-red type veth peer name veth-red-br
sudo ip link add veth-blue type veth peer name veth-blue-br

sudo ip link set veth-red netns red
sudo ip link set veth-blue netns blue

Step 10: Creating a Bridge

Create a bridge interface:

sudo ip link add name v-net-0 type bridge
sudo ip link set v-net-0 up

Step 11: Adding veth Pairs to the Bridge

Assign the bridge interfaces to the bridge:

sudo ip link set veth-red-br master v-net-0
sudo ip link set veth-blue-br master v-net-0
sudo ip link set veth-red-br up
sudo ip link set veth-blue-br up

Step 12: Assigning IP Addresses and Bringing Up the Interfaces

Assign IP addresses to the veth interfaces and bring them up:

sudo ip netns exec red ip addr add 192.168.15.1/24 dev veth-red
sudo ip netns exec blue ip addr add 192.168.15.2/24 dev veth-blue

sudo ip netns exec red ip link set veth-red up
sudo ip netns exec blue ip link set veth-blue up

Now, the red and blue namespaces are connected through a virtual switch (v-net-0), and they can communicate with each other.

Step 13: Testing the Bridge

Let's test the bridge by pinging from one namespace to another:

sudo ip netns exec red ping 192.168.15.2

If you see successful ping responses, it means the bridge is working, and the namespaces can communicate through it.

Error Handling: If ping fails, check that all interfaces are up and IP addresses are correctly assigned. Also, ensure the bridge is properly configured and up.

Relating to Docker Networking

Now that we've gone through the steps of creating a virtual network manually, let's connect these steps to how Docker manages networking. Docker simplifies the process we did manually by automating these steps behind the scenes:

  1. Create Network Namespace: When you run a Docker container, it creates a separate network namespace for the container.

  2. Create Bridge Network/Interface: Docker creates a default bridge network (docker0) if not specified otherwise.

  3. Create VETH Pairs: Docker creates veth pairs to connect the container's network namespace with the host or bridge.

  4. Attach vEth to Namespace: Docker attaches one end of the veth pair to the container's network namespace.

  5. Attach Other vEth to Bridge: Docker attaches the other end of the veth pair to the bridge network (docker0).

  6. Assign IP Addresses: Docker assigns IP addresses to the container interfaces.

  7. Bring the interfaces up: Docker ensures that all interfaces are brought up.

  8. Enable NAT – IP Masquerade: Docker sets up NAT rules to allow containers to communicate with the external network through the host.

Docker abstracts these complexities, making container networking straightforward and user-friendly. Here's a comparison of the manual steps we performed and Docker's automated process:

Manual StepDocker Equivalent
Create Network NamespaceAutomatically created when starting a container
Create Bridge Network/Interfacedocker0 bridge created by default
Create VETH PairsVeth pairs created for container-host communication
Attach vEth to NamespaceOne end of veth attached to the container's namespace
Attach Other vEth to BridgeOther end of veth attached to the bridge (docker0)
Assign IP AddressesIP addresses assigned automatically
Bring the interfaces upInterfaces are brought up automatically
Enable NAT – IP MasqueradeNAT rules set up by Docker for external network access

Host-to-Virtual Network Communication in Docker

When you want the host to communicate with a Docker container, Docker simplifies this through the bridge network. The host can interact with the container's IP address assigned by Docker:

docker run -d --name my-container nginx

Docker assigns an IP address to my-container which can be accessed directly from the host:

docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-container
ping <container_ip>

Namespace Container-to-Server Communication via Host Interface

In Docker, containers can communicate with external servers using the host's network interface because Docker sets up appropriate NAT rules. For example, a container can reach external servers without additional configuration:

docker run -it ubuntu bash
apt-get update

The apt-get update command accesses external servers seamlessly.

Host Port Forwarding for External Network Access

Docker allows external networks to access container services through port forwarding. For example, to access a web service running in a container, you can map the container's port to a host port:

docker run -d -p 8080:80 nginx

This command maps port 80 in the container to port 8080 on the host. You can now access the nginx service via http://<host_ip>:8080.

What's Next?

In this guide, we've covered the basics of creating virtual networks using Linux commands and related these concepts to Docker's networking model. We've explored:

  1. Creating and connecting virtual network interfaces

  2. Setting up network namespaces for isolation

  3. Establishing communication between namespaces

  4. Enabling host-to-virtual network communication

  5. Facilitating container-to-external server communication

  6. Setting up port forwarding for external access to containers

  7. Using bridges to connect multiple namespaces

  8. Relating these concepts to Docker's networking model

These foundational skills are crucial for understanding Kubernetes networking, where similar concepts are applied to manage container communication on a larger scale. In our next article, we'll dive deeper into Kubernetes networking, building upon the knowledge we've gained here.

Some topics we'll explore in the Kubernetes networking article include:

  • Kubernetes network model and its requirements

  • Pod networking and how it relates to the concepts we've learned

  • Services in Kubernetes and how they enable communication between pods

  • Network policies for controlling traffic flow

  • Ingress controllers for managing external access to services

  • CNI (Container Network Interface) plugins and their role in Kubernetes networking

By mastering these networking fundamentals, you'll be well-prepared to tackle more complex networking scenarios in Kubernetes. The concepts we've covered here - like namespaces, virtual interfaces, bridges, and NAT - all play crucial roles in how Kubernetes manages networking at scale.

Stay tuned for our next article, where we'll unravel the intricacies of Kubernetes networking and see how these foundational concepts are applied in a distributed container orchestration environment. Happy networking!

Further Reading

For those who want to dive deeper into the topics covered in this article, here are some valuable resources:

  1. Linux Networking Documentation

  2. Docker Networking Overview

  3. Introduction to Linux Virtual Interfaces

  4. Kubernetes Networking

  5. Container Network Interface (CNI) Specification

These resources will provide you with more in-depth information about the concepts we've discussed and prepare you for more advanced networking topics in containerized environments.

0
Subscribe to my newsletter

Read articles from vikash kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

vikash kumar
vikash kumar

Hey folks! 👋 I'm Vikash Kumar, a seasoned DevOps Engineer navigating the thrilling landscapes of DevOps and Cloud ☁️. My passion? Simplifying and automating processes to enhance our tech experiences. By day, I'm a Terraform wizard; by night, a Kubernetes aficionado crafting ingenious solutions with the latest DevOps methodologies 🚀. From troubleshooting deployment snags to orchestrating seamless CI/CD pipelines, I've got your back. Fluent in scripts and infrastructure as code. With AWS ☁️ expertise, I'm your go-to guide in the cloud. And when it comes to monitoring and observability 📊, Prometheus and Grafana are my trusty allies. In the realm of source code management, I'm at ease with GitLab, Bitbucket, and Git. Eager to stay ahead of the curve 📚, I'm committed to exploring the ever-evolving domains of DevOps and Cloud. Let's connect and embark on this journey together! Drop me a line at thenameisvikash@gmail.com.