This chapter explores the operational aspects of containers, focusing on how containers work internally, how pods communicate, and practical examples of container operations. Understanding these concepts is crucial for building and managing containerized applications in your custom Linux distribution.
A container is a lightweight, standalone, executable package that includes everything needed to run a piece of software. Containers isolate applications from the host system and from each other, providing consistency across different environments.
Key Characteristics:
- Isolation: Processes, filesystem, network
- Portability: Run anywhere with container runtime
- Efficiency: Shared kernel, minimal overhead
- Immutability: Consistent deployment
Core Components:
- Container Runtime: Executes containers (Docker, Podman, containerd)
- Container Image: Read-only template with application and dependencies
- Container Layer: Writable layer for runtime changes
- Namespaces: Kernel feature for isolation
- cgroups: Resource limits and accounting
Container Lifecycle:
Image → Container → Running Process → Stopped Container → Removed
Types of Namespaces:
- PID: Process ID isolation
- NET: Network interface isolation
- MNT: Filesystem mount isolation
- UTS: Hostname/domainname isolation
- IPC: Inter-process communication isolation
- USER: User/group ID isolation
Kernel Implementation - Code References:
Each namespace type has its own implementation in the kernel:
-
PID Namespace:
kernel/pid_namespace.c: PID namespace creation and managementkernel/pid.c: Process ID allocation in namespaces- Look for
create_pid_namespace(),find_pid_ns()
-
Network Namespace:
net/core/net_namespace.c: Network namespace infrastructurenet/core/dev.c: Per-namespace device management- Look for
copy_net_ns(),get_net_ns_by_fd()
-
Mount Namespace:
fs/namespace.c: Mount namespace and propagationfs/mount.h: Mount structures- Look for
copy_mnt_ns(),propagate_mount_busy()
-
UTS Namespace:
kernel/utsname.c: Hostname/domain isolation- Look for
copy_utsname()
-
IPC Namespace:
ipc/namespace.c: IPC object isolation- Look for
copy_ipcs()
-
User Namespace:
kernel/user_namespace.c: UID/GID mappingkernel/uid16.c: User ID mapping functions- Look for
create_user_ns(),map_id_range_down()
Namespace System Calls:
unshare(): Create new namespace (kernel/fork.c)setns(): Join existing namespace (kernel/nsproxy.c)clone(): Create process with new namespaces (kernel/fork.c)
Namespace Example:
# Create network namespace
ip netns add container_net
# Run command in namespace
ip netns exec container_net ip addr
# List namespaces
lsnscgroup Hierarchy:
cgroup/
├── cpu/
│ ├── container1/
│ └── container2/
├── memory/
│ ├── container1/
│ └── container2/
└── blkio/
├── container1/
└── container2/
Kernel CGroup Implementation - Code References:
-
Core CGroup System:
kernel/cgroup/cgroup.c: Main cgroup implementationkernel/cgroup/cgroup-v1.c: CGroup v1 (legacy hierarchy)kernel/cgroup/cgroup-v2.c: CGroup v2 (unified hierarchy)- Look for
cgroup_init(),cgroup_attach_task()
-
CGroup Controllers:
-
CPU Controller:
kernel/sched/core.c,kernel/sched/fair.c- Functions:
cpu_cgroup_attach(),task_group_sched_runtime()
- Functions:
-
Memory Controller:
mm/memcontrol.c- Functions:
mem_cgroup_charge(),mem_cgroup_try_charge() - OOM handling:
mm/oom_kill.c
- Functions:
-
Block I/O Controller:
block/blk-cgroup.c- Functions:
blkcg_init_queue(),blk_throtl_bio()
- Functions:
-
PID Controller:
kernel/cgroup/pids.c- Limits number of processes:
pids_can_fork()
- Limits number of processes:
-
-
CGroup Filesystem:
kernel/cgroup/cgroup.c: CGroupFS implementation- Mounted at
/sys/fs/cgroup/ - Virtual files for resource control
Resource Limits:
# Create cgroup
cgcreate -g cpu,memory:container1
# Set CPU limit (50% of one core)
cgset -r cpu.shares=512 container1
# Set memory limit
cgset -r memory.limit_in_bytes=100M container1
# Execute in cgroup
cgexec -g cpu,memory:container1 /bin/bashLayer Structure:
Base OS Layer (Ubuntu, Alpine, etc.)
├── Runtime Layer (Node.js, Python, etc.)
├── Application Layer (Your code)
└── Configuration Layer (Environment variables, etc.)
Union Filesystem:
- OverlayFS: Modern Linux union filesystem
- AUFS: Older union filesystem
- Btrfs/ZFS: Copy-on-write filesystems
Building Images:
# Dockerfile example
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y nginx
COPY app /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]Layer Inspection:
# Docker layer inspection
docker history nginx:latest
# Podman layer inspection
podman inspect nginx:latest | jq .RootFS
# Buildah layer manipulation
buildah from ubuntu:20.04
buildah run container_id apt-get update
buildah commit container_id myimageA pod is a group of one or more containers that share storage, network, and specifications for how to run. In Kubernetes, pods are the smallest deployable units, but the concept applies to container orchestration in general.
Pod Characteristics:
- Shared Network: All containers in a pod share IP and port space
- Shared Storage: Volumes mounted to all containers
- Lifecycle Management: Containers started/stopped together
- Local Communication: Containers communicate via localhost
Docker Compose Pod:
# docker-compose.yml
version: "3.8"
services:
web:
image: nginx
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
app:
image: myapp
depends_on:
- web
environment:
- WEB_HOST=webPodman Pod:
# Create pod
podman pod create --name mypod -p 8080:80
# Add containers to pod
podman run --pod mypod --name web nginx
podman run --pod mypod --name app myapp
# Pod operations
podman pod ps
podman pod logs mypod
podman pod stop mypodBridge Network (Default):
- Containers get IP from bridge network
- Communication via IP addresses
- Port mapping for external access
Host Network:
- Container uses host network stack
- Direct access to host ports
- No port mapping needed
Container Network:
- Share network namespace with another container
- Communication via localhost
None Network:
- No network access
- Isolated container
Direct IP Communication:
# Get container IP
docker inspect web | grep IPAddress
# Connect from another container
curl http://172.17.0.2:80DNS-Based Service Discovery:
# Docker networks with DNS
docker network create mynetwork
docker run --network mynetwork --name web nginx
docker run --network mynetwork --name app myapp
# App connects via hostname
curl http://web:80Environment Variables:
# Pass connection info via env
docker run --env WEB_HOST=web --env DB_HOST=db myapp
# Application reads environment
web_host = os.getenv('WEB_HOST')Architecture:
[Web Server] ←→ [Application] ←→ [Database]
↑ ↑ ↑
Port 80 localhost localhost
Implementation:
# Create pod
podman pod create --name webapp -p 8080:80
# Database container
podman run -d --pod webapp --name db \
-e POSTGRES_PASSWORD=mypass \
-e POSTGRES_DB=myapp \
postgres:13
# Application container
podman run -d --pod webapp --name app \
-e DB_HOST=localhost \
-e DB_PORT=5432 \
myapp:latest
# Web server container
podman run -d --pod webapp --name web \
-v ./nginx.conf:/etc/nginx/nginx.conf \
nginx
# Check pod status
podman pod ps
podman ps --podService Mesh Pattern:
# docker-compose.yml
version: "3.8"
services:
api-gateway:
image: nginx
ports:
- "80:80"
volumes:
- ./gateway.conf:/etc/nginx/nginx.conf
depends_on:
- auth-service
- user-service
auth-service:
image: auth-service
environment:
- USER_SERVICE_URL=http://user-service:8080
depends_on:
- user-service
user-service:
image: user-service
environment:
- DB_URL=postgres://db:5432/myapp
depends_on:
- db
db:
image: postgres:13
environment:
- POSTGRES_DB=myappInter-Service Calls:
# auth-service communicating with user-service
import requests
def authenticate_user(token):
# Call user service
response = requests.get(
f"{os.getenv('USER_SERVICE_URL')}/user",
headers={'Authorization': f'Bearer {token}'}
)
return response.json()Pipeline Architecture:
[Data Source] → [Processor 1] → [Processor 2] → [Storage]
Implementation:
# Create processing pod
podman pod create --name pipeline
# Shared volume for data
podman volume create pipeline-data
# Data source (simulated)
podman run -d --pod pipeline --name source \
--volume pipeline-data:/data \
busybox sh -c 'while true; do echo $(date) >> /data/input.txt; sleep 5; done'
# Processor 1
podman run -d --pod pipeline --name proc1 \
--volume pipeline-data:/data \
python:3 python -c "
import time
while True:
with open('/data/input.txt', 'r') as f:
lines = f.readlines()
processed = [line.upper() for line in lines]
with open('/data/processed1.txt', 'w') as f:
f.writelines(processed)
time.sleep(10)
"
# Processor 2
podman run -d --pod pipeline --name proc2 \
--volume pipeline-data:/data \
python:3 python -c "
import time
while True:
try:
with open('/data/processed1.txt', 'r') as f:
data = f.read()
result = data.replace(' ', '_')
with open('/data/final.txt', 'w') as f:
f.write(result)
except FileNotFoundError:
pass
time.sleep(15)
"
# Monitor pipeline
podman logs -f pipelineMulti-Service Application:
# docker-compose.yml
version: "3.8"
services:
frontend:
image: react-app
ports:
- "3000:3000"
environment:
- API_URL=http://api:8080
api:
image: node-api
ports:
- "8080:8080"
environment:
- DB_CONNECTION=postgresql://db:5432/app
depends_on:
- db
db:
image: postgres:13
environment:
- POSTGRES_DB=app
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:Orchestration Commands:
# Start all services
docker-compose up -d
# Scale services
docker-compose up -d --scale api=3
# Check service health
docker-compose ps
# View logs
docker-compose logs -f api
# Update services
docker-compose pull
docker-compose up -dPodman Quadlets:
# /etc/containers/systemd/api.container
[Unit]
Description=API Service
After=network.target
[Container]
Image=api:latest
PublishPort=8080:8080
Environment=DB_HOST=db
Volume=/data:/app/data
[Install]
WantedBy=multi-user.targetGenerate systemd units:
# Convert quadlet to systemd
podman generate systemd --new --files --name api
# Enable and start
systemctl enable podman-api.service
systemctl start podman-api.serviceContainer Introspection:
# Docker inspection
docker inspect container_name
# Podman inspection
podman inspect container_name
# Process tree
docker top container_name
podman top container_nameResource Usage:
# Container stats
docker stats
podman stats
# Specific container
docker stats container_name
podman stats container_nameContainer Logs:
# View logs
docker logs container_name
podman logs container_name
# Follow logs
docker logs -f container_name
podman logs -f container_name
# Log filtering
docker logs --since 1h container_nameInteractive Debugging:
# Execute in running container
docker exec -it container_name /bin/bash
podman exec -it container_name /bin/bash
# Debug stopped container
docker run --rm -it --volumes-from container_name ubuntu /bin/bashNetwork Debugging:
# Check container networking
docker network ls
podman network ls
# Inspect network
docker network inspect bridge
podman network inspect podman
# Network troubleshooting
docker exec container_name netstat -tlnp
podman exec container_name ss -tlnpgraph TD
A[Container Image] --> B[Container Runtime]
B --> C[Create Container]
C --> D[Start Container]
D --> E{Running}
E --> F[Execute Process]
E --> G[Network Setup]
E --> H[Volume Mounts]
F --> I[Application Logic]
G --> J[Inter-Container Communication]
H --> K[Data Persistence]
I --> L[Service Operations]
J --> M[Pod Communication]
L --> N[Container Lifecycle]
N --> O[Stop Container]
O --> P[Cleanup Resources]
- Create a simple container with busybox
- Execute commands inside the container
- Inspect container filesystem and processes
- Check resource usage with container stats
- Clean up the container
Expected Outcome: Understanding of basic container lifecycle and inspection
- Create a pod with Podman
- Add multiple containers to the pod
- Configure shared networking
- Test inter-container communication
- Monitor pod resources and logs
Expected Outcome: Working pod with communicating containers
- Design a simple web application architecture
- Create containers for each component
- Set up networking between containers
- Configure environment variables
- Test the complete application
Expected Outcome: Functional multi-container application
- Create custom Docker networks
- Connect containers to networks
- Test DNS resolution between containers
- Configure network aliases
- Debug network connectivity issues
Expected Outcome: Understanding of container networking patterns
- Create shared volumes
- Mount volumes in multiple containers
- Test data persistence across container restarts
- Implement data sharing patterns
- Clean up volumes safely
Expected Outcome: Containers sharing data through volumes
- Create a docker-compose file for a multi-service app
- Define service dependencies
- Configure environment variables
- Scale services horizontally
- Update services with zero downtime
Expected Outcome: Orchestrated multi-service application
- Create a failing container application
- Use logs to diagnose issues
- Execute commands in running containers
- Inspect container state and configuration
- Fix the application and redeploy
Expected Outcome: Proficiency in container debugging techniques
With a solid understanding of container operations, proceed to Chapter 12 for container security. Container operations provide the foundation for understanding how containers work together, while security focuses on protecting these operations from threats.
- Docker Documentation: https://docs.docker.com/
- Podman Documentation: https://podman.io/
- Kubernetes Pods: https://kubernetes.io/docs/concepts/workloads/pods/
- Container Networking: https://docs.docker.com/network/
- Docker Compose: https://docs.docker.com/compose/