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.

Intermediate11 min read

Containers vs VMs (Namespaces, Cgroups)

Why This Matters

Think of containers like apartments in a building. Each apartment is isolated (you can't see into other apartments), but they all share the same building infrastructure (plumbing, electricity). VMs are like separate houses—each has its own complete infrastructure. Containers are lighter (share the OS) but less isolated. VMs are heavier (full OS) but more isolated.

This matters because the choice between containers and VMs affects resource usage, startup time, and isolation. Containers start faster (seconds vs minutes) and use less resources (share the OS), but they're less isolated (share the kernel). VMs are more isolated (separate OS) but use more resources and start slower.

In interviews, when someone asks "How would you deploy an application?", they're testing whether you understand containers vs VMs. Do you know when to use each? Do you understand the trade-offs? Most engineers don't. They just use containers and wonder why isolation is weak.

What Engineers Usually Get Wrong

Most engineers think "containers are just lightweight VMs." But containers use different technologies: namespaces (for isolation) and cgroups (for resource limits). VMs use full virtualization (hypervisor, guest OS). Understanding this helps you understand the trade-offs and choose the right technology.

Engineers also don't understand that containers share the host kernel. If the host kernel has a vulnerability, all containers are affected. VMs have separate kernels, so a vulnerability in one VM doesn't affect others. This is why VMs provide stronger isolation.

How This Breaks Systems in the Real World

A service was using containers for multi-tenancy. Different customers' applications ran in different containers. But containers share the host kernel. A vulnerability in the kernel allowed one container to access another container's data. Customer data was compromised. The fix? Use VMs for stronger isolation, or use container security features (seccomp, AppArmor) to harden containers.

Another story: A service was using VMs for all deployments. Each VM took 5 minutes to start and used 2GB of RAM. When the service needed to scale quickly, it couldn't—VMs were too slow to start and used too many resources. The fix? Use containers. Containers start in seconds and use less resources. This allows faster scaling and better resource utilization.


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

FeatureContainersVMs
IsolationProcess-levelHardware-level
OSShared kernelFull OS per VM
StartupSecondsMinutes
Resource usageLowHigh
OverheadMinimalSignificant
SecurityLess isolatedMore isolated
Use caseApplicationsFull 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:

FeatureContainersVMs
OSShared kernelFull OS
IsolationProcess-levelHardware-level
StartupSecondsMinutes
ResourcesLowHigh

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:

  1. PID Namespace

    Isolates process IDs
    Container sees only its own processes
    Process 1 in container ≠ Process 1 on host
    
  2. Network Namespace

    Isolated network stack
    Own network interfaces, IP addresses, routing
    
  3. Mount Namespace

    Isolated file system
    Own root filesystem (/)
    
  4. 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:

  1. Namespaces: Complete isolation (PID, network, mount, etc.)
  2. Cgroups: Resource limits (CPU, memory, I/O)
  3. Security: User namespaces, capabilities, seccomp

Failure Stories You'll Recognize

The Security Breach: A service was using containers for multi-tenancy. Different customers' applications ran in different containers. But containers share the host kernel. A vulnerability in the kernel allowed one container to access another container's data. Customer data was compromised. The fix? Use VMs for stronger isolation, or use container security features (seccomp, AppArmor) to harden containers.

The Slow Scaling: A service was using VMs for all deployments. Each VM took 5 minutes to start and used 2GB of RAM. When the service needed to scale quickly, it couldn't—VMs were too slow to start and used too many resources. The fix? Use containers. Containers start in seconds and use less resources. This allows faster scaling and better resource utilization.

The Resource Exhaustion: A service was using containers but didn't set resource limits (cgroups). One container consumed all CPU and memory, starving other containers. The system became unresponsive. The fix? Set resource limits using cgroups. Limit CPU, memory, and I/O per container. This ensures fair resource sharing.

What Interviewers Are Really Testing

They want to hear you talk about containers and VMs as tools with trade-offs, not absolutes. Junior engineers say "containers are lightweight, VMs are heavy." Senior engineers say "containers share the host kernel, start fast, and use less resources, but provide weaker isolation. VMs have separate OS, provide stronger isolation, but are heavier and slower. Choose based on your needs—containers for apps, VMs for full systems or stronger isolation."

When they ask "How would you deploy an application?", they're testing:

  • Do you understand containers vs VMs?

  • Do you know when to use each?

  • Can you configure containers properly (namespaces, cgroups)?

  • 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

How InterviewCrafted Will Teach This

We'll teach this through production failures, not definitions. Instead of memorizing "containers are lightweight," you'll learn through scenarios like "why did one container access another container's data?"

You'll see how containers and VMs affect isolation, performance, and resource usage. When an interviewer asks "how would you deploy an application?", you'll think about containers, VMs, namespaces, cgroups, and trade-offs—not just "use containers."

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


About the author

InterviewCrafted helps you master system design with patience. We believe in curiosity-led engineering, reflective writing, and designing systems that make future changes feel calm.