Week 5

Containers and Resource Management

OPS3 - Virtualization and Cloud Infrastructure

Welcome to Week 5!

What You'll Learn This Week

1. The Container Paradigm

1.1. The Foundation: Namespaces and Control Groups

1.2. Understanding Control Groups in Depth

1.3. The cgroup Hierarchy

1.4. cgroup Controllers (Subsystems)

The power of cgroups comes from specialized controllers (also called subsystems), each responsible for managing a specific type of resource. The most critical controllers for container management include:

This controller limits disk read/write operations: - I/O Weight: Similar to CPU shares, assigns proportional I/O bandwidth. - Throttling: Sets absolute limits on read/write operations per second (IOPS) or bytes per second.

While technically separate from the primary cgroup implementation, network bandwidth can also be controlled through Traffic Control (tc) in conjunction with cgroups, allowing administrators to limit network throughput per container.

Limits the number of processes (PIDs) that can be created within a cgroup, preventing fork bombs and runaway process creation.

1.5. Practical cgroup Management

On modern Linux systems, cgroups are typically managed through the systemd init system, which uses cgroups extensively for service management. However, understanding direct cgroup manipulation is valuable for troubleshooting and advanced container configurations.

The cgroup filesystem is typically mounted at /sys/fs/cgroup/. Each controller has its own subdirectory, and creating a new cgroup is as simple as creating a directory within that hierarchy.

1.6. cgroups v1 vs v2

Most modern Linux distributions (such as Ubuntu 22.04+ and Debian 11+) have transitioned to cgroups v2 by default. Docker and other container runtimes now support both versions, though v2 offers improved performance and a cleaner API.

1.7. How Container Runtimes Use cgroups

When you run a container with resource limits, the container runtime (Docker, containerd, Podman, or LXC) performs these operations behind the scenes:

1.8. Example: Docker and cgroups

When you run the following Docker command:

Docker creates a cgroup and configures it approximately like this:

You can inspect these settings directly:

Figure 2: Linux Namespaces and Cgroups - Namespaces provide isolation (PID, Network, Mount) while cgroups enforce resource limits (CPU, Memory)

1.9. Section 1 Checkpoint

Summary: Namespaces: Provide isolation (Network, PID, Mount). The "Walls". Control Groups (cgroups): Provide resource limiting (CPU, RAM). The "Police". Containers share the Hot Kernel; VMs use their own Kernel.

Reflection: If a container crashes the kernel, does the host crash? Why can't you run a Windows Container on a Linux Host (natively)?

Resources: Red Hat: What are Linux Namespaces?

2. The Container Technologies Landscape

2.1. LXC (Linux Containers)

2.2. Docker

2.3. Podman

2.4. Apptainer (formerly Singularity)

2.5. Comparison Table

Figure 3: Container Technologies Landscape - LXC for system containers, Docker for application containers, Podman for secure daemonless containers, Apptainer for HPC workloads

Feature LXC Docker Podman Apptainer
Type System Container Application Container Application Container Compute Container
Philosophy "Lightweight VM" "Single Service" "Single Service" "Portable Application"
Management lxc-* commands docker CLI podman CLI apptainer CLI
Daemon None (Process based) Yes (dockerd) No (Fork/Exec) No
Network System IP (Bridge) Port Mapping Port Mapping Host Network (typ.)
Root Access Required for setup Required (Daemon) No (Rootless) No (Rootless)
Image Format System Templates OCI Layers OCI Layers Single File (.sif)
Primary Use Infrastructure / VPS Microservices Secure Microservices Scientific / Research

2.6. Section 2 Checkpoint

Summary:

Reflection:

Resources:

3. Working with System Containers (LXC CLI)

3.1. Creating a Container

Figure 4: LXC Container Lifecycle - From template download through creation, start, attach, stop, to destroy

3.2. Listing and Monitoring

To view the status of containers, the lxc-ls command is used. The --fancy flag provides a formatted table showing the state (RUNNING or STOPPED), IP addresses (if running), and autostart configuration.

3.3. Starting a Container

Booting an LXC container is significantly faster than booting a virtual machine because there is no kernel initialization. The lxc-start command simply initiates the init system within the isolated namespace environment.

3.4. Accessing the Container

3.5. Stopping and Destroying

Containers should be stopped gracefully to allow services to terminate correctly. The lxc-stop command sends the appropriate signals. When a container is no longer needed, lxc-destroy removes its configuration and deletes the root filesystem directory.

3.6. Section 3 Checkpoint

Summary:

Reflection:

Resources:

4. LXC in Proxmox VE (GUI Workflow)

4.1. Step 1: Downloading Templates

4.2. Step 2: Creating a Container

4.3. Step 3: Managing Resources Dynamically

4.4. Section 4 Checkpoint

Summary:

Reflection:

Resources:

5. Working with Application Containers (Docker CLI)

5.1. Docker Architecture Components

Figure 5: Docker Architecture - Docker CLI communicates with Docker Daemon via REST API to manage images, containers, networks, and volumes

5.2. Running a Container

Docker's most fundamental operation is docker run, which combines checking if the image exists locally, pulling it if missing, creating a container, and starting it.

5.3. Managing Container Lifecycle

Managing running containers involves a set of essential commands for inspection and control.

5.4. Inspecting and Debugging

The docker exec command is particularly useful for troubleshooting. It allows you to execute commands inside a running container. The -it flags allocate an interactive pseudo-TTY, giving you a shell prompt inside the container to inspect processes or check configurations.

Resource usage can be monitored using docker stats, which provides real-time information on CPU, memory, and network usage for running containers.

5.5. Building Custom Images with Dockerfiles

While pre-built images satisfy many needs, real applications require custom images. A Dockerfile is a text file containing instructions for building an image, where each instruction creates a new layer.

Consider a simple Python web application. A Dockerfile might look like this:

Figure 6: Dockerfile Image Layers - Each instruction creates a new layer; cached layers speed up rebuilds when only code changes

Building the image from this Dockerfile is done with the docker build command:

This reads the Dockerfile in the current directory (.) and builds an image tagged as myapp:1.0.

5.6. Section 5 Checkpoint

Summary:

Reflection:

Resources:

6. Working with Podman (Daemonless CLI)

6.1. Running a Container (Rootless)

By default, Podman runs containers as the user who invoked the command, mapping the user's UID to root inside the container. This is a significant security advantage.

6.2. Pods

Podman allows you to manage "Pods" locally. A Pod is a group of containers that share the same network namespace (localhost), a concept directly compatible with Kubernetes.

6.3. Section 6 Checkpoint

Summary:

Reflection:

Resources:

7. Future Preview: Kubernetes and kubectl

7.1. The Core Concepts (The K8s Dictionary)

Understanding K8s requires learning a new vocabulary, distinct from Docker's:

Docker Concept Kubernetes Concept Description
Container Pod A Pod is the smallest unit. It usually contains one container (like Nginx), but can contain helpers ("Sidecars"). Pods share a network namespace (localhost).
Volme Volume / PVC Storage that persists beyond the Pod's lifecycle.
Network Service A stable IP address/DNS name that sits in front of dynamic Pods. If a Pod dies and is replaced, the Service IP stays the same.
Compose File Manifest A YAML file describing the "Desired State" (e.g., "I want 3 copies of Nginx").

7.2. The Control Loop (Desired State)

7.3. The kubectl CLI

Start familiarizing yourself with these commands now. You will use them extensively in Week 11.

1. Creating Resources (Imperative)

Command Analysis: * run: Tells Kubernetes to create a single Pod. * --image=nginx: Uses the standard Nginx image from Docker Hub. * --restart=Never: Ensures this is treated as a simple Pod, not a managed service that automatically restarts.

2. Inspecting Resources

Command Analysis: * get: The universal command to list resources. You can use it for pods, nodes, services, etc. * describe: Shows the "Event Log" for a specific resource. If your Pod creation failed (e.g., "ImagePullBackOff"), this command tells you why.

3. Scaling Applications

Command Analysis: * create deployment: Instead of a single Pod, we create a Controller that manages Pods. * --replicas=3: We tell K8s we want 3 identical copies. K8s will start 3 Pods immediately. * scale: Changing this number updates the "Desired State." Kubernetes effectively "forks" 7 more copies to reach 10.

4. Exposing to the World

Command Analysis: * expose: Creates a Service that fronts the Deployment. * --type=NodePort: Opens a specific port (e.g., 32000) on every node in the cluster. This allows external traffic to reach your internal Pods. * --port=80: The internal port the container is listening on.

7.4. Self-Correction Checklist

8. Summary

9. Additional Resources

9.1. Video Tutorials

9.2. Documentation & Further Reading

10. Lab Exercises

Summary

Review the key concepts covered in this week's material

Questions?