Operating Systems
An operating system is just a program that manages other programs and hands out the hardware. Once you can see that happening, containers and schedulers stop being magic.
Every time a program touches the outside world — a file, the network, the clock — it asks the kernel with a system call. That boundary is where user space ends and the kernel begins.
Run strace on a simple command and count the syscalls it makes.
$ strace -c ls /You get a table of syscalls (openat, read, write, mmap...). Every one is a request to the kernel.
Reveal solution
$ sudo apt install -y strace # if needed $ strace -c ls /
Processes are created by fork (copy) + exec (replace image). Every process has a parent — all the way up to PID 1.
Start a background sleep and find it, its PID, and its parent.
$ ps -o pid,ppid,cmd --ppid $$You see the child sleep with ppid equal to your shell — the fork relationship, made concrete.
Reveal solution
$ sleep 100 & $ ps -o pid,ppid,cmd --ppid $$ $ pstree -p $$
The deepest Unix idea: files, pipes, and sockets are all reached through small integers called file descriptors. 0/1/2 are stdin/stdout/stderr; the kernel tracks the rest per process.
Open a file on fd 3 in your shell, then inspect the shell's open descriptors.
$ ls -l /proc/$$/fdfd 3 is a symlink to the file you opened. This is the same mechanism a network socket uses — it's just an fd too.
Reveal solution
$ exec 3< /etc/hostname $ ls -l /proc/$$/fd $ exec 3<&- # close it again
Reach engineers who read the man page
Native, contextual, no tracking — this is how the curriculum stays free.
Each process sees its own private virtual address space; the kernel maps it onto real physical RAM behind the scenes. The map is readable in /proc.
Print the memory map of a running process and find its heap, stack, and shared libraries.
$ cat /proc/self/maps | headYou'll see regions labelled [heap], [stack], and mapped .so libraries — the anatomy of a running program.
Reveal solution
$ cat /proc/self/maps | head -20Every fd costs a slot, and the kernel caps how many a process may hold (ulimit -n). Hit the cap and syscalls fail with EMFILE — a real, common production outage.
In a subshell, lower the fd limit hard, then watch a program fail to open files. Then explain what a real fix looks like.
$ bash -c 'ulimit -n 8; for i in $(seq 20); do exec {fd}<>/tmp/f$i || { echo "failed at $i"; break; }; done'It fails partway with an open-files error. The real fix: raise the soft limit or close leaked fds — never just paper over it.
Reveal solution
# Inspect current limits: $ ulimit -n # Raise the soft limit for a session: $ ulimit -n 4096
Processes, file descriptors, virtual memory, syscalls — these four ideas are the vocabulary for everything above. A container is a process; a socket is an fd; an OOM kill is virtual memory hitting a wall. You'll reuse this in every module that follows.