Portal | Level: L2: Operations | Topics: systemd, Linux Fundamentals | Domain: Linux
systemd Architecture¶
Scope¶
This document explains systemd as the init system and service manager that brings a modern Linux system to life after the kernel hands off to PID 1. It covers:
- boot targets and ordering
- units and dependencies
- service types
- sockets, timers, mounts, automounts
- cgroup integration
- journald
- common debugging patterns
- boot performance analysis
Big picture¶
systemd is not just "the thing that starts services." When running as PID 1 it is the central orchestrator of userspace boot and service lifecycle.
High-level boot handoff¶
firmware
-> bootloader
-> kernel
-> initramfs / switch_root
-> PID 1 = systemd
-> generators run
-> unit graph is built
-> default target and its dependencies are queued
-> services, sockets, mounts, devices, timers, and other units activate
-> system reaches operational target
What systemd actually does¶
- tracks desired and actual unit state
- builds dependency graphs
- orders startup and shutdown
- supervises services
- manages cgroups
- integrates logging and activation mechanisms
- provides standardized interfaces for service lifecycle
It is closer to a boot-time and runtime dependency scheduler plus service supervisor than to a dumb init script runner.
What PID 1 really means¶
The PID 1 process is special on Linux: it reaps orphans/zombies, defines boot and shutdown policy, and acts as the root of service supervision.
systemd takes that role and adds dependency resolution, structured logging, cgroup integration, socket activation, on-demand startup, transient units, resource control, and isolation features.
If PID 1 is broken, the machine is broken in a very literal sense.
flowchart TD
SYS["sysinit.target\nMounts, swap, udev\njournald, tmpfiles"] --> BAS["basic.target\nSockets, timers, paths\nOS plumbing ready"]
BAS --> MU["multi-user.target\nNetwork, SSH, services\nNon-graphical login"]
MU --> GR["graphical.target\nDisplay manager\nDesktop session"]
SYS --> |"early"| journald["journald.service"]
SYS --> |"early"| udev["udev.service"]
BAS --> |"plumbing"| sockets["sockets.target"]
BAS --> |"plumbing"| timers["timers.target"]
MU --> |"services"| sshd["sshd.service"]
MU --> |"services"| net["network.target"]
GR --> |"desktop"| dm["display-manager.service"]
style SYS fill:#4a6fa5,color:#fff
style BAS fill:#6b8cae,color:#fff
style MU fill:#f0ad4e,color:#333
style GR fill:#5cb85c,color:#fff
Unit types¶
A unit is a configuration object representing something systemd can manage.
Common unit types:
.service- daemon or one-shot work.socket- socket activation.target- synchronization / grouping point.mount- filesystem mount.automount- on-demand mount trigger.timer- scheduled activation.path- activate on filesystem events.device- kernel device exposure.slice- cgroup hierarchy partition.scope- externally created processes tracked by systemd.swap- swap device/file.tmpfiles/ generators / other helpers exist around the ecosystem
Key point¶
A target is not a runlevel clone in the simplistic sense. It is a dependency grouping point in a graph.
Dependencies vs ordering¶
This distinction causes endless confusion.
Requirement dependency¶
Examples:
Requires=Wants=BindsTo=PartOf=
These define relationship strength: what should come along or what failing units affect others.
Ordering dependency¶
Examples:
Before=After=
These define sequence, not requirement.
Important truth¶
After=network.target does not mean "make sure networking is really usable." It only means order after that target's activation event. Wrong mental model here creates a lot of boot bugs.
Boot transaction¶
At boot, systemd computes a transaction: the set of units to activate to reach the desired target while respecting dependencies and ordering rules.
It then starts as much as possible in parallel, constrained by those rules.
This is why modern boot is faster than old serial init script chains. systemd is graph-based, not a giant linear shell script.
When you request a unit start, systemd builds a transaction: pulls in requirements, validates conflicts, orders work, merges with current state, and rejects impossible operations. The graph, not the command line, is the truth.
Boot stages and special targets¶
Important targets and milestones include:
sysinit.target- early system initializationbasic.target- basic system initialization complete enough for broader startupmulti-user.target- non-graphical multi-user modegraphical.target- graphical login / desktop environment pathrescue.targetemergency.targetshutdown.target
Simplified boot flow¶
Real graphs are more complex, but this is the useful admin mental model.
Generators¶
Generators are small programs run early by systemd to dynamically produce unit files or symlinks based on current system state.
Examples of what generators handle:
- fstab conversion into mount units
- cryptsetup-derived units
- system update redirection
- initrd-specific logic
Why generators matter¶
The final runtime unit graph is not always just what sits statically in /etc/systemd/system and /usr/lib/systemd/system. Dynamic generation changes the graph.
Service unit types¶
A .service unit can represent different startup semantics.
Common Type= values:
simpleexecforkingoneshotnotifydbus
Why type matters¶
systemd needs to know when to consider startup successful and how to supervise the process.
Examples:
Type=simpleassumes the main process is the launched commandType=forkingis for old daemons that background themselvesType=notifywaits for explicit readiness signal from the serviceType=oneshotis for finite tasks
Misusing Type= is a classic cause of fake-success startups or broken dependency timing.
Socket activation¶
systemd can create listening sockets first and only start the service when traffic arrives.
Benefits:
- on-demand startup
- reduced boot-time work
- service restart without losing listen socket in some models
- compatibility with superserver-like patterns
This is one of the reasons systemd is more than a service runner.
Timer units vs cron¶
Timers are systemd's native scheduled activation mechanism.
Advantages over classic cron for many use cases:
- dependency-aware activation
- journal integration
- missed-run persistence with
Persistent= - standard unit semantics
- easy introspection with
systemctl list-timers
Cron still exists, but timers are usually cleaner on systemd-managed hosts.
Mount and automount units¶
Mounts are first-class managed units. This allows:
- boot ordering around filesystems
- failure propagation
- automount-on-access behavior
- consistent dependency handling
This matters a lot for network filesystems and slow mounts that would otherwise stall boot.
cgroups and resource management¶
Modern systemd uses cgroups as its process tracking and resource control foundation.
Why this matters¶
systemd can reliably know which processes belong to a service because they live in that service's cgroup.
This avoids many old init-script problems where child processes escaped supervision like greased raccoons.
Resource controls¶
systemd can set limits such as:
- CPU weight/quota
- memory ceilings
- IO weight/throttling
- task limits
It effectively acts as a cgroup manager for services and slices.
Slices¶
Slices organize cgroup hierarchy, for example:
system.sliceuser.slice- custom slices for workload grouping
Journald¶
systemd-journald provides structured log collection for local services and kernel/user logs.
Why it matters¶
- service logs correlate to unit identity
- boot logs can be queried by boot ID
- metadata-rich searching is possible
- journal and classic syslog can coexist depending on setup
Useful commands:
journalctl -bjournalctl -u sshdjournalctl -xejournalctl -k
Operational caution¶
The journal is great for investigation, but retention, forwarding, and durability choices still matter. Local logs alone are not your observability strategy.
Activation states¶
Units can be in states like:
- inactive
- activating
- active
- deactivating
- failed
There are also substate details that matter for services.
Key point: "loaded" only means the unit definition is known, not that the service is running.
Enable vs start¶
Another evergreen confusion.
systemctl start foo-> activate nowsystemctl enable foo-> make it start automatically via symlink-based dependency wiringsystemctl enable --now foo-> both
If someone says a service is "enabled" that does not prove it is currently running.
Boot performance analysis¶
systemd-analyze provides boot performance introspection.
Useful commands:
systemd-analyzesystemd-analyze blamesystemd-analyze critical-chain
blame¶
Shows units sorted by reported initialization time. Useful, but can mislead because waiting time and real boot criticality are not identical.
critical-chain¶
Shows the ordering chain that actually determined when a target was reached. This is often more useful than blaming the longest individual unit.
Service supervision and restart logic¶
A service can specify policies such as:
Restart=RestartSec=- watchdog integration
- start rate limits
This is powerful but also dangerous if abused. A misconfigured restart loop can thrash boot or flood logs.
Shutdown flow¶
systemd also orchestrates shutdown:
- reverse dependency order
- stop units
- unmount filesystems
- tear down swap
- reach shutdown/reboot/poweroff targets
Clean shutdown is not just "kill everything and pray."
Common failure patterns¶
1. Service starts manually but not at boot¶
Possible reasons:
- not enabled
- wrong target wiring
- ordering issue
- dependency failed at boot
- environment difference between boot and interactive shell
2. Service marked active too early¶
Usually:
- wrong
Type= - app daemonizes unexpectedly
- missing
sd_notify()usage forType=notify
3. Boot slow because of a mount or network wait¶
Common causes:
- remote mount blocking boot
network-online.targetmisunderstanding- slow device timeout
- dependency chain accidentally serialized
4. Service restarts forever¶
Could be:
Restart=always- failing dependency
- bad config
- permissions issue
- missing secret or socket
5. Logs missing or fragmented¶
Could be:
- journal volatility / retention behavior
- service writes elsewhere
- stdout/stderr redirection assumptions wrong
- chroot/containerized execution differences
Debugging workflow¶
Step 1 - inspect unit status¶
systemctl status <unit>
This gives:
- active state
- recent logs
- main PID
- result reason
- unit file path
Step 2 - inspect journal for that unit¶
journalctl -u <unit> -b
Use boot scoping aggressively.
Step 3 - inspect unit definition and overrides¶
systemctl cat <unit>systemctl show <unit>- look for drop-ins under
/etc/systemd/system/<unit>.d/
Step 4 - inspect dependencies¶
systemctl list-dependencies <unit>systemd-analyze critical-chain <unit>
Step 5 - inspect cgroup/process behavior¶
systemctl statussystemd-cglssystemd-cgtop
Interview angles¶
Questions often hidden here:
- difference between
Requires=andAfter= - what
systemdgains from cgroups - difference between start and enable
- what
Type=notifysolves - socket activation purpose
- why
systemd-analyze blamecan mislead - what a target is
- how timers differ from cron
- why
network.targetis not "network fully ready"
Strong answers focus on dependency graph + supervision + cgroups.
Mental model to keep¶
systemd is a dependency graph executor and service supervisor for userspace.
It:
- receives control after kernel/initramfs handoff
- builds a unit graph
- activates targets and dependencies in parallel where possible
- tracks services by cgroups
- supervises lifecycle
- integrates logging and activation mechanisms
- manages orderly shutdown
If boot or service management is broken, the question is usually:
- what unit relationship, readiness signal, or resource policy was modeled wrong?
References¶
- bootup(7)
- systemd(1)
- systemd.special(7)
- systemd.unit(5)
- systemd.service(5)
- systemd.timer(5)
- systemd.exec(5)
- systemd.resource-control(5)
- systemd-analyze(1)
- systemctl(1)
Fast mental model¶
Or simpler: kernel gets you to PID 1; systemd gets you to a working operating system.
Wiki Navigation¶
Prerequisites¶
- Linux Ops (Topic Pack, L0)
Related Content¶
- Deep Dive: Linux Boot Sequence (deep_dive, L2) — Linux Fundamentals, systemd
- Deep Dive: Systemd Timers Journald Cgroups and Resource Control (deep_dive, L2) — Linux Fundamentals, systemd
- LPIC / LFCS Exam Preparation (Topic Pack, L2) — Linux Fundamentals, systemd
- Linux Boot Process (Topic Pack, L1) — Linux Fundamentals, systemd
- Linux Logging (Topic Pack, L1) — Linux Fundamentals, systemd
- Linux Ops (Topic Pack, L0) — Linux Fundamentals, systemd
- Ops Archaeology: The Service That Won't Start (Case Study, L1) — Linux Fundamentals, systemd
- RHCE (EX294) Exam Preparation (Topic Pack, L2) — Linux Fundamentals, systemd
- Skillcheck: Linux Fundamentals (Assessment, L0) — Linux Fundamentals, systemd
- systemctl & journalctl Deep Dive (Topic Pack, L1) — Linux Fundamentals, systemd
Pages that link here¶
- Cron & Job Scheduling - Primer
- LPIC / LFCS Exam Preparation — Primer
- Linux Boot Process
- Linux Boot Process — Primer
- Linux Boot Sequence - From Power-On to Full Boot
- Linux Fundamentals - Skill Check
- Linux Logging
- Linux Logging — Primer
- Ops Archaeology: The Service That Won't Start
- Primer
- RHCE (EX294) Exam Preparation — Primer
- Runbook: Systemd Service Crash Loop
- Symptoms
- systemctl & journalctl Deep Dive
- systemctl & journalctl Primer