Add a systemd service file into a Yocto image

From KoanSoftware Wiki
Revision as of 10:26, 17 June 2024 by Koan (talk | contribs) (Create a recipe to add a systemd service file)

Jump to: navigation, search

Add a systemd service file into a Yocto image

During KOAN training we use a meta-training layer to create an example.bb recipe building a helloworld executable.

In this article we want to create a recipe to add a systemd service file that starts such helloworld executable.


Enable systemd in the final image

If systemd is not enabled by default in your Yocto Project final image you are very likely still using SystemV. Add the following lines to the local.conf to enable systemd as default init manager.

DISTRO_FEATURES_append = " systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit"
VIRTUAL-RUNTIME_init_manager = "systemd"
VIRTUAL-RUNTIME_initscripts = "systemd-compat-units"


Create a recipe to add a systemd service file

For the helloworld application, we don’t necessarily need a service file as this application does not provide services to other parts of this system. However, for example purposes, we will create an autostart script to run hello at boot time. The output from this invocation will be available in the systemd logs using the journalctl command. This service file can also be manually invoked at runtime.

First, we will create the service file itself which is read and processed by systemd:

mkdir -p meta-training/recipes-example/systemd/files/

Edit a new configuration file

gedit meta-training/recipes-example/systemd/files/hello.service

containing the following code

[Unit]
Description=GNU Hello World startup script for KOAN training course

[Service]
ExecStart=/usr/bin/hello

[Install]
WantedBy=multi-user.target

Now let’s add the recipe settings to integrate this into the systemd configuration for our build:


Edit a new configuration file

gedit meta-training/recipes-example/systemd/hellosystemd_1.00.bb

containing the following code

LICENSE = "CLOSED"
inherit systemd

SYSTEMD_AUTO_ENABLE = "enable"
SYSTEMD_SERVICE:${PN} = "hello.service"

SRC_URI:append = " file://hello.service "
FILES:${PN} += "${systemd_unitdir}/system/hello.service"

do_install:append() {
  install -d ${D}/${systemd_unitdir}/system
  install -m 0644 ${WORKDIR}/hello.service ${D}/${systemd_unitdir}/system
}

Add the recipe to the image editing local.conf

IMAGE_INSTALL:append = " hellosystemd"

Now rebuild your image

bitbake core-image-minimal

Boot and verify that the service started and the output is visible in the systemd logs.




UPDATE - Selecting an Initialization Manager

Instead of the previous settings you can use the following INIT_MANAGER variable to select your favorite init mechanism.

By default, the Yocto Project uses SysVinit as the initialization manager. There is also support for systemd, which is a full replacement for init with parallel starting of services, reduced shell overhead, increased security and resource limits for services, and other features that are used by many distributions.

In comparison to SysVinit, systemd treats components as units. Using units is a broader concept as compared to using a service. A unit includes several different types of entities. Service is one of the types of entities. The runlevel concept in SysVinit corresponds to the concept of a target in systemd, where target is also a type of supported unit.

In systems with SysVinit services load sequentially (i.e. one by one) during init and parallelization is not supported. With systemd, services start in parallel. This method can have an impact on the startup performance of a given service, though systemd will also provide more services by default, therefore increasing the total system boot time. systemd also substantially increases system size because of its multiple components and the extra dependencies it pulls.

Using SysVinit with udev

SysVinit with the udev device manager corresponds to the default setting in Poky. This corresponds to setting:

INIT_MANAGER = "sysvinit"

Using systemd

The last option is to use systemd together with the udev device manager. This is the most powerful and versatile solution, especially for more complex systems:

INIT_MANAGER = "systemd"

Controlling systemd from the target command line

Here is a quick reference for controling systemd from the command line on the target. Instead of opening and sometimes modifying files, most interaction happens through the systemctl and journalctl commands:

   systemctl status: show the status of all services
   systemctl status <service>: show the status of one service
   systemctl [start|stop] <service>: start or stop a service
   systemctl [enable|disable] <service>: enable or disable a service at boot time
   systemctl list-units: list all available units
   journalctl -a: show all logs for all services
   journalctl -f: show only the last log entries, and keep printing updates as they arrive
   journalctl -u: show only logs from a particular service

References

https://docs.yoctoproject.org/dev/ref-manual/variables.html#term-INIT_MANAGER

https://docs.yoctoproject.org/dev/dev-manual/init-manager.html#init-manager