mirror of
https://github.com/foo-dogsquared/wiki.git
synced 2025-02-26 06:19:06 +00:00

The topics I've covered so far for Linux, package managers, archiving, and learning. I also updated some formatting for other notes especially with the command line references.
411 lines
13 KiB
Org Mode
411 lines
13 KiB
Org Mode
:PROPERTIES:
|
|
:ID: 20830b22-9e55-42a6-9cef-62a1697ea63d
|
|
:END:
|
|
#+title: Exploring systemd features
|
|
#+date: "2021-05-20 22:37:22 +08:00"
|
|
#+date_modified: "2021-07-28 12:50:06 +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
|
|
:PROPERTIES:
|
|
:ID: c7edff80-6dea-47fc-8ecd-e43b5ab8fb1e
|
|
:END:
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
* systemd 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}~.
|
|
|
|
#+begin_src shell :eval yes
|
|
printf "Timespan example:\n"
|
|
printf "..............\n"
|
|
systemd-analyze timespan 4000min
|
|
printf "..............\n\n"
|
|
|
|
printf "Timestamp example:\n"
|
|
printf "..............\n"
|
|
systemd-analyze timestamp 2021-07-01
|
|
printf "..............\n\n"
|
|
|
|
printf "Calendar example:\n"
|
|
printf "..............\n"
|
|
systemd-analyze calendar "*-1/4-5 0/2:00:00"
|
|
printf "..............\n\n"
|
|
#+end_src
|
|
|
|
#+results:
|
|
#+begin_example
|
|
Timespan example:
|
|
..............
|
|
Original: 4000min
|
|
μs: 240000000000
|
|
Human: 2d 18h 40min
|
|
..............
|
|
|
|
Timestamp example:
|
|
..............
|
|
Original form: 2021-07-01
|
|
Normalized form: Thu 2021-07-01 00:00:00 PST
|
|
(in UTC): Wed 2021-06-30 16:00:00 UTC
|
|
UNIX seconds: @1625068800
|
|
From now: 2 weeks 4 days ago
|
|
..............
|
|
|
|
Calendar example:
|
|
..............
|
|
Original form: *-1/4-5 0/2:00:00
|
|
Normalized form: *-01/4-05 00/2:00:00
|
|
Next elapse: Sun 2021-09-05 00:00:00 PST
|
|
(in UTC): Sat 2021-09-04 16:00:00 UTC
|
|
From now: 1 month 16 days left
|
|
..............
|
|
|
|
#+end_example
|
|
|
|
|
|
|
|
|
|
* 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
|
|
|
|
The result should give you the generated name of the unit.
|
|
Then, they can be managed like an ordinary unit.
|
|
|
|
|
|
|
|
|
|
|
|
* 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=).
|
|
A summarized version can be found at [[Service configuration]].
|
|
|
|
Here's an example of a user service resided as =$HOME/.config/systemd/user/drive-backup.service=.
|
|
|
|
#+begin_src ini
|
|
[Unit]
|
|
Description=Periodic safety backup for my external drive
|
|
Documentation=man:borg(1) https://www.borgbackup.org/ https://torsion.org/borgmatic/
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=%h/.nix-profile/bin/borgmatic --config %h/dotfiles/borgmatic/personal-drive.yaml --verbosity 2 create
|
|
ExecStart=%h/.nix-profile/bin/borgmatic --config %h/dotfiles/borgmatic/personal-drive.yaml --verbosity 2 prune
|
|
ExecStart=%h/.nix-profile/bin/borgmatic --config %h/dotfiles/borgmatic/personal-drive.yaml --verbosity 2 check
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
#+end_src
|
|
|
|
You can then start the service with:
|
|
|
|
#+begin_src shell :eval no
|
|
systemctl --user start drive-backup.service
|
|
#+end_src
|
|
|
|
You can also stop it with the =stop= subcommand (e.g., ~systemctl --user stop drive-backup.service~) and restart it with =restart= (e.g., ~systemctl --user restart drive-backup.service~).
|
|
|
|
If you want to enable it at startup, you can go with =enable= subcommand.
|
|
(To disable it, use the =disable= subcommand.)
|
|
|
|
#+begin_src shell :eval no
|
|
systemctl --user enable drive-backup.service
|
|
#+end_src
|
|
|
|
systemd will use the configuration file as-is by the time it is started/enabled.
|
|
Which means if the config file has been modified after activation, it will not take effect until you restarted it.
|
|
For this, you can reload the daemon with =daemon-reload= subcommand.
|
|
But for simpler cases, you can use the =reload= subcommand without fully restarting the daemon.
|
|
|
|
#+begin_src shell :eval no
|
|
systemctl --user reload drive-backup.service
|
|
|
|
# You could also use...
|
|
# systemctl --user daemon-reload
|
|
# ...if you need a stronger option.
|
|
#+end_src
|
|
|
|
|
|
** Service configuration
|
|
|
|
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=.
|
|
|
|
|
|
|
|
|
|
* Bootloader configuration
|
|
|
|
systemd also comes with a bootloader aptly named =systemd-boot= though it only supports UEFI-based firmware.
|
|
Just like GRUB, they can be configured through plain-text files.
|
|
|
|
For detailed information about the bootloader, see the manual page =systemd-boot.7=.
|
|
|
|
With a complete installation, the bootloader config folder may look like the following list.
|
|
|
|
#+begin_src
|
|
/boot/
|
|
`-- loader
|
|
|-- entries # (ref:loader-entries)
|
|
| `-- arch.conf
|
|
|-- loader.conf # (ref:loader-conf)
|
|
`-- random-seed
|
|
#+end_src
|
|
|
|
- [[(loader-entries)][=loader/entries/=]] is a directory containing all of the entries available to be booted.
|
|
- [[(loader-conf)][=loader.conf=]] contains the loader configuration.
|
|
|
|
Most Linux distros with systemd installed should have a sample config file somewhere. [fn:: In case of Arch Linux, it has an example file at =/usr/share/systemd/bootctl/=.]
|
|
As an example, we'll show what those look like.
|
|
=loader.conf= is the configuration for the boot loader including the timeout seconds among others.
|
|
Here is a sample of a bootloader configuration.
|
|
|
|
#+begin_src
|
|
default arch
|
|
timeout 4
|
|
#+end_src
|
|
|
|
In this config, this simply makes the =arch= loader entry to be default when no actions has occurred.
|
|
It will start loading it automatically after a timeout of 4 seconds.
|
|
|
|
The =arch= loader entry can be found at =${ESP}/loader/entries/arch.conf=.
|
|
The following code block shows what a loader entry looks like.
|
|
|
|
#+begin_src
|
|
title Arch Linux
|
|
linux /vmlinuz-linux
|
|
initrd /initramfs-linux.img
|
|
options root="PARTUUID=${PARTUUID}"
|
|
#+end_src
|
|
|
|
You can customize and create extra entries for the same installation.
|
|
This is what roam:NixOS does with its package generations, letting the user to boot to a specific point in time from the boot loader.
|
|
Very useful for emergency boots in case the current generation breaks for whatever reason.
|
|
|
|
For complete details of the configuration file, you can see =loader.conf.5= manual page.
|
|
|
|
|
|
|
|
|
|
* Network manager configuration
|
|
:PROPERTIES:
|
|
:ID: e4dba4ef-71dd-4d30-9a2c-4ad97223510b
|
|
:END:
|
|
|
|
With a systemd-ful environment, you can run the network daemon (i.e., =systemd-networkd=).
|
|
Once enabled, you can run =networkctl= to list all of the network devices. [fn:: You can also run ~ip address~ for it.]
|
|
|
|
#+begin_src shell :cache yes
|
|
networkctl
|
|
#+end_src
|
|
|
|
#+results[84c83a400d07ef38e6813bc9ce677cef8a38bd66]:
|
|
: IDX LINK TYPE OPERATIONAL SETUP
|
|
: 1 lo loopback carrier unmanaged
|
|
: 2 enp1s0 ether routable configured
|
|
: 3 wlan0 wlan routable configured
|
|
:
|
|
: 3 links listed.
|
|
|
|
To configure network manager, you can create a network file in one of systemd unit file paths in the system.
|
|
Each of the device will be assigned an IP address.
|
|
You can either assign an IP address or dynamically assign them in some way.
|
|
One of the common ways to do dynamic IP addresses is installing a DHCP server (which is another thing to be configured).
|
|
Here's an example of configuring any wireless devices and assigning a dynamic IP addresses with [[https://wiki.archlinux.org/title/Network_configuration#DHCP][DHCP]].
|
|
|
|
#+begin_src
|
|
[Match]
|
|
Type=wlan
|
|
|
|
[Network]
|
|
DHCP=yes
|
|
IPv6PrivacyExtensions=yes
|
|
|
|
[DHCPv4]
|
|
RouteMetric=1024
|
|
|
|
[DHCPv6]
|
|
RouteMetric=1024
|
|
#+end_src
|
|
|
|
|
|
|
|
|
|
* DNS server configuration
|
|
|
|
While the network manager is enabled, you can access the internet.
|
|
But only with raw IP addresses (e.g., 1.1.1.1 from Cloudflare, 93.174.95.27 for Library Genesis). [fn:: You can find the IP addresses with DNS clients such as [[https://github.com/ogham/dog][dog]] or the [[https://nodejs.org/api/dns.html][DNS library from NodeJS]].]
|
|
|
|
Accessing the domain names as you would browse the web normally is an additional layer of the web.
|
|
To access a domain name, you need a DNS client that can resolve them.
|
|
While there are plenty of DNS resolvers, systemd has a component =systemd-resolved= which you can control with =resolvectl= binary.
|
|
|
|
systemd-resolved takes a configuration from =/etc/resolve.conf= which most third-party programs also relies on.
|
|
|
|
|
|
|
|
|
|
* Log management
|
|
|
|
systemd has a journal service storing logs from units.
|
|
It provides a consistent and structured way how to check the logs.
|
|
|
|
It uses =journalctl= as the command for managing logs.
|
|
See [[id:941e0a85-1bb4-45be-a729-1b577c7ee317][Command line: journalctl]] for more details.
|
|
|
|
#+begin_src shell
|
|
journalctl --user-unit backup.service --follow --boot
|
|
#+end_src
|