Why Linux Dominates
Linux runs on approximately 96% of the world's top 1 million web servers, nearly 100% of public cloud infrastructure, every Android device, most routers, IoT devices, and supercomputers. When you deploy to AWS, GCP, or Azure, you're deploying to Linux. When you run Docker or Kubernetes, you're relying on Linux kernel features. When you SSH into a server, you're almost always connecting to Linux.
Understanding Linux is not optional for anyone working in modern software infrastructure. The question isn't whether you'll encounter it — it's how deeply you need to understand it. This article gives you the mental model that makes the rest of Linux legible.
Kernel Architecture
The Linux kernel is a monolithic kernel — most OS services (process scheduling, memory management, file systems, device drivers, networking) run in a single large kernel address space in Ring 0. This is in contrast to a microkernel (like QNX or seL4) where most services run as user-space processes, communicating via IPC.
Monolithic kernels have a performance advantage (no context switches between kernel services) but a reliability tradeoff (a bug in any driver can crash the entire kernel). Linux mitigates this via loadable kernel modules (LKMs) — drivers and file system code can be compiled separately and loaded/unloaded at runtime without rebooting.
# View currently loaded kernel modules
lsmod | head -20
# Get info about a specific module
modinfo ext4
# Load a module (requires root)
# sudo modprobe nf_conntrack
# See the kernel version currently running
uname -r # e.g., 6.8.0-45-generic
# Detailed kernel build info
uname -a
# View kernel compile-time configuration (what features are built in vs modular)
zcat /proc/config.gz 2>/dev/null | grep CONFIG_EXT4 || \
cat /boot/config-$(uname -r) | grep CONFIG_EXT4
Key Kernel Subsystems
flowchart TD
subgraph US["User Space"]
A["Applications, Shells, Daemons, System Libraries (glibc)"]
end
subgraph KS["Kernel Space (Ring 0)"]
SC["System Call Interface\n(openat, read, write, fork, mmap, ioctl...)"]
PM["Process Scheduler\n(CFS — Completely Fair Scheduler)"]
MM["Memory Manager\n(Virtual memory, page tables, OOM killer)"]
VFS["Virtual File System\n(ext4, tmpfs, procfs, sysfs, overlayfs)"]
NET["Networking Stack\n(TCP/IP, netfilter, socket API)"]
DD["Device Drivers\n(block, char, network, USB, GPU)"]
KM["Kernel Modules\n(Loadable drivers, FS, net filters)"]
end
subgraph HW["Hardware"]
CPU["CPU"] --- RAM["RAM"] --- DISK["NVMe/HDD"] --- NIC["NIC"] --- USB["USB/Other"]
end
US <-->|syscall / sysret| SC
SC --> PM & MM & VFS & NET
VFS & NET --> DD
DD --> HW
KM -..->|extend| DD & VFS & NET
style US fill:#f8f9fa,stroke:#3B9797
style KS fill:#132440,color:#fff,stroke:#3B9797
style HW fill:#16476A,color:#fff,stroke:#3B9797
| Subsystem | Role | Key Concepts |
|---|---|---|
| Process Scheduler | Decides which process runs on which CPU core at what time | CFS (Completely Fair Scheduler), run queues, nice values, cgroups CPU limits |
| Memory Manager | Virtual memory, page allocation, OOM handling | Page tables, TLB, slab allocator, OOM killer, HugePages |
| VFS (Virtual File System) | Uniform file/directory API over many storage backends | inodes, dentries, superblock, file operations struct |
| Networking Stack | TCP/IP implementation, socket API, firewall | sk_buff (socket buffer), netfilter hooks, iptables, eBPF |
| Device Drivers | Hardware abstraction for block, char, and network devices | IRQ handlers, DMA, MMIO, device tree |
| IPC Subsystem | Inter-process communication primitives | pipes, FIFOs, Unix sockets, POSIX message queues, shared memory, futex |
The Linux Boot Sequence
Understanding the boot sequence is invaluable for debugging startup failures, configuring services, and understanding container/VM startup times. The sequence from power-on to a usable shell has six stages:
sequenceDiagram
participant FW as UEFI/BIOS Firmware
participant BL as Bootloader (GRUB2)
participant KN as Linux Kernel
participant ID as initramfs
participant SD as systemd (PID 1)
participant SV as Services & Shell
FW->>FW: POST — test hardware, find boot device
FW->>BL: Load GRUB2 from EFI partition
BL->>BL: Show boot menu, apply kernel cmdline params
BL->>KN: Load kernel image + initramfs into RAM
KN->>KN: Decompress self, detect hardware, init subsystems
KN->>ID: Mount initramfs as root, run /init script
ID->>ID: Load drivers needed to mount real root partition
ID->>KN: Switch root to real disk partition (pivot_root)
KN->>SD: Execute /sbin/init = systemd (PID 1)
SD->>SD: Parse unit files, calculate dependency graph
SD->>SV: Start services in parallel (networking, sshd, etc.)
SV->>SV: Login prompt available
# View boot messages from the kernel ring buffer
dmesg | head -50
dmesg --level=err,warn # Show only errors and warnings
# View systemd boot timing (which services took how long)
systemd-analyze
systemd-analyze blame | head -20 # Slowest units first
systemd-analyze critical-chain # Critical path to reaching default target
# View kernel command line passed by bootloader
cat /proc/cmdline
# See GRUB config
cat /boot/grub/grub.cfg | grep menuentry | head -5
systemd — The Init System
When the kernel starts PID 1 (systemd), it becomes responsible for bringing up every service the system needs. systemd uses unit files to describe resources (services, mount points, sockets, timers) and calculates a dependency graph to start them in the correct order, with maximum parallelism.
# List all active systemd units
systemctl list-units --type=service --state=active
# Inspect a service unit file
systemctl cat sshd.service # or ssh.service on Debian/Ubuntu
# Common service management commands
systemctl status nginx
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
systemctl enable nginx # Start on boot
systemctl disable nginx # Don't start on boot
# View the dependency graph for a service
systemctl list-dependencies sshd.service
# See the current default target (equivalent to old runlevel)
systemctl get-default # usually "multi-user.target" or "graphical.target"
# View logs for a specific service (systemd's journalctl)
journalctl -u nginx --since "1 hour ago" --no-pager
Why Containers Don't Run systemd by Default
Docker containers normally run a single application process as PID 1 (not systemd). This is because: (1) systemd tries to manage hardware, D-Bus, cgroups mounting, and other system-level things that conflict with the container runtime's ownership of these resources; (2) most container workloads are single services that don't need an init system; (3) systemd as PID 1 has different signal handling than expected by Docker (e.g., it doesn't forward SIGTERM to child processes by default).
When you do need systemd in a container (e.g., for testing Ansible roles or running legacy multi-service applications), use the --privileged flag and mount the cgroups — but understand you're breaking the single-process container model.
The Unix Philosophy
Linux inherits its design from Unix, and the Unix philosophy — articulated by Doug McIlroy in 1978 — continues to shape how Linux tools are built and composed:
- Write programs that do one thing and do it well.
- Write programs to work together.
- Write programs that handle text streams, because that is a universal interface.
This explains why Unix/Linux tools are designed the way they are: grep just filters lines, sort just sorts them, wc just counts words/lines. Power comes from composition via pipes: cat /var/log/nginx/access.log | grep "500" | awk '{print $1}' | sort | uniq -c | sort -rn | head -10 — a five-tool pipeline that identifies the top 10 source IPs causing 500 errors, written from primitives in 30 seconds.
Other corollaries of the Unix philosophy that you'll encounter constantly:
- Everything is a file: Devices (
/dev/sda), processes (/proc/1234/), kernel parameters (/sys/kernel/), network sockets — all exposed as filesystem paths you can read, write, and manipulate with standard tools. - Silence is success: Well-behaved tools print nothing on success and output errors to stderr. This allows clean chaining — if a command is silent, it succeeded.
- Small sharp tools: Prefer composing small tools over building large monolithic programs. This is why the Linux command line has thousands of single-purpose utilities.
The Filesystem Hierarchy Standard
Linux follows the FHS (Filesystem Hierarchy Standard) — a convention for where files live. Knowing this lets you find any file on any Linux system without documentation:
| Directory | Contents | Examples |
|---|---|---|
/ | Root — everything hangs off here | — |
/bin, /usr/bin | User-facing command binaries | ls, grep, bash, python3 |
/sbin, /usr/sbin | System administration binaries | ip, mount, fdisk, sysctl |
/lib, /usr/lib | Shared libraries (.so files) | libc.so.6, libssl.so |
/etc | System-wide configuration files | /etc/passwd, /etc/nginx/, /etc/systemd/ |
/var | Variable runtime data (logs, databases, mail) | /var/log/, /var/lib/docker/, /var/run/ |
/tmp | Temporary files (cleared on reboot) | Scratch space for programs |
/proc | Virtual FS: kernel/process state (in RAM) | /proc/cpuinfo, /proc/1/maps |
/sys | Virtual FS: hardware/kernel parameters | /sys/class/net/, /sys/block/sda/ |
/dev | Device files managed by udev | /dev/sda, /dev/null, /dev/tty |
/home | User home directories | /home/alice, /home/bob |
/root | root user's home | — |
/opt | Optional third-party software | /opt/google/, /opt/homebrew/ |
/usr/local | Locally compiled/installed software | /usr/local/bin/, /usr/local/lib/ |
/boot | Kernel images and bootloader files | vmlinuz-6.8.0, initrd.img, grub/ |
/proc and /sys — The Virtual Filesystems
/proc and /sys are pseudo-filesystems — they don't exist on disk. They're generated by the kernel in RAM and expose live kernel and process state as readable (and sometimes writable) files. They're the primary way to introspect and tune a running Linux system.
# === /proc — process and kernel state ===
# Your current process's info (PID of the running shell)
ls /proc/$$ # cmdline, exe, fd/, maps, mem, net/, status...
cat /proc/$$/status # Memory usage, UIDs, GIDs, thread count
cat /proc/$$/maps # Virtual memory map (same as /proc/PID/maps)
# System-wide info
cat /proc/cpuinfo # CPU model, cores, features (SSE4.2, AVX, etc.)
cat /proc/meminfo # RAM usage: MemTotal, MemFree, Buffers, Cached...
cat /proc/loadavg # Load averages (1, 5, 15 min) + running/total processes
cat /proc/net/tcp # Active TCP connections (hex addresses)
cat /proc/sys/kernel/hostname # Current hostname (readable!)
# Kernel tunable parameters via /proc/sys
cat /proc/sys/vm/swappiness # How aggressively the kernel swaps (0-100)
cat /proc/sys/net/ipv4/ip_forward # IP forwarding (0=off, 1=on — needed for routing/containers)
# === /sys — hardware and device parameters ===
ls /sys/class/net/ # Network interfaces
cat /sys/class/net/eth0/speed # Link speed in Mbps
cat /sys/class/net/eth0/statistics/rx_bytes # Bytes received
ls /sys/block/ # Block devices (sda, nvme0n1, etc.)
cat /sys/block/sda/queue/rotational # 1=HDD, 0=SSD
# Tuning example: disable transparent hugepages (common for databases)
cat /sys/kernel/mm/transparent_hugepage/enabled
Exercises
# Exercise 1: Explore your kernel and loaded modules
uname -r # Kernel version
lsmod | wc -l # How many modules are loaded?
lsmod | grep "^ext" # Find the ext4 filesystem module
# Exercise 2: Trace the boot timeline
systemd-analyze
systemd-analyze blame | head -10 # Top 10 slowest services
# Which service takes the most time on your system?
# Exercise 3: Navigate the FHS with purpose
ls /etc/*.conf | head -10 # Config files in /etc
ls /var/log/ | head -10 # Log files
ls /proc/ | grep "^[0-9]" | wc -l # How many processes are running?
# Exercise 4: Read live system state from /proc
cat /proc/loadavg # What's the current load average?
cat /proc/meminfo | grep -E "MemTotal|MemFree|Buffers|Cached"
# Free memory = MemFree + Buffers + Cached (Linux caches aggressively)
# Exercise 5: Inspect a systemd service
systemctl status sshd 2>/dev/null || systemctl status ssh
# Note: active/inactive state, PID, memory usage, recent log lines
Conclusion & Next Steps
The Linux kernel is a monolithic, modular OS kernel whose architecture — process scheduler, memory manager, VFS, networking stack, and device drivers — maps directly to the system calls you've already seen in Part 1. The Unix philosophy of small, composable, text-streaming tools gives Linux its characteristic power through composition. The FHS makes any Linux system navigable, and /proc//sys make the live system inspectable without any special tools.