feat(root01): author Computing & Linux Foundations, and the real 01->05 prerequisite chain

Adds all 6 ROOT 01 modules (how computers run software, the shell, filesystem navigation,
files & text, processes, users & permissions foundations), each with a real lesson,
demonstration/guided exercise, knowledge check where warranted, a hands-on Lab, and a
reflection — 35 activities, 29 new content files.

Adds 6 new hands-on Linux scenarios (linux-inspect-hardware, linux-shell-basics,
linux-filesystem-navigation, linux-files-and-text, linux-process-management,
linux-permissions-foundations) plus 2 MCQ scenarios, using the existing generic scenario/
validation engine (docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md §1) — every one tested end-to-end via
the real scenario setup/validate API, including negative tests confirming they correctly FAIL
when not actually solved (e.g. the process-management scenario fails while the target process
is still running; the permissions scenario is tested against a real `su - labuser` denial).

Wires rootnode-linux-foundations-assessment (2 required + 4 random-draw scenarios) using the
existing Phase 3B assessment engine.

Adds a real, server-side ROOT 01->02->03->04->05 course prerequisite chain
(courses.prerequisites) — verified live on two students: one who completed ROOT 01 sees ROOT 02
unlock; a fresh student sees ROOT 02 correctly locked while 03/04/05 stay vacuously satisfied
(their own prerequisite courses are still empty). ROOT 06+ and the Capstone are unaffected.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-26 12:59:52 -05:00
co-authored by Claude Sonnet 5
parent 87526bcf7f
commit 15b616274b
37 changed files with 1549 additions and 0 deletions
@@ -0,0 +1,66 @@
# How Computers Run Software
## Hardware, OS, and application: three different layers
When you run a program, three distinct layers cooperate:
- **Hardware** — the physical CPU, RAM, and storage. It has no idea what a "file" or a "process"
is; it just executes instructions and stores bits.
- **The operating system (kernel)** — the layer that turns raw hardware into something usable:
it decides which program gets the CPU next, hands out memory, and organizes storage into
files and directories. Linux is a kernel plus a large set of standard tools around it.
- **Applications (userspace)** — the programs you actually run. They ask the kernel for
resources (memory, files, network) through a well-defined interface (system calls) instead of
touching hardware directly.
This module gives you just enough of this model to reason about what you're actually looking at
for the rest of ROOT_ — not a full computer architecture course.
## CPU: the thing that actually executes instructions
A CPU has some number of **cores** — each core can run one stream of instructions at a time.
`nproc` tells you how many cores/threads Linux believes it has available. When a system feels
"slow," it's very often because more processes want CPU time than there are cores to give them.
## RAM: fast, temporary, and finite
RAM holds the data and code a running program is actively using. It's fast but **volatile** —
its contents disappear when power is lost, which is exactly why persistent data lives on
storage instead. `free -h` shows you total memory, how much is in use, and how much is free.
## Storage: slower, but persistent
Storage (an SSD/disk) keeps data even when the machine is off. It's organized into a
**filesystem** — the tree of directories and files you already have some intuition for. `df -h`
shows how much space exists and how much is used on each mounted filesystem.
## Processes: a running program
A **process** is a program actually being executed — code plus its own private memory, tracked
by the kernel with a unique ID (a PID). One program can have many processes running at once
(open two terminals running the same shell, and you have two separate processes). ROOT 01
Module 5 goes much deeper into this; for now, just know: everything you run becomes a process
the kernel is responsible for scheduling onto a CPU core.
## Why this matters for everything after this module
Every concept the rest of ROOT_ builds on is a refinement of this same idea. A container is
(mostly) an isolated process with its own filesystem view. A Kubernetes Pod is a group of
containers the scheduler places onto a specific machine's CPU/RAM. None of that will make sense
as anything other than magic if you don't first have this base model of what a computer is
actually managing.
## Instructor Notes
**Lesson goal:** Give students just enough of a mental model to stop treating "the computer" as
an opaque box — without turning this into a full CS/architecture course.
**Approximate timing:** 15 minutes read; 10 minutes live with discussion.
**Common misconception to watch for:** students often conflate RAM and storage ("my computer
has 8GB" meaning disk space). Draw the volatile-vs-persistent distinction explicitly and early.
**Discussion question:** "Why can't a program just talk to the hardware directly instead of
going through the kernel?" (Answer: the kernel is what lets many programs safely share one CPU/
one block of RAM without stepping on each other — this is worth naming explicitly, as it's the
root of why containers and Kubernetes are even possible.)
@@ -0,0 +1,35 @@
# Guided Exercise: Predict Before You Look
Before you run the real inspection commands in the Lab, commit to a guess — this is what makes
the real numbers meaningful instead of just scrolling past them.
## Your task
On paper or in a scratch file, write down your best GUESS for:
1. How many CPU cores does this machine have?
2. How much total RAM, roughly, in GB?
3. How much free disk space is on the root filesystem?
Then think through: which of these three would you expect a "student Lab" environment to be
MOST constrained on, and why? (Hint: think about what happens if 50 students are each running
their own Lab on one shared physical machine at the same time.)
## A worked shape to check yourself against
There's no single right numeric answer here — the point is the habit of predicting first. A
reasonable answer to the "most constrained" question: memory and CPU are typically the tightest
shared resource on a multi-tenant host, since every additional Lab needs its own slice of both,
while disk is comparatively cheap to over-provision.
## Instructor Notes
**Facilitation:** Have students commit to a number verbally or on a shared doc BEFORE anyone
runs the real commands — the value is in noticing the gap between guess and reality, not in
getting it right.
**Approximate timing:** 5 minutes.
**Optional extension:** ask what would happen to their guess if this were a "real" laptop
they personally own vs. a shared cloud server — good primer for later resource-limit
discussions (ROOT 06's resource requests/limits, ROOT 09's resource governance).
@@ -0,0 +1,27 @@
# Reflection: You Just Looked Inside the Box
## Reflection questions
1. How close was your guess to the real numbers? What surprised you most?
2. Name one thing you now understand about "the computer" that you couldn't have explained
before this module.
3. When you eventually run `kubectl describe pod` and see `requests`/`limits` for CPU and
memory, what do you now expect those numbers to actually be constraining?
## Real Ops takeaway
**Every resource limit you'll ever configure — in Docker, in Kubernetes, in a systemd unit — is
a promise about exactly the three things this module named: CPU, memory, and storage.** You
can't reason well about "why did my container get killed" or "why is my Pod stuck Pending"
without this base model. This module isn't computer-science trivia — it's the vocabulary the
rest of ROOT_ assumes you have.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 3 is worth spending real time on — it's
the first moment students connect this abstract lesson to something they'll type as a real
command many courses from now. Naming that connection explicitly here pays off later.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
@@ -0,0 +1,58 @@
# Linux and the Shell
## What "Linux" actually means
Linux is a **kernel** — the core piece of software from Module 1 that manages CPU, memory, and
storage. What most people call "a Linux system" (Ubuntu, Debian, Fedora, Alpine...) is a
**distribution**: the Linux kernel plus a chosen set of standard tools, package manager, and
configuration conventions layered on top. Different distributions, same kernel underneath —
which is why a command you learn on Ubuntu mostly still works on Alpine.
## Shell vs. terminal
These get used interchangeably but are different things:
- The **terminal** is the window/program that displays text and sends your keystrokes somewhere.
- The **shell** is the program actually interpreting what you type as commands — `bash` is the
shell this Lab uses. The terminal is just the display; the shell is the brain.
## Command structure
Every command follows roughly the same shape:
```
command [options] [arguments]
```
`ls -la /var/log` — `ls` is the command, `-la` are options (flags) that change its behavior,
`/var/log` is the argument (what to act on). Options can usually be combined (`-l -a` = `-la`).
## Exit codes: how a command reports success or failure
Every command returns a number when it finishes: `0` means success, anything else (1-255) means
some kind of failure. This isn't a Linux quirk — it's the exact mechanism scripts, CI pipelines,
and (much later) Kubernetes health checks all rely on to know whether something worked. You can
read the last command's exit code with the special variable `$?`.
## Getting help without leaving the terminal
- **Tab completion** — press Tab while typing a command or path; the shell completes it for you
or shows you the options. This is a genuine time-saver, not just a convenience.
- **Command history** — press the Up arrow to recall previous commands; `history` lists them.
- **`man <command>`** — the manual page for almost any command, with every option explained.
`man ls`, `man grep`, `man chmod` are all real, useful references — reaching for `man` before
a search engine is a habit worth building now.
## Instructor Notes
**Lesson goal:** Establish shell fluency vocabulary (shell vs. terminal, exit codes, options vs.
arguments) that every later module assumes without re-explaining.
**Approximate timing:** 15 minutes read; 10 minutes live with a short live demo of tab
completion and `man`.
**Common misconception to watch for:** students often think "Linux" and "the terminal" are the
same thing — clarify the kernel/distribution/shell/terminal layering explicitly.
**Demo idea:** live-type a command that fails (e.g. `ls /nonexistent`), then run `echo $?`
immediately after to show the exit code in real time — more convincing than describing it.
@@ -0,0 +1,49 @@
# Demonstration: Watching Exit Codes in Real Time
## OBSERVE
Run a command you know will succeed, then immediately check its exit code:
```
$ true
$ echo $?
0
```
## HYPOTHESIS
Now predict: what will the exit code be if the command fails instead?
## INSPECT
Run a command that fails, and check immediately:
```
$ ls /this-does-not-exist
ls: cannot access '/this-does-not-exist': No such file or directory
$ echo $?
2
```
## CHANGE
Try a few other failing commands and note their codes: `grep nomatch /etc/hostname` (exit 1 —
"no matches found," a different kind of failure than "file not found").
## VERIFY
Notice: exit codes aren't just "0 or 1" — different failures often get different non-zero
codes. `0` always means success; the exact non-zero value's MEANING varies by command, but ANY
non-zero value reliably means "something went wrong," which is the part every script actually
relies on (`if command; then ... else ...`).
## Instructor Notes
**Demo goal:** Make the abstract "exit code" concept concrete by actually watching `$?` change
in real time, immediately after each command — this is far more convincing live than described
in prose.
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** running `echo $?` after ANY other command in between (even
`ls`) silently checks the WRONG command's exit code — emphasize "check it immediately."
@@ -0,0 +1,37 @@
# Knowledge Check: Linux and the Shell
---
**1. What's the difference between a shell and a terminal?**
*Answer:* The terminal is the window/program that displays text and captures keystrokes; the
shell (e.g. `bash`) is the program actually interpreting what you type as commands. The terminal
is the display, the shell is the brain.
---
**2. A command exits with code `0`. What does that tell you?**
*Answer:* It succeeded. `0` is the universal "success" convention every script and pipeline
relies on; any non-zero value means some kind of failure occurred.
---
**3. You've typed half a long path and can't remember the rest. What should you press?**
*Answer:* Tab — tab completion finishes the path (or shows the options) without you needing to
type or remember it exactly.
---
**4. Where would you look to learn every option a command supports, without leaving the
terminal?**
*Answer:* Its manual page — `man <command>`.
## Instructor Notes
**Facilitation:** Question 1 is the one students most often blur together — worth confirming
verbally before moving on.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,31 @@
# Guided Exercise: Predict the Exit Code Before You Run It
This is a paper exercise — commit to an answer before checking it in the Lab.
## Your task
For each command below, predict whether its exit code will be `0` (success) or non-zero
(failure), and why:
1. `cat /etc/hostname` (a file that exists)
2. `cat /etc/does-not-exist-at-all` (a file that doesn't)
3. `grep root /etc/passwd` (a pattern that's very likely present)
4. `grep zzz-not-a-real-user /etc/passwd` (a pattern that's very likely absent)
5. `mkdir /tmp/already-exists && mkdir /tmp/already-exists` (running the same `mkdir` twice)
## A worked shape to check yourself against
1. `0` — the file exists and is readable.
2. Non-zero — the file doesn't exist, `cat` fails.
3. `0` — `grep` succeeds (exit 0) when it finds at least one match.
4. Non-zero (specifically `1`) — `grep` "fails" when it finds NO matches, even though nothing
went technically wrong. This is a common surprise: `grep`'s exit code means "did I find a
match," not "did an error occur."
5. The SECOND `mkdir` fails (non-zero) — the directory already exists. The first one succeeds.
## Instructor Notes
**Facilitation:** Item 4 is the one worth pausing on — many students assume "no error message"
means "exit code 0," and `grep`'s no-match convention is a good early counter-example.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced.
@@ -0,0 +1,25 @@
# Reflection: Exit Codes Are Everywhere After This
## Reflection questions
1. Before this module, did you know commands returned a machine-readable success/failure
signal at all? What did you assume happened instead?
2. Where do you think exit codes might matter later in ROOT_ — in a script, a CI pipeline, or
a container?
## Real Ops takeaway
**Every automated system you'll ever build or operate checks exit codes, not error messages.**
A script deciding whether to continue, a CI pipeline deciding whether to deploy, and (much
later) a container orchestrator deciding whether a process is healthy, all reduce to the exact
same question this module taught you to answer by hand: did this exit `0` or not? Getting
comfortable checking `$?` now means none of those later systems will feel like magic.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 2 previews Docker/Kubernetes health
checks well before students get there — useful to name explicitly without going deep yet.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
@@ -0,0 +1,55 @@
# Navigating the Filesystem
## Everything is one tree, starting at `/`
Linux has exactly one filesystem tree, rooted at `/` (pronounced "root," unrelated to your
username). Every file and directory, no matter what physical disk it's actually on, appears
somewhere under this one tree — there's no separate "C:\" and "D:\" the way Windows shows
multiple drives.
## Absolute vs. relative paths
An **absolute path** starts with `/` and always means the same location no matter where you
currently are: `/home/student/notes.txt`. A **relative path** is interpreted relative to your
CURRENT directory: `notes.txt` means something different depending on where you're standing
when you type it. `.` means "this directory," `..` means "one directory up" — `cd ..` moves up
one level, `cd ../..` moves up two.
## Key commands
- `pwd` — print your current directory (where am I?)
- `ls` — list what's in a directory (`ls -la` shows hidden files and details)
- `cd <path>` — change directory (absolute or relative)
## Hidden files
A file or directory starting with `.` (like `.bashrc` or `.config`) is "hidden" — `ls` skips it
by default, `ls -a` shows it. This isn't a security feature, just a convention to keep
configuration/metadata files out of the way of normal directory listings.
## The important top-level directories (conceptually, not memorized)
You don't need to memorize the entire Filesystem Hierarchy Standard, but recognizing these by
purpose will save you real confusion later:
- **`/etc`** — system-wide configuration files (nginx's config lives at `/etc/nginx/nginx.conf`)
- **`/var`** — variable data that changes while the system runs: logs (`/var/log`), among others
- **`/home`** — personal directories for regular users
- **`/tmp`** — temporary files, safe to assume anything here can disappear on reboot
- **`/usr`** — most installed programs and their supporting files live somewhere under here
- **`/proc`** — not real files on disk at all — a live, kernel-generated view into running
processes and system state (you'll use this again in Module 5)
## Instructor Notes
**Lesson goal:** Give students a working mental model of "one tree, absolute vs. relative
paths" plus just enough top-level-directory recognition to not be lost later — not FHS
memorization.
**Approximate timing:** 15 minutes read; 10 minutes live.
**Common misconception to watch for:** students coming from Windows sometimes expect separate
drives/roots — emphasize the single unified tree explicitly.
**Demo idea:** `cd /` then `ls`, narrating what each top-level directory is for as you see it,
rather than listing them in the abstract.
@@ -0,0 +1,43 @@
# Demonstration: The Same Word, Two Different Destinations
## OBSERVE
Starting from `/home/student`, run `cd project` — you land at `/home/student/project`.
## HYPOTHESIS
Now, from `/home/student/project`, what do you predict `cd project` will do this time?
## INSPECT
```
$ pwd
/home/student/project
$ cd project
bash: cd: project: No such file or directory
```
It fails — there's no `project` directory INSIDE `project` (unless you happened to create one).
The exact same relative path meant something completely different depending on where you stood.
## CHANGE
From `/home/student/project`, run `cd ../project` instead — this correctly goes back up one
level, then into `project` again, landing you right back where you started.
## VERIFY
`pwd` after each `cd` to confirm exactly where you ended up — this habit (verify your location
before assuming it) prevents a huge share of "why did my command run somewhere unexpected"
confusion later.
## Instructor Notes
**Demo goal:** Make "relative paths depend on where you are" concrete and slightly surprising,
rather than an abstract rule to memorize.
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** students assume a relative path always means the SAME thing
once they've used it once — reinforce that it's re-evaluated fresh every time, from wherever
they currently are.
@@ -0,0 +1,36 @@
# Knowledge Check: Navigating the Filesystem
---
**1. What does `..` mean in a path?**
*Answer:* One directory up from your current location.
---
**2. You're at `/home/student/project`. Does `cd project` do the same thing here as it did at
`/home/student`?**
*Answer:* No — a relative path is re-evaluated from your CURRENT location every time. At
`/home/student`, `project` refers to `/home/student/project`; from inside that same directory,
`project` would refer to `/home/student/project/project`, which likely doesn't exist.
---
**3. A file is "hidden" from a normal `ls`. What actually makes it hidden?**
*Answer:* Its name starts with a `.` — it's purely a naming convention `ls` respects by
default, not a real permission or security feature. `ls -a` shows it.
---
**4. Where would you expect to find a running system's log files?**
*Answer:* `/var/log` — `/var` holds data that changes while the system runs.
## Instructor Notes
**Facilitation:** Question 2 is the one worth confirming out loud — it's the core "gotcha" of
relative paths.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,39 @@
# Guided Exercise: Plan a Directory Structure on Paper First
Before you build anything in the Lab, plan it — this is the same discipline you'll use later
when planning a Kubernetes namespace layout or a Git repository structure.
## Your task
You're setting up a small project called `weather-app`. On paper, sketch a directory tree
containing:
- A place for source code
- A place for documentation
- A place for tests
- A single hidden configuration file at the project's root
Write out the exact `mkdir` and file-creation commands you'd use, including whether each path
you write is absolute or relative.
## A worked shape to check yourself against
```
mkdir -p weather-app/src weather-app/docs weather-app/tests
echo "ready" > weather-app/.config
```
(Or with an absolute path: `mkdir -p /srv/weather-app/src ...`.) The `-p` flag matters here —
without it, `mkdir` refuses to create `weather-app/src` if `weather-app` doesn't already exist.
## Instructor Notes
**Facilitation:** Have students commit to their command in writing before revealing the worked
answer — the value is in noticing what `-p` actually buys them, not just copying a correct
command.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced.
**Common mistake to watch for:** forgetting `mkdir -p` and getting a "No such file or
directory" error when creating a nested path in one command — a good moment to connect back to
Module 2's exit-code lesson (that error IS a non-zero exit code).
@@ -0,0 +1,27 @@
# Reflection: Structure Isn't Bureaucracy, It's Communication
## Reflection questions
1. Why might a real engineering team insist on a consistent directory structure across every
project, instead of everyone organizing files however they like?
2. Which of `/etc`, `/var`, `/home`, `/tmp`, `/usr`, `/proc` do you feel most confident you could
explain to someone else right now? Which one still feels fuzzy?
## Real Ops takeaway
**A predictable filesystem layout is what lets tools (and other engineers) reason about a
system without asking you first.** `/etc` always means configuration, `/var/log` always means
logs — this convention is exactly why a monitoring tool can be pointed at "check `/var/log`" on
any Linux machine and just work. Container images later inherit this same convention (an
nginx container still keeps its config at `/etc/nginx/nginx.conf`) — you're not learning a
one-off Linux fact, you're learning a convention that outlives this specific module.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 1 connects directly to why Kubernetes
namespaces and Git repository conventions matter later — a good moment to name that connection
without going deep yet.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
@@ -0,0 +1,52 @@
# Files and Text
## Basic file operations
- `touch <file>` — create an empty file (or update its timestamp if it exists)
- `mkdir <dir>` — create a directory (`-p` creates any missing parent directories too)
- `cp <src> <dst>` — copy a file
- `mv <src> <dst>` — move OR rename a file (Linux treats renaming as "moving to a new name in
the same place")
- `rm <file>` — delete a file (`-r` for a directory, `-f` to skip confirmation — dangerous
combined: `rm -rf` deletes without asking, permanently)
## Reading text
- `cat <file>` — print the whole file at once
- `less <file>` — page through a file interactively (press `q` to quit) — the right tool for
anything too long to read in one screen
- `head <file>` / `tail <file>` — the first/last 10 lines by default (`-n 20` for a different
count); `tail -f` follows a file live as new lines are appended — exactly how you'd watch a
log file update in real time
## Searching text: `grep`
`grep PATTERN file` prints only the lines matching PATTERN. This is one of the most-used
commands in real operations work — "find the lines that matter" beats "read everything."
## Pipes and redirection: composing commands
- **A pipe (`|`)** sends one command's output as the next command's input:
`cat app.log | grep ERROR` — read the file, then filter it.
- **Redirection (`>`)** sends a command's output into a file instead of the screen (overwriting
it): `grep ERROR app.log > errors.txt`. `>>` appends instead of overwriting.
## stdout vs. stderr
A command actually has TWO separate output streams: **stdout** (normal output) and **stderr**
(error messages), even though both print to your screen by default. This is why
`command 2>/dev/null` (redirecting stream `2`, stderr, to nowhere) can suppress error noise
while still showing normal output — you'll use exactly this pattern in later Labs.
## Instructor Notes
**Lesson goal:** Build real fluency composing small commands together — this is the single
highest-leverage Linux skill for troubleshooting work later in ROOT_.
**Approximate timing:** 15 minutes read; 10 minutes live.
**Common misconception to watch for:** students often don't realize stdout/stderr are separate
streams until they see `2>/dev/null` change what's suppressed — worth demonstrating live.
**Demo idea:** run a command that produces both real output and an error in the same call
(e.g. `ls /etc /nonexistent`) and show how `2>/dev/null` changes what appears.
@@ -0,0 +1,56 @@
# Demonstration: Filtering a Log Down to What Matters
## OBSERVE
A raw log file has five lines mixing `INFO` and `ERROR`:
```
$ cat app.log
INFO: boot ok
ERROR: disk full
INFO: retry
ERROR: timeout
INFO: done
```
## HYPOTHESIS
Predict what `grep ERROR app.log` will print, before running it.
## INSPECT
```
$ grep ERROR app.log
ERROR: disk full
ERROR: timeout
```
Only the matching lines — everything else is filtered out.
## CHANGE
Now redirect that filtered result into a new file instead of just viewing it:
```
$ grep ERROR app.log > errors.txt
$ cat errors.txt
ERROR: disk full
ERROR: timeout
```
## VERIFY
Count how many lines actually matched, without eyeballing them: `wc -l < errors.txt` (or
`grep -c ERROR app.log` directly). This composition — filter, then count, then act — is the
exact shape of a huge share of real troubleshooting work.
## Instructor Notes
**Demo goal:** Show the filter → redirect → verify chain as one continuous, composable
workflow, not three unrelated commands.
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** using `>` when they meant `>>` and accidentally overwriting a
file they wanted to append to — worth calling out explicitly since it's a real, common mistake
with no undo.
@@ -0,0 +1,37 @@
# Knowledge Check: Files and Text
---
**1. What's the difference between `>` and `>>`?**
*Answer:* `>` overwrites the target file's contents entirely; `>>` appends to the end of it,
preserving what was already there.
---
**2. A command prints both normal output and an error message. What are these two streams
called?**
*Answer:* stdout (normal output) and stderr (error messages) — two separate streams that both
happen to print to your screen by default.
---
**3. You want to watch a log file update live, as new lines are appended, without re-running a
command repeatedly.**
*Answer:* `tail -f <file>` — follows the file and prints new lines as they're written.
---
**4. `cat app.log | grep ERROR`. What does the `|` actually do?**
*Answer:* It pipes `cat`'s output directly into `grep`'s input, so `grep` filters the file's
contents without needing a separate temporary file.
## Instructor Notes
**Facilitation:** Question 2 is worth a live show-of-hands check — many students haven't
consciously registered that stdout/stderr are separate until this module.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,31 @@
# Guided Exercise: Which Tool Actually Answers the Question?
This is a paper exercise — commit to an answer before checking it in the Lab.
## Your task
For each situation, name the ONE command (or short pipeline) you'd reach for first:
1. You want to see just the last 20 lines of a 50,000-line log file.
2. You want to know how many lines in a file contain the word "timeout."
3. You want to watch a log file update live while a process is running.
4. You want to see a file's full contents but it's too long for one screen and you want to
scroll through it interactively.
## A worked shape to check yourself against
1. `tail -n 20 file.log`
2. `grep -c timeout file.log`
3. `tail -f file.log`
4. `less file.log`
Notice: `cat` would technically "work" for #4 too, but it dumps everything at once with no way
to scroll back — `less` is the actual right tool once a file is longer than one screen.
## Instructor Notes
**Facilitation:** Item 4 is worth discussing explicitly — "it works" isn't the same bar as
"it's the right tool for this situation," and that distinction matters more as commands compose
into real troubleshooting workflows.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced.
@@ -0,0 +1,26 @@
# Reflection: Filtering Is a Reasoning Skill, Not a Syntax Trick
## Reflection questions
1. Before this module, how would you have found "the important lines" in a huge log file?
How does that compare to `grep`?
2. Which combination (pipe, redirect, or a specific command like `tail -f`) do you expect to
use the most once you're doing real troubleshooting work?
## Real Ops takeaway
**"Read everything and eyeball it" does not scale — filtering does.** Every troubleshooting
framework you'll learn later in ROOT_ (starting with ROOT 02's own version, then again more
formally in ROOT 10) depends on being able to quickly narrow a huge amount of system output down
to the handful of lines that actually matter. `grep`, pipes, and redirection are the first real
tools you have for that — not a syntax exercise, a reasoning skill.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 1 often produces good answers ("I'd
just scroll and read") that make the value of filtering obvious by contrast — let students
articulate this themselves rather than stating it for them.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
@@ -0,0 +1,64 @@
# Processes
## What a process actually is
A **process** is a running instance of a program — its own code, its own private memory, and a
unique identifier the kernel tracks called a **PID** (Process ID). Run the same program twice
(open two terminals both running `bash`), and you get two separate processes with two different
PIDs, even though they're running identical code.
## Foreground vs. background
A command you run normally occupies your terminal until it finishes (**foreground**) — you
can't type anything else until it's done. Append `&` to run it in the **background** instead,
freeing your terminal immediately while the process keeps running. `sleep 300 &` starts a
300-second sleep in the background and hands your prompt right back.
## Inspecting processes: `ps` and `top`
- `ps aux` — a snapshot of every process currently running, including its PID, how much CPU/
memory it's using, and the exact command that started it.
- `top` (or `htop`, if installed) — the same idea, but live-updating and sorted by resource
usage, useful for "what's actually eating CPU/memory right now."
## Stopping a process: `kill` and signals
`kill <PID>` doesn't instantly destroy a process — it sends it a **signal**, a message the
process can (usually) choose how to respond to. The default signal, `SIGTERM` (15), politely
asks a process to shut down, giving it a chance to clean up first. `kill -9 <PID>` sends
`SIGKILL`, which the kernel enforces immediately with no chance for the process to react —
appropriate only when a process is truly stuck and ignoring `SIGTERM`. `kill -0 <PID>` is a
special case: it sends NO real signal at all, just checks whether the PID still exists —
exactly how you confirm "did that process actually stop" without side effects.
## Process hierarchy
Every process (except the very first one at boot) has a **parent** — the process that started
it. Your shell is the parent of every command you run from it. This matters later: a parent
process's own lifecycle can affect its children (this is part of why a container, which is
often just one process tree, behaves the way it does when its main process exits).
## Why this matters for containers and Kubernetes
A container is, underneath, mostly an isolated process (or small process tree) with its own
view of the filesystem and network — when people say "a container exited," they mean its main
process exited, exactly the same event you'll cause on purpose in this module's Lab. Kubernetes'
entire job, at its core, is deciding which machine a process (inside a container) runs on and
restarting it if it dies unexpectedly — none of that will feel intuitive without this module's
model of what a process actually is.
## Instructor Notes
**Lesson goal:** Build a real process mental model (PID, foreground/background, signals,
parent/child) that ROOT 04 (containers) and ROOT 06 (Kubernetes workloads) both directly build
on without re-explaining.
**Approximate timing:** 15 minutes read; 10 minutes live.
**Common misconception to watch for:** students often think `kill` always means "forcefully
destroy" — clarify that plain `kill` sends a polite, ignorable request (SIGTERM), and `-9` is
the forceful escalation, not the default.
**Discussion question:** "What do you think happens to a container if its main process exits on
its own, versus if something outside kills it?" (Don't need a complete answer yet — just plant
the question for later.)
@@ -0,0 +1,53 @@
# Demonstration: Watching a Process Actually Terminate
## OBSERVE
Start a long-running background process and note its PID:
```
$ sleep 300 &
[1] 1421
```
`1421` is the PID (yours will differ every time).
## HYPOTHESIS
Predict: will `kill -0 1421` print anything if the process is still running?
## INSPECT
```
$ kill -0 1421 && echo "still running"
still running
```
`kill -0` sends no real signal — silence (or, here, our own `echo`) means the process exists.
## CHANGE
Now actually terminate it:
```
$ kill 1421
```
## VERIFY
```
$ kill -0 1421 2>/dev/null && echo "still running" || echo "gone"
gone
```
The exact same check now reports the opposite result — real, observable proof the process is
gone, not an assumption.
## Instructor Notes
**Demo goal:** Make "checking before and after" a visible habit, not just narrated — students
should see the SAME command return a different real answer once state actually changed.
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** reaching for `kill -9` by default "to be safe" — reinforce that
plain `kill` (SIGTERM) is the correct first attempt almost always.
@@ -0,0 +1,38 @@
# Knowledge Check: Processes
---
**1. What does a PID identify?**
*Answer:* One specific running instance of a program — the kernel's unique identifier for that
process, distinct from every other running process, even other copies of the same program.
---
**2. What's the actual difference between `kill <pid>` and `kill -9 <pid>`?**
*Answer:* Plain `kill` sends SIGTERM, a polite request the process can choose to handle (clean
up, then exit). `kill -9` sends SIGKILL, which the kernel enforces immediately with no chance
for the process to react — an escalation for when SIGTERM is ignored, not the default choice.
---
**3. You want to confirm a process is still running WITHOUT affecting it in any way. What do
you use?**
*Answer:* `kill -0 <pid>` — sends no real signal, only checks whether the PID still exists.
---
**4. Why might understanding processes matter for understanding containers later?**
*Answer:* A container is, underneath, mostly an isolated process (or small process tree) — a
container "exiting" is really its main process exiting, the exact same event this module's Lab
causes on purpose.
## Instructor Notes
**Facilitation:** Question 2 is worth confirming explicitly — "kill -9 by default" is a common,
worth-correcting habit.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,28 @@
# Guided Exercise: Choosing the Right Signal
This is a paper exercise — commit to an answer before checking it in the Lab.
## Your task
For each situation, decide: plain `kill` (SIGTERM) first, or is `kill -9` (SIGKILL) actually
justified?
1. A normal web server process you want to shut down for a routine restart.
2. A process that received SIGTERM two minutes ago and is still running, showing no signs of
responding.
3. A script you just started by mistake, that hasn't done anything harmful yet.
## A worked shape to check yourself against
1. Plain `kill` — give it the chance to shut down cleanly (close connections, flush data, etc).
2. `kill -9` is now justified — you already gave it the polite chance, and it didn't respond.
3. Plain `kill` first, still — "just started" doesn't change the default; SIGKILL is a last
resort, not a shortcut for convenience.
## Instructor Notes
**Facilitation:** Item 3 sometimes trips students who reach for `-9` out of impatience — worth
reinforcing that SIGTERM-first is the discipline REGARDLESS of urgency, since a process that
ignores SIGTERM is the actual signal that escalation is warranted.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced.
@@ -0,0 +1,27 @@
# Reflection: You Just Stopped a Real Process, Not a Simulation
## Reflection questions
1. Before checking `kill -0` after your `kill`, how confident were you the process was
actually gone? What would you have done if it hadn't stopped?
2. Why do you think SIGTERM-before-SIGKILL matters more for a real production service than for
a throwaway script in a Lab?
## Real Ops takeaway
**"I ran the kill command" is not the same as "I confirmed the process is gone."** This module's
Lab required you to verify state, not just take an action and assume it worked — that
verification step is exactly what separates a confident operator from someone hoping for the
best. You'll repeat this exact pattern (act, then verify) constantly for the rest of ROOT_,
starting as soon as ROOT 04's containers and continuing all the way through Kubernetes
troubleshooting.
This module is complete. Continue to the next module.
## Instructor Notes
**Discussion questions for a live classroom:** question 2 is a good bridge to ROOT 06's later
discussion of graceful shutdown/`terminationGracePeriodSeconds` — plant the idea now without
naming Kubernetes specifics yet.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
@@ -0,0 +1,59 @@
# Users and Permissions Foundations
## Users, groups, and ownership
Every file on Linux has an **owner** (a user) and a **group**. `ls -la` shows both: the third
column is the owning user, the fourth is the owning group. Multiple users can belong to the same
group, which is how permissions get shared across a team without giving every individual user
direct ownership.
## Read, write, execute — for three different audiences
Every file has permissions for THREE separate audiences: the owner, the group, and everyone
else ("other"). Each audience gets some combination of:
- **r**ead — can view the file's contents (or list a directory's contents)
- **w**rite — can modify the file (or create/delete files inside a directory)
- e**x**ecute — can run the file as a program (or enter/traverse into a directory)
`ls -la` shows this as a 10-character string like `-rw-r--r--`: the first character is the file
type, then three groups of `rwx` for owner/group/other.
## Reading and setting permissions as octal numbers
Each `rwx` triplet can be written as one digit: read=4, write=2, execute=1, summed together.
`rw-` = 4+2 = `6`. `r--` = `4`. So `644` means: owner can read+write (6), group can read-only
(4), everyone else can read-only (4) — a very common, sensible default for a regular file.
`chmod 644 <file>` sets exactly that.
## `sudo`: temporary elevated privilege
Rather than logging in AS the root user (with permanent full access to everything), `sudo
<command>` runs just that one command with elevated privileges, after checking you're allowed
to. This is deliberate: the less time you spend with full privileges, the smaller the window for
a mistake (or a compromised session) to do serious damage — the exact same reasoning behind
"least privilege," which this module introduces by name for the first time.
## Least privilege: the principle, not just the command
**Least privilege** means: grant exactly the access something needs to do its job, and nothing
more. A user who only needs to read a file shouldn't also be able to write it. A process that
only needs to read one directory shouldn't have write access to the whole filesystem. This
principle isn't specific to Linux permissions — you'll meet it again, in a much more elaborate
form, in ROOT 09's Kubernetes RBAC and SecurityContext content. This module is where it starts.
## Instructor Notes
**Lesson goal:** Build real fluency with rwx/octal permissions AND plant the least-privilege
PRINCIPLE explicitly — not just command syntax, since ROOT 09 depends on students already
having this vocabulary.
**Approximate timing:** 15 minutes read; 10 minutes live.
**Common misconception to watch for:** students often memorize "644 = read/write" without being
able to derive it from 4+2+1 — walk through the arithmetic explicitly rather than treating the
numbers as magic.
**Discussion question:** "Why not just make everything readable and writable by everyone, to
avoid permission headaches?" (Good setup for the least-privilege principle — let students
generate the security argument themselves before you confirm it.)
@@ -0,0 +1,55 @@
# Demonstration: A Real Permission Denial, and the Real Fix
## OBSERVE
A file is owned by root with permissions `600` (owner read/write only):
```
$ stat -c '%a %U' data.txt
600 root
```
## HYPOTHESIS
Predict: can a different, non-root user read this file?
## INSPECT
```
$ su - labuser -c "cat data.txt"
cat: data.txt: Permission denied
```
Confirmed — `600` grants nothing to group or other, so `labuser` (neither the owner nor root)
is correctly denied.
## CHANGE
Grant read access to everyone, while keeping write access limited to the owner:
```
$ chmod 644 data.txt
$ stat -c '%a' data.txt
644
```
## VERIFY
```
$ su - labuser -c "cat data.txt"
sensitive
```
The exact same command that failed before now succeeds — the permission bits, not the file's
actual content, were the only thing that changed.
## Instructor Notes
**Demo goal:** Show a permission denial as a real, reproducible fact (not just a described
error message) and the exact minimal fix, not an overcorrection like `chmod 777`.
**Approximate timing:** 8 minutes live.
**Common mistake to watch for:** students reaching for `chmod 777` "to make the error go away"
— explicitly name why that's wrong (it also grants WRITE to everyone, not just the read access
actually needed) and connect it back to least privilege.
@@ -0,0 +1,38 @@
# Knowledge Check: Users and Permissions Foundations
---
**1. A colleague says "permission denied" and fixes it with `chmod 777`. What's wrong with
that fix?**
*Answer:* `777` grants read, write, AND execute to the owner, group, AND everyone else — almost
always far more access than the actual problem required. It "fixes" the symptom while violating
least privilege, usually granting write access nobody asked for.
---
**2. What does the permission `644` actually mean, broken down?**
*Answer:* Owner: read+write (4+2=6). Group: read-only (4). Other: read-only (4). Nobody but the
owner can modify the file; everyone can read it.
---
**3. Why does `sudo <command>` exist instead of just logging in as root permanently?**
*Answer:* It grants elevated privilege only for the one command that needs it, minimizing the
time spent with full access — reducing the chance a mistake (or a compromised session) causes
serious, wide damage.
---
**4. State the least-privilege principle in your own words.**
*Answer:* Grant exactly the access something needs to do its job, and nothing more.
## Instructor Notes
**Facilitation:** Question 1 is worth discussing as a group — most students have seen `chmod
777` somewhere online as "the fix," and unlearning that habit early matters.
**Approximate timing:** 5 minutes.
@@ -0,0 +1,32 @@
# Guided Exercise: Pick the Minimal Permission, Not the Easy One
This is a paper exercise — commit to an answer before checking it in the Lab.
## Your task
For each situation, write the exact `chmod` octal value that grants the MINIMUM permission
actually needed:
1. A private SSH key file — only the owner should ever read or write it, nobody else, no
execute for anyone.
2. A shared script every user on the system should be able to run, but only the owner should be
able to edit.
3. A log file every user should be able to read (for troubleshooting), but only a logging
service (the owner) should write to it.
## A worked shape to check yourself against
1. `600` — owner read+write (6), nothing for group or other (0, 0). This is the real, standard
permission for private SSH keys — SSH itself refuses to use a key file that's more open than
this.
2. `755` — owner read+write+execute (7), group and other read+execute (5, 5) so they can run it
but not modify it.
3. `644` — owner read+write (6), group and other read-only (4, 4).
## Instructor Notes
**Facilitation:** Item 1 is a good moment to mention that this isn't a hypothetical rule — SSH
genuinely refuses to use an overly-permissive private key file, a real-world consequence of
exactly this principle.
**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced.
@@ -0,0 +1,33 @@
# Reflection: Least Privilege Is a Habit, Not a One-Time Fix
## Reflection questions
1. Before this module, what would you have done the first time you hit a "permission denied"
error? How does that compare to what you'd do now?
2. Name one place outside of file permissions where you'd expect "grant only what's needed" to
matter (a user account, an API key, a service's network access — anything).
## Real Ops takeaway
**Least privilege is the single idea from this entire module that reappears the most across
the rest of ROOT_.** File permissions are just the first, most concrete place you'll apply it —
ROOT 09 applies the exact same principle to Kubernetes RBAC (what can a user or workload
actually DO) and SecurityContext (what can a container actually access). Getting comfortable
asking "what's the minimum this actually needs" now, on a file you can see and touch, makes that
same question much easier to ask later about something more abstract, like a ServiceAccount's
permissions.
This module is complete. This is the end of ROOT 01 — continue to ROOT 02: Linux
Administration & Networking.
## Instructor Notes
**Discussion questions for a live classroom:** question 2 works well as a round-robin — the
variety of answers (API keys, database credentials, network firewall rules) is itself useful
evidence of how far this one principle travels.
**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing.
**Milestone note:** this is the last module of ROOT 01 — consider a short recap of the whole
course's arc (hardware → shell → filesystem → files/text → processes → permissions) before
moving on, so students see it as one coherent foundation rather than six separate topics.