mirror of
https://github.com/foo-dogsquared/wiki.git
synced 2025-01-31 10:58:28 +00:00
195 lines
6.4 KiB
Org Mode
195 lines
6.4 KiB
Org Mode
#+title: Exploring systemd features
|
|
#+date: "2021-05-20 22:37:22 +08:00"
|
|
#+date_modified: "2021-06-19 15:07:52 +08:00"
|
|
#+language: en
|
|
#+property: header-args :eval no
|
|
|
|
|
|
systemd is a big tool for a big system.
|
|
Let's explore some of them from a perspective of a wannabe power user.
|
|
|
|
|
|
|
|
|
|
* systemd at user-level
|
|
|
|
systemd has the ability to run at user-level empowering the user to manage their own system with their own settings.
|
|
It immensely helps separating user-specific settings from the system-wide settings.
|
|
|
|
systemd looks for the units from certain paths.
|
|
You can look for them from the =systemd.unit.5= manual page.
|
|
|
|
To run systemd as a user instance, simply add a =--user= flag beforehand for =systemctl= and other systemd binaries, if applicable.
|
|
|
|
#+begin_src shell :results none
|
|
# See how different the output when run at user- and system-level.
|
|
systemctl --user show-units
|
|
systemctl show-units
|
|
|
|
systemctl --user show-environment
|
|
systemctl show-environment
|
|
|
|
systemctl --user start $SERVICE
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* Timers as cron replacement
|
|
|
|
You can schedule tasks with timers.
|
|
If systemd is compiled with the feature, it makes cron unnecessary.
|
|
|
|
systemd has different ways to denote time.
|
|
|
|
- Timespans denote the duration — e.g., =100 seconds=, =5M 3w=.
|
|
- Timestamps refer to a specific point in time — e.g., =2021-04-02=, =today=, =now=.
|
|
- Calendar events can refer to more than one point of time — e.g., =*-*-4/2=, =Sun,Wed,Fri *-1/2-1/8=.
|
|
|
|
Here's an example of setting a timer for an example backup service.
|
|
The following timer unit sets it to execute every day at 18:00.
|
|
|
|
#+begin_src ini
|
|
[Unit]
|
|
Description=A deduplicated backup from my computer
|
|
Documentation=man:borg(1) https://borgbackup.readthedocs.io/
|
|
|
|
[Timer]
|
|
Unit=borg-backup.service
|
|
OnCalendar=*-*-* 18:00:00
|
|
Persistent=true
|
|
|
|
[Install]
|
|
WantedBy=graphical.target
|
|
#+end_src
|
|
|
|
This will trigger =borg-backup.service= from the load path.
|
|
But you can omit it if you named the timer unit file similarly (e.g., =borg-backup.timer= with =borg-backup.service=).
|
|
|
|
You can find more information about it from the =systemd.time.5= manual page.
|
|
Furthermore, systemd has a testing tool for time with ~systemd-analyze {timespan,timestamp,calendar}~.
|
|
|
|
|
|
|
|
|
|
* Unit templates
|
|
|
|
You can create unit templates which is useful for simple services that only requires an argument.
|
|
Rather than creating individual simple service files, let systemd handle it.
|
|
|
|
For example, you may want to spawn a service for Borgmatic with multiple repos.
|
|
If you don't know templates, the dumb way to serve multiple repos is to create individual unit files for each.
|
|
If you want to schedule them, you also have to create a timer unit for each.
|
|
|
|
The more efficient solution is to use templates.
|
|
To make a unit template, there are only a handful of requirements:
|
|
|
|
- Addition of =%i= to represent the template value.
|
|
- The unit file name has to end with =@= (e.g., =unit-name@.service=, =unit-name@.timer=).
|
|
|
|
This could be compressed into a template for a service unit.
|
|
The following code shows how to create one.
|
|
|
|
#+begin_src ini
|
|
[Unit]
|
|
Description=Periodic safety backup for %i
|
|
Documentation=man:borg(1) https://www.borgbackup.org/
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=borgmatic --config %i --verbose
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
#+end_src
|
|
|
|
To use the service, you have to give it a value — e.g., ~systemctl --user start borg-backup@test.yaml.service~.
|
|
|
|
That's all good but what about scheduling them?
|
|
What if you want to create an archive every hour starting at 08:00?
|
|
You can just create a templated timer unit.
|
|
|
|
#+begin_src ini
|
|
[Unit]
|
|
Description=Periodic safety backup for %i
|
|
Documentation=man:borg(1) https://www.borgbackup.org/
|
|
|
|
[Timer]
|
|
Unit=borg-backup@%i.service
|
|
Calendar=08/1:00:00
|
|
Persistent=true
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* Transient units
|
|
|
|
You can create units on-the-go with =systemd-run=.
|
|
It generates transient unit files.
|
|
Though, this is oriented around service units, making it useful for one-time configurations and task scheduling.
|
|
|
|
Like most systemd-related binaries, this can configure in system- and user-level.
|
|
|
|
#+begin_src shell
|
|
# This will create a user-level service file with the given command as the task.
|
|
systemd-run --user borgmatic --config emergency-config.yaml --verbose
|
|
|
|
# Create a transient timer for the service.
|
|
systemd-run --user borg-backup@external-drive.service --on-calendar=12:00
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* Service management
|
|
|
|
One of the functions of the system suite is service management.
|
|
Like most of the components, it can be used at user-level with their set locations, managing the service daemon, and all.
|
|
|
|
Just plop down a service unit file at one of the search paths and you can start managing right away.
|
|
For more information, see the manual page (i.e., =systemd.service.5=).
|
|
|
|
Here's an example of a user service resided as =$HOME/.config/systemd/user/borgbackup@.service=.
|
|
|
|
#+begin_src ini
|
|
[Unit]
|
|
Description=Periodic safety backup for %i
|
|
Documentation=man:borg(1) https://www.borgbackup.org/ https://torsion.org/borgmatic/
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStartPre=%h/.nix-profile/bin/borgmatic --config %h/dotfiles/borgmatic/%i.yaml --verbosity 2 create
|
|
ExecStart=%h/.nix-profile/bin/borgmatic --config %h/dotfiles/borgmatic/%i.yaml --verbosity 2 check
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
#+end_src
|
|
|
|
There are different types of services.
|
|
|
|
- The most common type of service is =simple= which considers the unit active after the main process is forked (e.g., =Service.ExecStart=).
|
|
This is the recommended type for long-running processes.
|
|
|
|
- =oneshot= marks the service resolved after the main process exits.
|
|
Due to the behavior, it will directly go from activating to deactivating instead of active.
|
|
|
|
- =exec= considers the service active after the binary has been executed.
|
|
|
|
Aside from types, each service may have one or more commands although the behavior is set depending on the type.
|
|
|
|
- =ExecStart= which is usually the main command and most services will throw an error if it's missing.
|
|
All services, unless specified as a =oneshot= service, only have one of these values.
|
|
|
|
- =ExecStop= only executes after the main command successfully starts.
|
|
|
|
- =ExecStartPre= and =ExecStartPost= gives you additional commands that will be executed before and after the main command, respectively.
|
|
|
|
- =ExecStopPre= and =ExecStopPost= is similar to the pre- and post-start commands except for the stop command.
|
|
|
|
- =Reload= sets whether the service restarts on fail.
|
|
Values accepted are =no=, =on-failure=, and =on-success=.
|