Deep Dive into Cgroups v2 on Linux Systems
🏁 Introduction
Deep Dive into Cgroups v2 on Linux Systems

🏁 Introduction
Cgroups version 2 represents a significant evolution in Linux resource management, providing a unified control interface for managing and limiting resource usage across processes. This article delves into the intricacies of Cgroups v2, exploring its core concepts, practical applications, and advanced configuration options suitable for optimizing performance and resource allocation in modern Linux environments. Cgroups v2 offers a unified and hierarchical approach to managing system resources like CPU, memory, and I/O.
🧠 Core Concepts
Cgroups, short for control groups, provide a mechanism for aggregating processes and managing their resource consumption. The shift to Cgroups v2 brings several architectural improvements, including a simplified hierarchy, enhanced resource isolation, and improved feature discoverability. Understanding these core concepts is critical for leveraging the full potential of Cgroups v2.
The unified hierarchy in Cgroups v2 means that all controllers, also known as resource controllers, are mounted under a single root. This simplifies management and eliminates the complexities of managing multiple hierarchies as was the case in Cgroups v1. Processes are added to the cgroup tree, and their resource usage is then governed by the configuration applied at each level of the hierarchy. Each cgroup can have child cgroups, enabling granular resource allocation and isolation.
Resource controllers are the components that enforce resource limits. Common controllers include cpu for managing CPU usage, memory for managing memory usage, io for controlling disk I/O, and pids for limiting the number of processes. Each controller exposes a set of parameters that can be tuned to meet specific requirements. For example, the cpu.max parameter allows you to specify the maximum CPU time a cgroup can consume within a given period. The memory.max parameter allows you to set a hard limit on the memory a cgroup can use.
The importance of delegation is apparent when considering containers. Cgroups provide the underlying mechanism for resource isolation in container runtimes like Docker and Kubernetes. By placing each container in its own cgroup, resource consumption can be limited, preventing one container from monopolizing system resources and impacting others. This delegation also extends to user-level systemd services, where resource limits can be set at the service level to ensure stability.
A crucial aspect of Cgroups v2 is the absence of the ‘named’ hierarchy. Unlike Cgroups v1, there is no explicit way to create a hierarchy specifically for named cgroups. Instead, all cgroups fall under the unified hierarchy, promoting a more structured and predictable resource management system. In terms of metrics, Cgroups v2 offer more detailed and precise accounting of resource usage. For example, the memory.stat file provides comprehensive information on memory usage, including cache usage, swap usage, and kernel memory usage. The level of detail helps in monitoring and optimizing application performance.
Observability is enhanced through tools like systemd-cgtop, which provides a real-time view of cgroup resource usage. The perf tool can also be used to profile the performance of processes within specific cgroups, providing valuable insights into bottlenecks and optimization opportunities. Performance implications must be considered when configuring cgroups. Setting overly restrictive limits can degrade application performance, while insufficient limits can lead to resource contention. It’s essential to monitor resource usage and adjust limits accordingly. Scalability strategies can be implemented by dynamically adjusting cgroup configurations based on workload demands. For example, Kubernetes can automatically adjust cgroup limits based on pod resource requests and limits.
Security is also a key consideration. Cgroups provide a layer of defense against resource exhaustion attacks. By limiting the resources available to a specific cgroup, it is possible to prevent malicious processes from consuming all available resources and impacting other applications. Compliance requirements may dictate the use of cgroups to ensure fair resource allocation and prevent resource hogging, aligning with broader governance policies.
⚙️ Comprehensive Code Examples
1️⃣ Creating a Basic Cgroup in Cgroups v2
This example demonstrates how to create a basic cgroup and move a process into it. Creating a new cgroup allows for the isolation and resource management of specific processes or applications.
💡 Use Case: Isolating a background process to prevent it from consuming excessive resources, thus ensuring the stability of critical applications.
⚠️ Risk Assessment: Incorrectly configured cgroups can lead to resource starvation or performance degradation for the processes within them.
🚀 Operational Value: Enables resource isolation and prevents resource contention between different applications, improving overall system stability.
#!/bin/bash
# Create a new cgroup named 'my_cgroup'
mkdir /sys/fs/cgroup/my_cgroup
# Get the PID of the current shell
PID=$$
# Add the current shell process to the cgroup
echo $PID > /sys/fs/cgroup/my_cgroup/cgroup.procs
# Verify the process has been added
cat /sys/fs/cgroup/my_cgroup/cgroup.procs
This script creates a new cgroup directory, retrieves the process ID of the current shell, and adds the shell process to the cgroup.procs file within the newly created cgroup. This moves the current shell into the my_cgroup. Error handling is minimal; in a production environment, robust error checking and logging would be essential. This basic setup can be extended to set resource limits using the cgroup controllers. Dependencies include a Linux system with Cgroups v2 enabled. Note that the script must be run with sufficient privileges to create and modify cgroup files. Always run scripts with caution, especially those that modify system configurations.
2️⃣ Limiting CPU Usage with the CPU Controller
This example demonstrates how to use the CPU controller to limit the CPU usage of a cgroup. Limiting CPU usage prevents processes within a cgroup from monopolizing CPU resources.
💡 Use Case: Limiting the CPU usage of a non-critical application to ensure that critical applications have sufficient CPU resources.
⚠️ Risk Assessment: Setting the CPU limit too low can cause performance degradation for the processes within the cgroup.
🚀 Operational Value: Ensures fair CPU allocation and prevents CPU contention, leading to more predictable application performance.
#!/bin/bash
# Create a new cgroup named 'cpu_limited'
mkdir /sys/fs/cgroup/cpu_limited
# Set the CPU limit to 50% of one CPU core
echo "50000 100000" > /sys/fs/cgroup/cpu_limited/cpu.max
# Get the PID of a process you want to limit
PID=$1
# Add the process to the cgroup
echo $PID > /sys/fs/cgroup/cpu_limited/cgroup.procs
echo "CPU limit set for PID: $PID"
This script first creates a new cgroup named cpu_limited. It then sets the cpu.max parameter to “50000 100000”, which means the cgroup is limited to 50% of one CPU core. The script takes a process ID as an argument and adds the specified process to the cgroup. To use this script, one must supply a PID as an argument; otherwise, the PID variable will be empty, and no process will be added. Proper error handling and input validation are important, especially when dealing with process IDs. Cgroups v2 must be enabled for this to function correctly.
3️⃣ Limiting Memory Usage with the Memory Controller
This example showcases how to use the memory controller to limit the memory usage of a cgroup. Setting a memory limit prevents a cgroup from consuming excessive memory.
💡 Use Case: Limiting the memory usage of a memory-intensive application to prevent it from crashing the system due to OOM errors.
⚠️ Risk Assessment: Setting the memory limit too low can cause the application to crash or perform poorly.
🚀 Operational Value: Prevents memory exhaustion and ensures that applications do not consume more memory than they are allocated.
#!/bin/bash
# Create a new cgroup named 'memory_limited'
mkdir /sys/fs/cgroup/memory_limited
# Set the memory limit to 1GB
echo 1073741824 > /sys/fs/cgroup/memory_limited/memory.max
# Get the PID of a process you want to limit
PID=$1
# Add the process to the cgroup
echo $PID > /sys/fs/cgroup/memory_limited/cgroup.procs
echo "Memory limit set for PID: $PID"
This script creates a new cgroup called memory_limited and sets a memory limit of 1GB using the memory.max parameter. It takes a process ID as an argument and adds that process to the cgroup. The script is straightforward, but in a production environment, it would be beneficial to add error handling to check if the cgroup directory already exists and to validate the process ID. Additionally, the script assumes the user knows the correct byte value for 1GB, which can be improved by adding a simple calculation within the script. Requires Cgroups v2 support and appropriate permissions.
4️⃣ Monitoring CPU Usage of a Cgroup
This example demonstrates how to monitor the CPU usage of a cgroup using the cpu.stat file. Monitoring CPU usage provides insights into how much CPU time a cgroup is consuming.
💡 Use Case: Monitoring the CPU usage of a critical application to identify performance bottlenecks or resource contention issues.
⚠️ Risk Assessment: Relying solely on cpu.stat might not provide a complete picture of CPU utilization; consider using more advanced monitoring tools.
🚀 Operational Value: Provides real-time insights into CPU usage, enabling proactive identification and resolution of performance issues.
#!/bin/bash
# The cgroup you want to monitor
CGROUP=$1
# Check if the cgroup exists
if [ ! -d "/sys/fs/cgroup/$CGROUP" ]; then
echo "Cgroup $CGROUP not found"
exit 1
fi
# Read the CPU usage from cpu.stat
cat /sys/fs/cgroup/$CGROUP/cpu.stat
This script takes a cgroup name as an argument and then reads and prints the contents of the cpu.stat file for that cgroup. This file contains various CPU usage statistics, such as the total CPU time consumed by the cgroup. The script includes a check to ensure that the specified cgroup exists before attempting to read the cpu.stat file. For continuous monitoring, this script can be incorporated into a monitoring system, and the output can be parsed to create graphs and alerts.
5️⃣ Limiting the Number of Processes in a Cgroup
This example demonstrates how to limit the number of processes that can run within a cgroup using the pids controller. Limiting the number of processes can prevent fork bombs and other resource exhaustion attacks.
💡 Use Case: Preventing a runaway process from spawning too many child processes and consuming excessive system resources.
⚠️ Risk Assessment: Setting the process limit too low can prevent legitimate applications from running correctly.
🚀 Operational Value: Enhances system stability by preventing resource exhaustion due to excessive process creation.
#!/bin/bash
# Create a new cgroup named 'pids_limited'
mkdir /sys/fs/cgroup/pids_limited
# Set the maximum number of processes to 100
echo 100 > /sys/fs/cgroup/pids_limited/pids.max
# Get the PID of a process you want to limit
PID=$1
# Add the process to the cgroup
echo $PID > /sys/fs/cgroup/pids_limited/cgroup.procs
echo "Process limit set for PID: $PID"
This script creates a cgroup named pids_limited and sets the maximum number of processes allowed in that cgroup to 100 using the pids.max parameter. It then adds a process with a given process ID to the cgroup. Production environments need more robust error handling, particularly around checking the return codes of the echo commands. In cases where the process limit is reached, new processes within the cgroup will fail to start, which requires application-level handling. Requires Cgroups v2 and root privileges.
6️⃣ Setting up a Systemd Service with Cgroup Resource Limits
This example demonstrates how to configure a systemd service with cgroup resource limits. Integrating cgroups with systemd allows for easy management of resource limits for system services.
💡 Use Case: Ensuring that a critical system service has guaranteed CPU and memory resources, preventing it from being affected by other resource-intensive processes.
⚠️ Risk Assessment: Misconfigured systemd service files can lead to service failures or unexpected behavior.
🚀 Operational Value: Provides a standardized way to manage resource limits for system services, improving system stability and predictability.
# /etc/systemd/system/my_service.service
[Unit]
Description=My Service
After=network.target
[Service]
ExecStart=/usr/bin/my_service
Restart=on-failure
CPUAccounting=true
MemoryAccounting=true
CPUQuota=50%
MemoryMax=1G
[Install]
WantedBy=multi-user.target
This systemd service file defines a service named my_service. The CPUAccounting and MemoryAccounting options enable CPU and memory accounting for the service. The CPUQuota option limits the service to 50% of one CPU core, and the MemoryMax option limits the service to 1GB of memory. Systemd automatically creates and manages the cgroup associated with this service. To apply these settings, save the file as /etc/systemd/system/my_service.service, enable the service with systemctl enable my_service, and start it with systemctl start my_service. Observability can be enhanced by using systemctl status my_service to view resource usage statistics.
7️⃣ Creating Nested Cgroups for Granular Resource Control
This example demonstrates how to create nested cgroups for granular resource control. Nested cgroups allow for hierarchical resource allocation and isolation.
💡 Use Case: Allocating resources to different teams or projects within an organization, with each team having its own set of resource limits.
⚠️ Risk Assessment: Managing complex nested cgroup hierarchies can be challenging and requires careful planning.
🚀 Operational Value: Provides fine-grained resource control, enabling efficient allocation and utilization of system resources across different workloads.
#!/bin/bash
# Create a parent cgroup named 'team_a'
mkdir /sys/fs/cgroup/team_a
# Create a child cgroup named 'project_x' under 'team_a'
mkdir /sys/fs/cgroup/team_a/project_x
# Set resource limits for 'project_x'
echo 200000 > /sys/fs/cgroup/team_a/project_x/cpu.max
# Get the PID of a process you want to add to 'project_x'
PID=$1
# Add the process to the cgroup
echo $PID > /sys/fs/cgroup/team_a/project_x/cgroup.procs
echo "Nested cgroup setup complete for PID: $PID"
This script creates a parent cgroup team_a and a child cgroup project_x under team_a. It sets a CPU limit for project_x and adds a process to it. The key benefit of nested cgroups is the ability to apply different resource limits at different levels of the hierarchy, offering greater control over resource allocation. Requires root privileges and Cgroups v2.
8️⃣ Using the I/O Controller to Limit Disk Bandwidth
This example demonstrates how to use the I/O controller to limit disk bandwidth for a cgroup. Limiting disk bandwidth can prevent I/O-intensive processes from impacting other applications.
💡 Use Case: Preventing a backup process from saturating the disk and impacting the performance of other critical applications.
⚠️ Risk Assessment: Setting the I/O limit too low can significantly degrade the performance of the processes within the cgroup.
🚀 Operational Value: Ensures fair I/O allocation and prevents I/O contention, improving overall system responsiveness.
#!/bin/bash
# Create a new cgroup named 'io_limited'
mkdir /sys/fs/cgroup/io_limited
# Determine the major:minor number of the disk
DISK=$(lsblk -n -o MAJ:MIN /dev/sda)
# Set the I/O limit to 20MB/s for reads
echo "$DISK rbps=20000000" > /sys/fs/cgroup/io_limited/io.max
# Get the PID of a process you want to limit
PID=$1
# Add the process to the cgroup
echo $PID > /sys/fs/cgroup/io_limited/cgroup.procs
echo "I/O limit set for PID: $PID"
This script creates a cgroup named io_limited and sets an I/O limit of 20MB/s for reads on the /dev/sda disk. It retrieves the major and minor device numbers of the disk using lsblk. It then adds a process to the cgroup. The lsblk command is used to dynamically determine the disk’s major:minor number, which is required by the I/O controller. Ensure that the specified disk is correct for your system. This script offers a basic example of limiting read bandwidth; similar parameters exist for write bandwidth. Requires root privileges and Cgroups v2.
9️⃣ Monitoring Memory Usage with memory.stat
This example showcases how to monitor the memory usage of a cgroup using the memory.stat file. Gaining insights into memory usage is crucial for optimizing application performance and preventing OOM errors.
💡 Use Case: Tracking the memory usage of a memory-intensive application to identify potential memory leaks or excessive memory consumption.
⚠️ Risk Assessment: Interpreting the memory.stat file requires a good understanding of the different memory metrics and their implications.
🚀 Operational Value: Provides detailed memory usage statistics, enabling proactive identification and resolution of memory-related issues.
#!/bin/bash
# The cgroup you want to monitor
CGROUP=$1
# Check if the cgroup exists
if [ ! -d "/sys/fs/cgroup/$CGROUP" ]; then
echo "Cgroup $CGROUP not found"
exit 1
fi
# Read the memory usage from memory.stat
cat /sys/fs/cgroup/$CGROUP/memory.stat
This script takes a cgroup name as an argument and prints the contents of the memory.stat file for that cgroup. The memory.stat file contains various memory usage statistics, such as the total memory usage, cache usage, and swap usage. This provides a detailed breakdown of memory consumption within the specified cgroup. The script performs a simple check to ensure that the specified cgroup exists. In a real-world monitoring setup, one would typically parse the output of memory.stat and graph the memory usage over time.
🔟 Dynamically Adjusting Cgroup Limits Based on Workload
This example demonstrates how to dynamically adjust cgroup limits based on workload using a simple monitoring loop. Adjusting cgroup limits dynamically allows resources to be allocated based on actual demand.
💡 Use Case: Automatically increasing the memory limit for a cgroup when the application within that cgroup experiences a surge in memory usage.
⚠️ Risk Assessment: Incorrectly configured dynamic adjustment logic can lead to resource oscillation and performance instability.
🚀 Operational Value: Optimizes resource utilization by dynamically allocating resources based on actual workload demands, improving overall system efficiency.
#!/bin/bash
# The cgroup to monitor
CGROUP=$1
# Memory threshold in bytes
THRESHOLD=$2
# Increment value in bytes
INCREMENT=$3
while true; do
# Get current memory usage
USAGE=$(awk '/anon/{print $2}' /sys/fs/cgroup/$CGROUP/memory.stat)
# Get current memory limit
LIMIT=$(cat /sys/fs/cgroup/$CGROUP/memory.max)
# Check if memory usage exceeds the threshold
if [ "$USAGE" -gt "$THRESHOLD" ]; then
NEW_LIMIT=$((LIMIT + INCREMENT))
echo $NEW_LIMIT > /sys/fs/cgroup/$CGROUP/memory.max
echo "Increased memory limit to $NEW_LIMIT for $CGROUP"
fi
# Sleep for a while
sleep 60
done
This script monitors the memory usage of a specified cgroup and dynamically increases the memory limit if the usage exceeds a defined threshold. The script reads the current memory usage from the memory.stat file and compares it to the threshold. If the threshold is exceeded, the script increases the memory limit by a specified increment. This script provides a basic example of dynamic cgroup adjustment. In a production environment, it is important to implement more sophisticated monitoring and adjustment logic to prevent resource oscillation. The script uses awk to extract the anonymous memory usage from memory.stat. The initial memory threshold and increment are passed as arguments. The loop sleeps for 60 seconds between checks. Requires root privileges and Cgroups v2.
🧩 Conclusion
Cgroups v2 provides a powerful and flexible mechanism for managing and controlling resource usage in Linux systems. By understanding the core concepts and practical applications, system administrators and DevOps engineers can optimize resource allocation, improve system stability, and enhance application performance. The transition to Cgroups v2 represents a significant step forward in Linux resource management, offering a unified and hierarchical approach to managing system resources.
메타데이터
- post_id
- 8cf2df50d1ef
- slug
- deep-dive-into-cgroups-v2-on-linux-systems-8cf2df50d1ef
- url
- https://medium.com/@linuxgd/deep-dive-into-cgroups-v2-on-linux-systems-8cf2df50d1ef
- canonical_url
- https://medium.com/@linuxgd/deep-dive-into-cgroups-v2-on-linux-systems-8cf2df50d1ef
- author_url
- https://medium.com/@linuxgd
- status
- ok
- fetched_at
- 2026-08-18 06:32:24