- How to run script on startup using systemd in Linux
- Step 1: Overview on systemd
- Step 2: Create Sample Script
- [Basic] How to: Start a Program or Script on Linux Automatically on Boot with systemd
- How to start a program on Linux automatically on boot
- Create the sample script or program that we want to automatically start on boot
- Create a system unit (also known as a service)
- Configure your service to automatically start on boot
- Test your service with a reboot!
- Linux Boot Scripts
- Richard Gooch
- 21-NOV-2002
- Introduction
- BSD-style problems
- SysV-style problems
- The New Scheme
- Implementation details
- Single-user and runlevels
- Optimisations
- Runlevels and rollback
- Multiple providers and provide(8)
- The need(8) implementation
- Wrapup
- History
- Status
- Things to do:
How to run script on startup using systemd in Linux
Table of Contents
In this article I will share a sample systemd unit file which you can use to run script at startup with systemd without using crontab in RHEL/CentOS 7/8 Linux.
Some more articles on similar topic:
- How to execute a command or script with systemd at shutdown only and not at reboot in Linux
- How to execute a command or script with systemd right before login prompt appears on terminal in Linux
- How to execute a command or script at system startup using systemd without using cronjob in Linux
- How to execute a command or script after N minutes of boot up (system startup) with systemd in Linux
- How to halt system reboot or shutdown and read user input during boot up stage in Linux
- How to execute a command or script using systemd right before shutdown happens in Linux
- How to run a service as a specific user or group using systemd in Linux
There can be various scenarios when you expect a script or command to be called at startup such as
- Execute a script after waiting for N minutes of startup
- Execute a script after all the systemd services are loaded
- Execute a script immediately after login prompt appears
- Execute a script just before the login prompt appears
In this article I will cover below two topics as they are almost similar
- Run script at startup with systemd after network is reachable
- Execute script at starup after all the systemd services are loaded
I will be using CentOS/RHEL 7/8 Linux node to verify the steps from this article to run script with systemd right before login prompt.
Step 1: Overview on systemd
I hope you are already familiar with below topics
Step 2: Create Sample Script
Now to run script at startup with systemd firstly we need a script or command. For the sake of this article I have create a dummy shell script /tmp/startup_script.sh which we will use for testing this article.
This script will continue to run for 5 minutes and will print an echo statement on the screen every minute as a broadcast message using wall command for all Linux users on the respective node. And at the end of 5th minute it will print a completed broadcast. With this we can also make sure that the script is not killed by systemd if it continues to run for 5 minutes .
Provide executable permission to the script
Enable the service to make sure this is called automatically after reboot
Источник
[Basic] How to: Start a Program or Script on Linux Automatically on Boot with systemd
TABLE OF CONTENTS
If you have a Linux server and have a need to configure a service or program to automatically start on boot, this guide will demonstrate how to do so. This guide will be helpful to those that run critical services on their Linux machines. You will learn
how to ensure that those services always auto-start, even after an unplanned reboot.
How to start a program on Linux automatically on boot
We will be utilizing systemd for this task. First, we will create a sample script. Next, we will create a system unit that references our sample script. Finally, we will tell systemd, to automatically run our script (service unit) on system startup.
Start by logging onto your VPS via SSH. You may follow this guide to help you SSH into your SkySilk VPS
Create the sample script or program that we want to automatically start on boot
Create the following script in /usr/sbin/testscript.sh using your favorite text editor (like nano):
Make sure that the script is executable:
Create a system unit (also known as a service)
We will now create a system unit that references the above test script. This system unit is how systemd will know to run the test script at system boot.
Create the following file in /etc/systemd/system/test.service. Make sure you reference the script that you created above and that you save the system unit with a «.service» extension.
Configure your service to automatically start on boot
Reload the systemctl daemon:
Tell systemd to enable your custom system unit:
Confirm that your test service was created successfully:
Start your service:
Test your service with a reboot!
Go ahead and do a test reboot of your server. The service you configured should auto-start as the server boots up. At this point your all done with the configuration!
Источник
Linux Boot Scripts
Richard Gooch
21-NOV-2002
Introduction
The new boot scripts require a modified version of simpleinit(8), which is distributed with the util-linux package. See http://www.kernel.org/ for a mirror site near you. I’m the new maintainer of simpleinit(8), and the changes I’ve made are available in the latest util-linux package.
OK, with all that out of the way, let me tell you why we think a new boot script scheme is needed. The two main existing schemes are the so-called «BSD» and «SysV» styles. Each have their respective disadvantages:
BSD-style problems
Where this scheme fails is in its scalability. If a 3rd-party package needs to have an initialisation script run during the boot procedure, it needs to edit one of the existing boot scripts. Such editing is dangerous, as boot scripts are fragile at the best of times. A simple mistake by the installer can lead to an unbootable system.
SysV-style problems
This scheme places a number of mini-scripts in a master directory (typically /etc/rc.d/init.d/) which collectively can boot most of the system. Each of these mini-scripts starts and stops one «service». This is quite neat and modular.
A master boot script is used to orchestrate the boot process, which does some «special» setup (i.e. anything which was too hard to put into a mini-script), and then proceeds to run each of the mini-scripts in another directory. The order is based on shell wildcard expansion rules.
The «other directory» is populated with symbolic links back into /etc/rc.d/init.d/ (where the scripts are kept). Each script usually has two links to it. One starts with ‘S’ and the other with ‘K’. The «S*» scripts are called when booting up the system, the «K*» scripts are called when shutting down the system. The desired ordering is achieved by using numbers after the ‘S’ and ‘K’ in the link names.
So a link with name «S10» will run before «S15», which in turn runs before «S20». It is the responsibility of the system integrator to name these links such that services are started and stopped in the correct order. A 3rd-party software installer can «simply» place their startup script in /etc/rc.d/init.d/ and then create a symbolic link to the script in the «other directory». The installer has to pick a name that is not already taken, and has to determine the number to use (which depends on how far into the boot procedure the script must be run).
The author of the system boot scripts must therefore allocate numbers with sufficient gaps between them to allow for later insertions. Typically, the numbers 10, 20, 30, 40, 50, 60, 70 and so on are chosen. This reminds me of when I was a youngster programming BASIC on my Apple ][. Every line had to be given a number, and you had to be careful to leave «space» for later insertions. The SysV numbering isn’t quite so restrictive, as it is possible to append an arbitrary string to the number, which effectively increases the number space. Typically, the name of the script is appended, such as 10inetd and 10named. Thus, it is possible to «group» scripts so that the order between groups is well-defined, while ordering within a group is unknown (or knowable but not important).
The SysV booting scheme also supports the concept of «runlevels». What this means is that the system may be booted «all the way» (by convention, this is runlevel 5) by default, but may also be booted only part of the way. The most common purpose is to allow the system to be booted «single-user» (i.e. maintenance/repair mode), where only a handful of services are started. The runlevel scheme is supported by splitting the symlinks in the «other directory» into a number of directories, each directory corresponding to a runlevel. These directories are typically named: /etc/rc.d/rc0.d/ /etc/rc.d/rc1.d/ /etc/rc.d/rc2.d/ /etc/rc.d/rc3.d/ /etc/rc.d/rc4.d/ /etc/rc.d/rc5.d/ /etc/rc.d/rc6.d/.
The master boot script will start all scripts in the runlevel directory corresponding to the desired runlevel. Thus, the system can be booted to runlevel 1 by running the scripts in /etc/rc.d/rc1.d/ (this is often «single-user» mode). Then, perhaps after some maintenance work the system can be booted all the way by switching to runlevel 5 by stopping services for runlevel 1 and starting the scripts in /etc/rc.d/rc5.d/. Similarly, the system can be taken from a higher runlevel to a lower one by stopping services.
The problem with all this, if it isn’t obvious already, is that it’s complex. The directories of symlinks make it difficult to see what is being run and how all the pieces fit together. If that doesn’t convince you, consider the number of words required to describe this scheme. Note how the BSD-style scheme is much easier to describe (and by extension, understand).
All that is going for the SysV-style scheme is that it works. We believe that it is not elegant, and is confusing to experienced system administrators (when first exposed to the scheme), let alone novice administrators. And there remains a problem for 3rd-party boot scripts: which symlink name should be chosen? Usually the script is started in runlevel 6, because by that time «most» services are available. The simplest solution is to pick a random high number, which «should» work. Also, the use of numerical runlevels is far from intuitive. While old-guard SysV administrators may feel the runlevel definitions are simple to learn, the reality is the numbers convey no meaning. Certainly novice system administrators (the bulk of the Linux population now) will just scratch their collective heads and say «ah well, I guess that’s just Unix».
The New Scheme
The solution we came up with is simple yet powerful. There is no master script which orchestrates everything. It’s all done by init(8) and need(8) which provide the mechanism. The master script (which my old boot scripts have, and which SysV also has, despite their attempts to modularise), is broken into a bunch of smaller mini scripts.
The mini scripts are kept in /sbin/init.d and init(8) runs all of them, in random order. Ordering of the mini scripts is controlled by the scripts themselves. Each script runs any other scripts it depends on, using the need(8) programme which ensures that a script is only run once. It doesn’t matter which order init(8) starts running the scripts, it all magically sorts itself out.
3rd-party scripts need only use need(8) to ensure services they require are running. That’s all there is to the scheme. It’s worth noting that Mastodon Linux (by David Parsons) has a similar dependency-based scheme (although it doesn’t go quite as far). Thanks to Larry McVoy for pointing this out. NetBSD subsequently implemented a similar system although less flexible scheme, described here.
Implementation details
In the new scheme, init(8) is configured to run all mini startup scripts in /sbin/init.d/. Each script starts/stops one service (i.e. printing, filesystem checks, NFS mounting and so on). Ordering requirements are solved by each script pulling in other scripts it depends on using the need(8) programme. This basically means «run with dependency check». So the NFS export script would be: or something like that. The need(8) programme is used to run a script with. If the programme has not been run before, need(8) will run it. If it has already run, need(8) does nothing.
Single-user and runlevels
There are two ways in which traditional runlevels can be supported. One is that an appropriate directory is created with symlinks back into /sbin/init.d/. A more elegant solution is to have a script for each runlevel, which would look something like this:
Optimisations
Runlevels and rollback
An orderly shutdown is as simple as rolling back the entire table. The algorithm is trivial: get the last entry in the table and run the appropriate stop script (which removes itself from the table). Repeat the process until the table is empty. All services have been stopped in the reverse order in which they were started.
Increasing runlevel is easy: just run the desired runlevel script. So going from runlevel 2 to 3 involves running runlevel.3 under the dependency management scheme. Simple.
Going from runlevel 3 to 2 is slightly more complicated, but not much. Just roll back, stopping each script/service in reverse order. As each is stopped, remove it’s entry from the dependency table. Stop at «runlevel.2» (i.e. don’t stop «runlevel.2», only the scripts listed after it).
This scheme works because «runlevel.3» is added to the dependency table after it can pull in new dependencies (because it’s added to the list once it completes). So once you’ve rolled back to «runlevel.2», you know you’ve stopped all the services «runlevel.3» has started, plus all the services it depended on, but not the services runlevel 2 depended on, or runlevel 2 itself. Magic.
For switching between runlevels to work, the burden is placed on the runlevel scripts, not init(8), which is important IMO. Earlier I showed a sample implementation for «runlevel.3». It’s important because it provides maximum flexibility in the construction of boot scripts and keeps init(8) simple.
Multiple providers and provide(8)
In this case, you only want one of these script to be started. It might not matter which one is started, or perhaps each script may check some system-specific configuration to determine whether or not it should start the service. Either way, all scripts providing the generic service should be run, but only one should start the service.
The solution to this is the provide(8) programme. It tells init(8) that the calling programme/script is able to provide the generic service. Init(8) then makes sure that only one provider will actually provide this service. An example script follows:
The need(8) implementation
Script starting and stopping, as well as database management, is performed by init(8), and need(8) is a trivial programme which simply writes service requests to the FIFO and waits for a success/failure signal.
Because the dependency table for init(8)-started processes is kept in init(8), it makes partial rollbacks (switching between runlevels) easier to implement. One nice thing that we can rely on is that init(8) never dies, and doesn’t crash (if it does, we’re rooted anyway). So keeping the table in VM is quite safe. And it’s small anyway, so we don’t have to worry about memory limitations.
Note that need(8) and provide(8) are actually symbolic links to the initctl(8) programme.
Wrapup
There are other issues we still have to deal with (such as personalities (a scheme I came up with in my old boot scripts for configuration control)), but that’s orthogonal to the above issues.
History
For years, Patrick and I have been bitching and moaning about the way Unix systems boot. «One day» we were going to figure out a better way. That day came on Saturday, 29th January 2000. After an afternoon checking out the new VW Beetle, we settled back and started plotting and arguing.
One significant issue where we disagreed was in how dependency data were to be gathered. Patrick suggested parsing the scripts, which I didn’t like. While it would have made some things easier, this approach would either be too limiting (it would not support conditional dependencies), or it would require writing a full parser. Writing a full parser would yield something almost as complex as bash. In addition, it would not support scripts in other shell languages, or binaries. In the end, I convinced Patrick a parser was not practical.
That night, I sent off an email to Larry (with whom I’d sparred before, and he had previously expressed discontent with the way booting worked). Soon, he pointed out David had done something similar for his distribution (Mastodon Linux). David had done something using a support script, which required a writable root FS. I considered this a significant limitation. Also, he hadn’t gone far enough in my opinion, as he still had some large script orchestrating the boot process. Patrick and I both agreed that there should be no «special» or master script.
After (too much) email discussion, I decided that Patrick and I were still on the right track, and went forth and coded. This resulted in the basic need(8) implementation and a set of sample boot scripts using this scheme. Parallel booting even worked.
In March, Wichert Akkerman (Debian project leader) was in town for the Linux conference and Expo, which was our chance to sell the idea to the Debian project. Wichert liked the idea (in fact he’d once tried something similar, but never got it fully working), but wanted the addition of the provide(8) feature. This required more work, and thus the project stalled, since on my return from Sydney I had a large backlog of work to deal with.
Finally, in October, sitting on a plane headed for ALS, I had the time to get back to boot scripts, and started writing the provide(8) implementation. Shortly after my return from this trip I had finished this work, and finally had emptied out the ToDo list. Joy of joys!
As a side note, I find it interesting that other people have considered a similar approach (I’ve talked to people at conferences and had resonses like «oh, yeah, I’ve thought about doing that»). It seems this idea was ripe for the plucking. Hopefully this will translate into community acceptance.
Status
All these changes have been incorporated into util-linux-2.10q.
Things to do:
- I’ve considered keeping a full dependency history inside simpleinit(8) (right now it only keeps track of the currently depended-on service for each script). This would allow any service to be stopped and all services which depend on it to be stopped (dependent services would be stopped first, of course). This would be more flexible than either runlevels or rollback. In addition, a stopped service could still be recorded in the database and thus restarted with all the services that depended on it also being restarted. I have not yet determined whether these features would yield sufficient benefit to justify the implementation effort.
A set of sample boot scripts are available as a gzipped tarfile. I consider these «production quality». They have been in use on workstations and servers for years, and perform very well. They are fast and reliable. If there are missing features (such as configurations or daemons that are not supported), please let me know and I’ll update them. Go back to my: Home Page or Linux Page.
Источник