DevOps01. Linux & Foundations·EXPERT·9 min read
1. Linux Administration
Linux Administration
TL;DR
- The Linux OS layer (filesystem, processes, systemd, permissions, package management) underlies every orchestration platform and CI/CD pipeline — production incidents are diagnosed fastest at this layer, not at the abstraction on top of it.
- A filesystem can be “full” (
df -h) for three distinct reasons: block exhaustion, inode exhaustion (df -i), or space held by a deleted-but-open file (lsof | grep deleted) — each needs a different fix. - A zombie process (Z state) is a dead process whose exit status hasn’t been reaped by its parent; it cannot be killed directly and consumes no real resources. A D-state process is blocked on I/O and inflates load average without inflating CPU%.
systemd+journalctlis the primary service-management and log-triage toolchain;StartLimitBurst/StartLimitIntervalSeccaps crash-loop restarts.chmod 777is a near-automatic security-review finding; a dedicated group with setgid (2770) is the correct pattern for shared write access.- Package pinning (
apt-mark hold,yum versionlock) must happen at the package-manager level to survive unattended upgrades — avoiding a manual upgrade command isn’t sufficient.
Core Concepts
Filesystem: blocks, inodes, and deleted-but-open files
The filesystem is a tree, but two operational details matter more than the tree structure itself:
- Inodes vs. data blocks: a filesystem tracks free space in two independent pools — data blocks and inodes (metadata structures, one per file). A directory tree with millions of tiny files can exhaust inodes while blocks still show free space.
df -hreports block usage only;df -ireports inode usage, and it is the only command that reveals inode exhaustion. - Deleted-but-open files: on Unix filesystems, a file’s data isn’t freed until both its directory entry is removed and its last open file descriptor is closed. A process that has a file open when it’s deleted (e.g., a log file removed by a cleanup job while the writing process is still running) keeps consuming disk space invisibly.
duwalks the directory tree and cannot see the file (no directory entry exists), butdfstill counts the space against the filesystem, so the two disagree.lsof +L1(orlsof | grep deleted) lists open files with a link count of 0 — the direct way to find the process holding the space, which is freed only when that process closes the descriptor or is restarted.
Process lifecycle and states
- Zombie (Z): the process has exited and released its resources, but its entry remains in the process table until the parent calls
wait()/waitpid()to collect the exit status. A zombie is not consuming CPU or memory beyond a table slot; it cannot be killed withkill -9because it is already dead — the fix targets the parent (fixing its signal handling, or restarting/killing the parent soinit/systemdreparents and reaps the zombie). - Uninterruptible sleep (D): the process is blocked on a low-level I/O operation (disk, some NFS calls) and cannot be interrupted by signals, including
SIGKILL, until the I/O completes or times out. Many D-state processes are the direct explanation for a load average that looks high relative to CPU usage. - Load average counts both runnable processes and uninterruptible-sleep processes over 1/5/15-minute windows. A high load average with moderate CPU% in
topis the classic signature of an I/O bottleneck, not a CPU capacity problem —iostator the%wacolumn intopconfirms it.
systemd service management and log triage
systemd is the init system and service manager on most modern distributions. Core operational commands:
systemctl status <service>— quick health snapshot (active/failed/state, recent log lines, main PID).journalctl -u <service> -f— live tail of a unit’s logs.journalctl -u <service> --since "10 min ago"— recent history without tailing.- Unit-file restart control:
Restart=on-failure,RestartSec=, and criticallyStartLimitBurst=/StartLimitIntervalSec=, which cap how many restart attempts are allowed within a time window. Without a sane limit, a broken deploy can crash-loop indefinitely, hammering the host and any downstream dependency it calls on each restart attempt, instead of systemd giving up and reporting a clear failed state.
Users, groups, and permissions
The rwx model is simple in isolation but requires care for shared access:
chmod 777grants read/write/execute to owner, group, and all other users — any local account or compromised process on the host gains full access to the directory’s contents. This is flagged in virtually every security review because it removes any access boundary at all.- The correct pattern for a directory that a specific team needs shared write access to is a dedicated group plus the setgid bit (
chmod 2770 dir): setgid on a directory makes new files/subdirectories inherit the directory’s group automatically, and770restricts read/write/execute to the owner and that group only — narrower and auditable, while still functionally supporting shared writes. umaskcontrols default permission bits for newly created files/directories and interacts with setgid-based directory schemes; worth checking when new files unexpectedly land with the wrong group-write bit.
Package management and version pinning
apt/dpkg (Debian/Ubuntu) and yum/dnf/rpm (RHEL/CentOS/Fedora) manage installed software and dependencies. The operational risk they introduce is an unattended or routine upgrade silently bumping a package whose exact version a service depends on for compatibility.
- Debian/Ubuntu:
apt-mark hold <package>prevents the package manager (includingunattended-upgrades) from upgrading it until unheld withapt-mark unhold. - RHEL/CentOS:
yum versionlock add <package>(via theversionlockplugin) achieves the same effect. - Pinning must happen at this level — relying on convention (“nobody run
apt upgradeon this box”) does not protect against automated unattended-upgrade services or a teammate running a routine patch cycle across a fleet.
Process monitoring
top/htop— live resource snapshot; sortable by CPU/memory.ps aux --sort=-%mem/--sort=-%cpu— one-shot sorted process listings, useful for scripting and non-interactive checks.- A high load average with low CPU% in either tool points to I/O wait, not a CPU shortage — adding compute does not fix a storage bottleneck.
systemd vs. SysV init
| Aspect | systemd | SysV init |
|---|---|---|
| Startup model | Parallel, dependency-graph-based | Sequential, runlevel scripts executed in order |
| Service definition | Declarative unit files (.service, .socket, etc.) |
Shell scripts in /etc/init.d/ |
| Logging | Centralized via journald/journalctl |
Scattered across /var/log/, format varies per service |
| Restart/crash handling | Built-in (Restart=, StartLimitBurst=) |
Requires custom scripting or a wrapper |
| Dependency management | Explicit (After=, Requires=, Wants=) |
Implicit, ordering via numbered symlinks (S01, S02, …) |
| Socket activation | Native (.socket units) |
Not supported natively |
Soft link vs. hard link
| Aspect | Soft (symbolic) link | Hard link |
|---|---|---|
| What it points to | A path (filename) | An inode directly |
| Cross-filesystem | Yes | No — must be on the same filesystem |
| Can link to a directory | Yes | No (in practice, disallowed on most filesystems) |
| Behavior if target deleted | Becomes a dangling link | Original inode/data persists as long as any hard link remains |
ls -l indicator |
l file type, shows -> target |
Indistinguishable from a regular file; check link count |
Command / Configuration Reference
df -h # disk usage by block, human-readable
df -i # inode usage — catches "too many small files" full disks
du -sh /* # directory sizes at top level (won't see deleted-but-open files)
lsof +L1 # files with link count 0 (deleted but still open)
lsof | grep deleted # alternate way to find deleted-but-open file handles
ps aux | grep ' Z ' # find zombie processes
ps -eo pid,ppid,stat,cmd | grep D # find processes in uninterruptible sleep
systemctl status <service> # health snapshot
journalctl -u <service> -f # live log tail
journalctl -u <service> --since "10 min ago" # recent history
systemctl restart <service> # restart a unit
# unit file:
# [Service]
# Restart=on-failure
# RestartSec=5
# StartLimitBurst=5
# StartLimitIntervalSec=60
chmod 2770 /shared/dir # setgid + rwx for owner/group, nothing for others
chgrp teamgroup /shared/dir # set the directory's group ownership
apt-mark hold <package> # pin package version (Debian/Ubuntu)
apt-mark unhold <package> # remove the pin
yum versionlock add <package> # pin package version (RHEL/CentOS)
yum versionlock delete <package>
top # live process/resource view
ps aux --sort=-%mem | head # top memory consumers
iostat -x 1 # I/O wait / device utilization, refreshed every second
Common Pitfalls
- Pitfall: A “disk full” alert is investigated with
dualone and the discrepancy againstdfis never explained. Why:duonly sees files reachable through the directory tree; a deleted-but-open file has no directory entry. Fix: Cross-checkdfagainstdu, and runlsof | grep deletedwhen they disagree. - Pitfall:
chmod 777is applied to resolve a permissions error and left in place. Why: It’s the fastest way to make an error disappear, but it removes any access boundary. Fix: Use a dedicated group with setgid (2770) scoped to the users who actually need write access. - Pitfall: A systemd service crash-loops for an extended period, hammering a downstream dependency. Why: No
StartLimitBurst/StartLimitIntervalSecwas configured, so systemd keeps retrying indefinitely. Fix: Set restart limits in the unit file so systemd gives up and reports a failed state after a bounded number of attempts. - Pitfall: A high load average is treated as a CPU capacity problem and more compute is provisioned. Why: Load average includes uninterruptible-sleep (D-state) processes, which are blocked on I/O, not CPU. Fix: Check
iostat/%wabefore assuming the CPU is the bottleneck. - Pitfall: A package believed to be “pinned” gets upgraded by an automated process anyway. Why: The pin existed only as a convention (“don’t run apt upgrade on this”), not as an actual package-manager hold/versionlock. Fix: Use
apt-mark hold/yum versionlock, which unattended-upgrade tooling itself respects.
Interview Questions
- A host shows 100% disk usage but
du -sh /*only accounts for 60% of it — walk through the investigation. — Tests whether the deleted-but-open-file mechanism (not just the symptom) is understood. - Explain the difference between a zombie process and a process stuck in D state, and what action (if any) resolves each. — Tests precise process-state knowledge versus vague familiarity.
- A load average of 8 on a 4-core box shows 20% CPU usage in
top. What’s the first hypothesis, and how is it confirmed? — Tests whether I/O wait is the immediate, correct instinct over a CPU-scaling reflex. - Why does
chmod 777get flagged in security reviews, and what’s the correct alternative for a genuinely shared directory? — Tests understanding of least-privilege sharing patterns (group + setgid) versus a blanket “never use 777” rule without an alternative. - What’s the difference between systemd’s restart handling and SysV init’s, and why does it matter operationally? — Tests whether the candidate can reason about crash-loop protection, not just recite that systemd is “newer.”
Knowledge check
6 scenario questions on this topic
Related in 01. Linux & Foundations