Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

How to simulate network latency in local containers

May 26, 2025
Balazs Szeti
Related topics:
ContainersDeveloper Productivity
Related products:
Podman Desktop

Share:

As a developer, it can be challenging to test certain real world use cases and verify how our application behaves in case of network connectivity or performance problems. With limited resources and permissions sometimes we can't reproduce issues that we face in QA or production environments, which makes debugging and fixing them cumbersome. In this post, we'll take a look at how to use containers locally to simulate the impact of network latency on a distributed database cluster.

Generally, it's a good idea to use containers in a local environment—the developer’s inner loop, shown in Figure 1—to test how the application works in a production-like environment in certain situations (for example, limited resource availability or network issues).

Developer experience inner/outer loop
Figure 1: Developer experience overview. The inner loop is the rapid, iterative cycle of coding, building, running, testing, and debugging code on a local environment before sharing it.

If you have a Linux host, you can use Podman directly to spin up containers. On Mac or Windows, you'll need Podman Desktop to creates a Linux virtual machine (VM) under the hood to run the containers.

Before trying the following commands, read the Prepare Podman host section for guidance on how to prepare the host to load the required kernel module.

Add delay to an interface

Use Linux traffic control (tc) and NetEm to add delays or simulate other network issues on an interface. The tc operations require the NET_ADMIN capability to be added to the container when it's created (otherwise getting RTNETLINK answers: Operation not permitted). See details about using NetEm.

Install tc

Install the tc tool within the container. We can build a whole new image with a Containerfile or simply add the installation steps to the container's entry point if its user is root or it can sudo like this:

On a Fedora or Red Hat Enterprise Linux-based image:

dnf update -y && dnf install -y iproute-tc

On a Debian-based image:

apt update && apt-get install -y iproute2

Use tc

A container running locally usually has two interfaces: lo and eth0.

Add a delay to the lo interface to have an impact on a port published to the host. Run as root inside the container:

tc qdisc add dev lo root netem delay 50ms

Use interface eth0 to add delay between containers attached to the same internal network:

tc qdisc add dev eth0 root netem delay 50ms

Additional commands

Check status for all interfaces:

tc qdisc show

Remove set delay:

tc qdisc del dev lo root

Try with PostgreSQL

Start the container with published database port:

podman run -d --name mypostgres --cap-add NET_ADMIN -p 5432:5432 -e POSTGRES_PASSWORD=secret docker.io/library/postgres:17.4

Check that a SELECT is quick (less than 1 millisecond) by default. We enabled \timing, so psql logs the execution time.

If you have psql installed on your laptop:

PGPASSWORD=secret psql -h localhost -p 5432 -U postgres  postgres -c "\timing" -c "SELECT 1"

Or use psql within the container:

podman exec -it mypostgres sh -c 'psql -h 127.0.0.1 -p 5432 -U postgres postgres -c "\timing" -c "SELECT 1"'

Let's install tc and add delay to the lo interface:

podman exec -it mypostgres sh -c 'apt update && apt-get install -y iproute2 && tc qdisc add dev lo root netem delay 50ms'

Run SELECT 1 again. It should report ~100 millisecond execution time because of the added network delay.

Try 2 containers on the same network

Run a container with a 50-millisecond delay on eth0 and ping it from another container on the same internal network:

#Create container network
podman network create mynetwork
# Start container on custom network
podman run -d --name fedora --net mynetwork --cap-add NET_ADMIN fedora:42 sh -c 'dnf install -y iproute-tc && tc qdisc add dev eth0 root netem delay 50ms && sleep infinity'
# Ping from another container
podman run --rm -it --name ping --net mynetwork fedora:42 sh -c 'dnf install iputils -y && ping fedora'

Expect to see the added ~50 millisecond ping time.

Try a whole YugabyteDB cluster

YugabyteDB is a distributed PostgreSQL-compatible database. See steps in this script how to create a whole db cluster in containers simulating a five node database distributed in two different regions/datacenters with network latency in between:

  • Region-A has db-node1-2. Region-B has db-node3-5 with network latency.
  • Ports of db-node1 are published to host, to connect with psql or a test application.
  • SELECT is quick as there is no latency set for db-node1.
  • INSERT is slow because we enforced replication to all 5 nodes including the ones "in the other region."

Original use case

Here is a quick note about a real-world problem we managed to replicate and resolve using local containers as explained in the previous section. We saw significant performance degradation with a Spring Boot application caused by longer than expected execution time for inserting hundreds of rows in a database.

Creating a YugabyteDB cluster with network delays matching the production environment in containers made it possible to do an in depth analysis and debugging on our local laptops. The tools available in inner loop accelerated investigation and resulted in a short feedback loop for developers trying different approaches to fix the root cause of a problem.

In this special case, we found that enabling batch inserts was not enough to achieve performance improvement due to the distributed nature of the database, but we had to add reWriteBatchedInserts=true in our postgresql JDBC connection string to merge INSERT statements.

Using a Pod instead of a single container

If you can't install the tc tool directly in the main container (for example, if you're using Red Hat Universal Base Image without a subscription attached), you can run the tc command in another container attached to the same container network namespace.

Podman supports the concept of Pods for such purposes, similar to Kubernetes. Containers in the same Pod share the same network interface, so the network delay set in one container has an impact on the whole Pod.

For example, add latency to a published port:

# Create a Pod with a published port
podman pod create -p 5432:5432 mypod
# Run a temporary container in the Pod having the "tc" tool
podman run --pod mypod -it --rm --cap-add NET_ADMIN fedora:42 sh -c 'dnf install -y iproute-tc && tc qdisc add dev lo root netem delay 50ms'
# Run the main container in the Pod
podman run --pod mypod -d -e POSTGRES_PASSWORD=secret postgres:17.4
# Verify increased query time with "psql"
PGPASSWORD=secret psql -h localhost -p 5432 -U postgres postgres -c "\timing" -c "SELECT 1"

Similarly, increase ping time between containers:

# Create a Pod attached to a network
podman pod create --network mynetwork mypod
# Run a temporary container in the Pod having the "tc" tool
podman run --pod mypod -it --rm --cap-add NET_ADMIN fedora:42 sh -c 'dnf install -y iproute-tc && tc qdisc add dev eth0 root netem delay 50ms'
# Run the main container in the Pod
podman run --pod mypod -d redhat/ubi9 sh -c 'sleep infinity'
# Hostname to ping is the Pod's name in this case
podman run --rm -it --name ping --net mynetwork fedora:42 sh -c 'dnf install iputils -y && ping mypod'

Prepare Podman host

The preceding tc qdisc commands require the sch_netem Network Emulator kernel module to add delay to network interfaces. It's common to run into the error Specified qdisc not found if this kernel module is not available on your host. As the kernel is shared between containers, you need to enable the kernel module on your Linux host or within the Linux VM on Mac or Windows.

On Windows, you need to use Podman with Hyper-V backend instead of Windows Subsystem for Linux (WSL2). Make sure that Hyper-V is enabled on your machine and select Hyper-V as the virtualization provider during installation. You need local admin permissions.

The Linux VM machine used by Podman Desktop is based on Fedora CoreOS. See available images and repo for details. Currently image v5.3 is used by default, but you can enforce a specific version as follows:

podman machine init --image docker://quay.io/podman/machine-os:5.5

To enable the sch_netem kernel module, get a shell inside the VM:

podman machine ssh

This command will drop an error if the required module is not installed yet:

sudo modprobe sch_netem

Install the missing kernel module:

sudo rpm-ostree install kernel-modules-extra

Remove the default config blocking auto-load for this kernel module (this is a dangerous module, if you think about it):

sudo rm /etc/modprobe.d/sch_netem-blacklist.conf

Enable loading kernel module on startup:

sudo sh -c 'echo sch_netem >/etc/modules-load.d/sch_netem.conf'

Exit from the VM, then restart the machine:

podman machine stop && podman machine start

The sch_netem kernel module should be loaded now in the VM:

podman machine ssh lsmod | grep sch_netem

If you work directly on a Linux host, you need to run similar commands based on your Linux distribution to enable the sch_netem kernel module. It’s better to avoid auto-load and just activate the module with modprobe sch_netem whenever it’s needed.

Conclusion

“Shift left” is a software development approach that encourages testing and detecting performance or security problems in the earlier phases of the development life cycle. Using containers in inner loop developer experience with tools like Podman Desktop helps you test complex architectures and simulate use cases that you might run into later in a production environment.

Related Posts

  • Introducing image mode for RHEL and bootable containers in Podman Desktop

  • A quick look at large language models with Node.js, Podman Desktop, and the Granite model

  • How to install and use Podman Desktop on Windows

  • Working with Kubernetes in Podman Desktop

  • Experiment and test AI models with Podman AI Lab

  • Develop SQL Server databases on RHEL with Podman Desktop

Recent Posts

  • How to run AI models in cloud development environments

  • How Trilio secures OpenShift virtual machines and containers

  • How to implement observability with Node.js and Llama Stack

  • How to encrypt RHEL images for Azure confidential VMs

  • How to manage RHEL virtual machines with Podman Desktop

What’s up next?

This learning path demonstrates how you can go from an initial application to a container to a fully running pod on Kubernetes using Podman Desktop and the no-cost Developer Sandbox for Red Hat OpenShift.

Start the activity
Red Hat Developers logo LinkedIn YouTube Twitter Facebook

Products

  • Red Hat Enterprise Linux
  • Red Hat OpenShift
  • Red Hat Ansible Automation Platform

Build

  • Developer Sandbox
  • Developer Tools
  • Interactive Tutorials
  • API Catalog

Quicklinks

  • Learning Resources
  • E-books
  • Cheat Sheets
  • Blog
  • Events
  • Newsletter

Communicate

  • About us
  • Contact sales
  • Find a partner
  • Report a website issue
  • Site Status Dashboard
  • Report a security problem

RED HAT DEVELOPER

Build here. Go anywhere.

We serve the builders. The problem solvers who create careers with code.

Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

Sign me up

Red Hat legal and privacy links

  • About Red Hat
  • Jobs
  • Events
  • Locations
  • Contact Red Hat
  • Red Hat Blog
  • Inclusion at Red Hat
  • Cool Stuff Store
  • Red Hat Summit

Red Hat legal and privacy links

  • Privacy statement
  • Terms of use
  • All policies and guidelines
  • Digital accessibility

Report a website issue