The first time you explore a Red Hat Enterprise Linux 7 system, you will quickly discover that the traditional init scripts are gone. When you view the /etc/init.d/README file, it is going to say that you are using a systemd based operating system and your init scripts are now replaced by systemd unit files.
You may ask "what is the advantage of moving to systemd from init system"? The main advantages are:
systemd reduces system startup time in parallelizing startup of services.
systemd uses Cgroups for better tracking of processes, also allowing control of the execution environment.
systemd has a better logging mechanism as it is tightly coupled with journald, which is a logging mechanism that was introduced with Red Hat Enterprise Linux 7.
systemd can handle dynamic system configuration changes.
Converting SysV init scripts to systemd unit files
The first step to convert a SysV init script to a systemd unit file is to study the existing init script that you are actually planning to convert and identify the unique information from it. In my example, I am going to use the SysV init script of the service abrtd from Red Hat Enterprise Linux 6. Abrtd is an automated bug reporting tool service which will report the detected issues in your system. From the screenshot shown below, you can see that I have picked up some of the unique information and highlighted it in red.
Here is the interesting part! Now, what about this command block (shown below) which you normally see it in sysV init scripts?
The answer is that all these lines are actually not required and systemd will automatically take care of those sections. Brilliant! Then how about this section given below that we commonly see in every sysV init script. Do we need to declare those?
Systemd doesn't need all of these lines and this section will be taken care of automatically.
At this stage, we have identified the important information that are needed and what is unnecessary. Now, let's go ahead and design the template for the systemd unit files. You can expect three sections in the unit files that you commonly see in most systemd unit files: unit, service and install tags.
Based on the unique information that you have identified from your sysV init scripts, you will probably need to populate with some of the corresponding configuration directives under each tag. Based on the use case of your service or script, you will be choosing the configuration directives to fit the service behavior. To know more about available configuration directives, you can do man systemd.unit or systemd.services.
As per the screenshot above, below the unit tag, you may have to put the description, before or after directives depending on your use case. Below the service tag, I have mentioned execstart and type directives. Finally, under the install tag, I am mentioning wantedby directives.
It will be difficult for the first time to remember all these sections and directives, but what you can, for example, is copy the crond unit file from /usr/lib/systemd/system to a different location and remove all the crond specific entries which will give a basic template and start building your own unit file.
Armed with our template file, let's now convert the initscript to systemd unit file. The screenshot given below illustrates how we have converted to unit file.
Under [Unit] tag:
"Description" directive - This field normally summarizes what this service is all about. Let's copy this information straight from the init script to the unit file.
"After" directives: let's go back and look at the init script. It has been mentioned in the "Required start" that the abrt service needs syslog, so here in the unit file - we are going to use "After" directive and let's mention syslog.target. This says after syslog.target this abrt service needs to be started.
Under [Service] tag:
"Execstart" directives - This will call the binary script to start the abrt service. We already have this information in init script under ABRT_BIN. Let's copy the same information to the unit file.
"Type" directives - When abrt service is started, it will fork away from systemd and start the whole new process. systemd must be aware of the PID of the master process of the abrt service for a better control over that process. So for any service that use startup type "type= forking", we need to specify the PID file path so that systemd will store the PID information in that file. We already have the "pidfile" information in the init script. So let’s use "type=forking" and copy the "pidfile" information straight from the init scripts to unit files.
Under [Install] tag:
"Wantedby" directives - This directive always corresponds to the runlevel. In the init script, it was mentioned that the service must run on runlevel 3. Hence we are going to declare "multiuser.target" which is equivalent to runlevel 3 in legacy versions.
At this point, we have sufficiently translated the SysV init script into a usable systemd unit file.
We could drop it into /etc/systemd/system/abrt.service and then run a systemd daemon-reload to start using it [i.e. start, stop, enable]. But remember, we have now made systemd just to start and stop the service. It is difficult for systemd to properly supervise a service of Type=forking, since it's tough to determine the main process from an auxiliary process which is why we had to specify a PID file. It would be far better for systemd and for the monitoring to make use of systemd benefits, if the process spawned by systemd is actually the main process of the daemon (in other words if it didn't fork off) and if systemd had a reliable way to figure out when the daemon is fully started.
As mentioned in the beginning, one of the advantages of systemd is having better control on processes.
Lets see how we can make use of systemd capabilities and make the services to spawn within systemd rather than forking away and starting a separate process.
In the case of abrt service, it actually has command options to not daemonize, meaning not to fork off. You can see that by just running ABRT --help, you'll see this - D option here.
Let’s go back to the abrt unit file that we just created. Remove the "Type=forking" in our Service Unit configuration file and make use of this -d flag. We can actually change the startup type here in the method by which systemd is going to call and keep track of the service to "type=simple". It is a good idea to clean up the description a bit and give it a better, more descriptive name to indicate that this is the abrt automated bug reporting tool.
As you can see in the above screenshot, we have changed the description. We changed the ExecStart now to make use of this -d flag and also you're going to go ahead and do -s flag for this particular Daemon, so it logs to syslog and type=simple. By changing type=simple from type=forking, we're now starting to take better advantage of systemd and its ability to track and monitor a particular service. There are other notable start types that you may want to consider depending on the type of program that you're trying to insistently start with.
Other startup types in systemd
We are lucky that in the above example with abrt because the service was written in such a way that we can actually tell it to not daemonize and actually start up and log to syslog in that particular way. There are other services floating around in your system and other programs that are written that might take advantage of a few other start types that you should know about. For instance, DBus. Some programs register a name on the message bus when they start up successfully. You can take advantage of this and systemd using type=Dbus. You'll need to know the actual bus name that is registered on the message bus.
The example shown above is the query to determine a list of the dbus names that are actually registered. So for instance in our example "tuned" on the right, we can see that it registers the name com.redhat.tuned. We can take advantage of that fact by changing message type=Dbus. But again, the aim of all of this is to get us closer to having systemd managing our particular services rather than having them fork away to some shell, to some process space where it can be very difficult to know which one is the main process and which one it should actually be watching.
Another type that you come across is, type=notify. To make use of type=notify, the daemon that uses this type needs to be written in a very particular way. It needs to be what you might consider systemd ready, meaning that it will send an SD notify or some equivalent call when it finishes starting up. It should notify systemd directly saying, "Hey, I've started. I'm good to go." The below screenshot is an example of type=notify.
The final type that you may find yourself making use of when converting different sysv init scripts to the systemd unit files is type=oneshot.
If you've got some type of script or some type of application that just needs to be run one time and completely exit and it's not a daemon and it's not something that's going to stick around constantly pulling for some type of activity in your system, you can use this type. One example of a type=oneshot, the service that you're probably aware of is iptables. It loads the rules one time and once done, it exits.
So back to our abrt service example, we successfully converted the abrt sysv init script and set up type=forking. We further enhance the unit file by telling systemd to start abrt service not daemonize by changing type=simple. This improves the ability of systemd to monitor and track that particular service.
Now there are other things you can take advantage of. You've got systemd unit file and here are a few examples of resource limiting using cgroups. You can limit the cpu for your service using directives like CPU shares as shown in the example below.
You can do resource accounting if you want to keep track of your particular services that are being used on your particular system in terms of CPU, memory, block IO.
You could also set up monitoring and restarting logic into your service if it terminates abnormally.
Here, you can coordinate parallel startup if you want to. For instance, you can put more logic here, not just saying start after a particular service, but you can also set up a conflict directive here to basically say that one particular service conflicts with another and you can deactivate the service that is creating the conflict.
You can even set up specific ownership for your running environment. Here's an example with a HTcache clean service. You will notice that it is a service that is particularly used with Apache and can also see that we want this process to run as Apache user. In the ps output below, that's what is happening.
These are the advantages that you can now take with systemd unit files.
Jayaraj Deenadayalan is a senior technical account manager from Singapore. He is supporting business environments for major banking and financial institutions, telco and chip manufacturing companies that are having presence in APAC. Most recently, he has been focused on enabling customers to migrate legacy Red Hat Satellite and Red Hat Enterprise Linux systems to supportable versions. About me.
A Red Hat Technical Account Manager (TAM) is a specialized product expert who works collaboratively with IT organizations to strategically plan for successful deployments and help realize optimal performance and growth. The TAM is part of Red Hat’s world class Customer Experience and Engagement organization and provides proactive advice and guidance to help you identify and address potential problems before they occur. Should a problem arise, your TAM will own the issue and engage the best resources to resolve it as quickly as possible with minimal disruption to your business.