Generators are systemd’s way of creating unit files on the fly before any services actually start.
Let’s see a generator in action. Imagine you have a cluster of machines, and you want to start a service on every machine that has a specific IP address. You don’t want to manually create unit files on each machine. Instead, you write a generator.
Here’s a simplified my-cluster-service@.service template:
[Unit]
Description=My Cluster Service on %i
[Service]
ExecStart=/usr/local/bin/my-cluster-service --node %i
Restart=on-failure
Now, let’s write a generator script. This script will be placed at /usr/lib/systemd/system-generators/my-cluster-generator.
#!/bin/bash
# Simulate discovering nodes with a specific IP pattern
# In a real scenario, this would query a CMDB, DNS, or network scanner.
nodes=(
"192.168.1.101"
"192.168.1.102"
"192.168.1.103"
)
for node_ip in "${nodes[@]}"; do
# Output a .d directory for each node, containing a .conf file
# This will create units like my-cluster-service@192.168.1.101.service
echo "D /run/systemd/system/my-cluster-service.d/$node_ip.conf"
echo "[Unit]"
echo "Description=My Cluster Service for Node $node_ip"
echo ""
echo "[Service]"
echo "ExecStart=/usr/local/bin/my-cluster-service --node $node_ip"
done
Make the script executable: chmod +x /usr/lib/systemd/system-generators/my-cluster-generator.
Now, when systemd boots, it finds this generator. It runs the script, and the script outputs directives. For each IP address, it tells systemd to create a configuration file in /run/systemd/system/my-cluster-service.d/. Systemd then combines these generated configurations with the base template my-cluster-service@.service to create actual, runnable unit files like my-cluster-service@192.168.1.101.service.
You can then enable and start these dynamically created units:
systemctl enable my-cluster-service@192.168.1.101.service
systemctl start my-cluster-service@192.168.1.101.service
The core problem generators solve is managing dynamic environments. If your cluster configuration changes (nodes are added or removed), you don’t have to manually edit unit files. You just update your generator script (or the external data it consults), and systemd will rebuild the units on the next boot.
Generators are executed very early in the boot process, before systemd even starts parsing static unit files. They are located in specific directories: /usr/lib/systemd/system-generators/ and /etc/systemd/system-generators/. Scripts in these directories are executed in alphabetical order.
The output of a generator script is a list of directives that tell systemd how to create or modify unit files. Common directives include:
d /path/to/dir: Create a directory.f /path/to/file: Create a file.a /path/to/file: Append content to a file.e /path/to/file: Create a file or overwrite if it exists.
The generated configuration files are typically placed in /run/systemd/system/ which is a temporary filesystem. This means they are ephemeral and will be regenerated on each boot.
The most surprising true thing about generators is that they don’t create unit files from scratch in the way you might expect. Instead, they generate configuration snippets (often .conf files) that systemd then merges with existing unit templates (like .service or .timer files) using systemd’s drop-in mechanism. This allows for a powerful combination of static templates and dynamic overrides. For instance, a generator might create a file like /run/systemd/system/my-service@.d/override.conf which systemd then applies to my-service@.service.
The next concept you’ll likely encounter is how to manage the lifecycle of these dynamically generated units, especially if you need to react to changes without a full reboot.