Topic Overview
Containers vs VMs (Namespaces, Cgroups)
Compare containers and VMs: namespaces, cgroups, and virtualization technologies. Understand isolation, resource management, and when to use each.
Virtual Machines (VMs)
VM runs a complete operating system on virtualized hardware.
VM Architecture
Host OS
└─ Hypervisor (Virtualization Layer)
├─ VM 1 (Guest OS + Apps)
├─ VM 2 (Guest OS + Apps)
└─ VM 3 (Guest OS + Apps)
Characteristics:
- Full OS: Each VM has its own OS
- Hardware virtualization: Virtual CPU, RAM, disk
- Strong isolation: Complete separation
- Heavy: More resources, slower startup
Containers
Container shares the host OS kernel, isolated by namespaces and cgroups.
Container Architecture
Host OS (Linux Kernel)
├─ Container 1 (isolated by namespaces/cgroups)
├─ Container 2 (isolated by namespaces/cgroups)
└─ Container 3 (isolated by namespaces/cgroups)
Characteristics:
- Shared kernel: All containers share host OS kernel
- OS-level virtualization: Namespaces, cgroups
- Lightweight: Less resources, faster startup
- Less isolation: Share kernel (security consideration)
Linux Namespaces
Namespaces provide isolation for different system resources.
Namespace Types
1. PID Namespace
Isolates process IDs
Container sees only its own processes
2. Network Namespace
Isolated network stack
Own network interfaces, routing tables
3. Mount Namespace
Isolated file system mounts
Own root filesystem
4. UTS Namespace
Isolated hostname, domain name
5. IPC Namespace
Isolated inter-process communication
6. User Namespace
Isolated user IDs
Cgroups (Control Groups)
Cgroups limit and account for resource usage.
Cgroup Features
Resource limits:
- CPU: Limit CPU usage
- Memory: Limit memory usage
- I/O: Limit disk I/O
- Network: Limit network bandwidth
Example:
Container 1: CPU 50%, Memory 2GB
Container 2: CPU 30%, Memory 1GB
Container 3: CPU 20%, Memory 512MB
Comparison
| Feature | Containers | VMs |
|---|---|---|
| Isolation | Process-level | Hardware-level |
| OS | Shared kernel | Full OS per VM |
| Startup | Seconds | Minutes |
| Resource usage | Low | High |
| Overhead | Minimal | Significant |
| Security | Less isolated | More isolated |
| Use case | Applications | Full systems |
Examples
Container with Namespaces
# Create network namespace
ip netns add container1
# Create PID namespace (conceptual)
unshare --pid --fork bash
# Isolated process tree
ps aux # Only sees processes in namespace
Cgroups Example
# Create cgroup
mkdir /sys/fs/cgroup/memory/container1
# Set memory limit (1GB)
echo 1073741824 > /sys/fs/cgroup/memory/container1/memory.limit_in_bytes
# Add process to cgroup
echo $$ > /sys/fs/cgroup/memory/container1/cgroup.procs
Docker Container
# Dockerfile
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# Run container (uses namespaces and cgroups)
docker run -d --name web --memory=1g --cpus=0.5 nginx
Common Pitfalls
- Security: Containers share kernel, less isolated. Fix: Use VMs for strong isolation, secure containers
- Resource limits: Not setting cgroup limits. Fix: Set CPU, memory limits
- Kernel compatibility: Containers need compatible kernel. Fix: Use VMs for different OS
- Overhead misunderstanding: Thinking containers always better. Fix: Choose based on use case
Interview Questions
Beginner
Q: What is the difference between containers and virtual machines?
A:
Virtual Machines (VMs):
- Full OS: Each VM has its own operating system
- Hardware virtualization: Virtual CPU, RAM, disk
- Architecture: Host OS → Hypervisor → Guest OS → Apps
- Isolation: Complete separation
- Resource usage: High (full OS per VM)
- Startup: Minutes
Containers:
- Shared kernel: All containers share host OS kernel
- OS-level virtualization: Namespaces, cgroups
- Architecture: Host OS → Containers (isolated)
- Isolation: Process-level
- Resource usage: Low (shared kernel)
- Startup: Seconds
Key Differences:
| Feature | Containers | VMs |
|---|---|---|
| OS | Shared kernel | Full OS |
| Isolation | Process-level | Hardware-level |
| Startup | Seconds | Minutes |
| Resources | Low | High |
When to use:
- Containers: Applications, microservices, fast deployment
- VMs: Full systems, strong isolation, different OS
Intermediate
Q: Explain how Linux namespaces and cgroups enable containers. How do they provide isolation and resource management?
A:
Linux Namespaces (Isolation):
Provide isolation for system resources:
-
PID Namespace
Isolates process IDs Container sees only its own processes Process 1 in container ≠ Process 1 on host -
Network Namespace
Isolated network stack Own network interfaces, IP addresses, routing -
Mount Namespace
Isolated file system Own root filesystem (/) -
UTS Namespace
Isolated hostname Container can have different hostname
Cgroups (Resource Management):
Limit and account for resource usage:
# Memory limit
/sys/fs/cgroup/memory/container1/memory.limit_in_bytes = 1GB
# CPU limit
/sys/fs/cgroup/cpu/container1/cpu.shares = 512
How containers work:
1. Create namespaces (isolation)
2. Create cgroups (resource limits)
3. Run process in namespaces with cgroup limits
4. Process sees isolated environment
Example:
# Container sees:
- Only its own processes (PID namespace)
- Its own network (Network namespace)
- Its own filesystem (Mount namespace)
- Limited resources (Cgroups)
Senior
Q: Design a container orchestration system that manages thousands of containers. How do you use namespaces, cgroups, and ensure security and resource management?
A:
class ContainerOrchestration {
private namespaceManager: NamespaceManager;
private cgroupManager: CgroupManager;
private securityManager: SecurityManager;
constructor() {
this.namespaceManager = new NamespaceManager();
this.cgroupManager = new CgroupManager();
this.securityManager = new SecurityManager();
}
// 1. Namespace Management
class NamespaceManager {
async createContainer(config: ContainerConfig): Promise<Container> {
// Create all namespaces
const namespaces = {
pid: await this.createPIDNamespace(),
network: await this.createNetworkNamespace(),
mount: await this.createMountNamespace(),
uts: await this.createUTSNamespace(),
ipc: await this.createIPCNamespace(),
user: await this.createUserNamespace()
};
return new Container(namespaces);
}
async createPIDNamespace(): Promise<PIDNamespace> {
// Unshare PID namespace
// Container sees only its processes
}
async createNetworkNamespace(): Promise<NetworkNamespace> {
// Create isolated network
// Own interfaces, routing
}
}
// 2. Cgroup Management
class CgroupManager {
async setLimits(containerId: string, limits: ResourceLimits): Promise<void> {
// Set CPU limit
await this.setCPULimit(containerId, limits.cpu);
// Set memory limit
await this.setMemoryLimit(containerId, limits.memory);
// Set I/O limit
await this.setIOLimit(containerId, limits.io);
}
async setMemoryLimit(containerId: string, limit: number): Promise<void> {
const cgroupPath = `/sys/fs/cgroup/memory/${containerId}`;
await fs.writeFile(`${cgroupPath}/memory.limit_in_bytes`, limit.toString());
}
}
// 3. Security
class SecurityManager {
async secureContainer(container: Container): Promise<void> {
// Use user namespace (non-root in container)
await this.createUserNamespace(container);
// Capabilities: Drop unnecessary capabilities
await this.dropCapabilities(container);
// Seccomp: Restrict system calls
await this.applySeccomp(container);
// AppArmor/SELinux: Additional security
await this.applyAppArmor(container);
}
}
}
Features:
- Namespaces: Complete isolation (PID, network, mount, etc.)
- Cgroups: Resource limits (CPU, memory, I/O)
- Security: User namespaces, capabilities, seccomp
Key Takeaways
- VMs: Full OS per VM, hardware virtualization, strong isolation, heavy
- Containers: Shared kernel, OS-level virtualization, lightweight, fast startup
- Namespaces: Provide isolation (PID, network, mount, UTS, IPC, user)
- Cgroups: Limit resources (CPU, memory, I/O, network)
- Trade-offs: Containers faster/lighter, VMs more isolated
- Use cases: Containers for apps, VMs for full systems
- Best practices: Use namespaces for isolation, cgroups for limits, secure containers properly