Tag: system-administration

  • Run App as SystemD Service Example

    Here we go. You got an old web app that start/stop/restart using initd scripts. This was well and good in the CentOS days. After some OS updates here and there, your web app now runs on Rocky 9.7. Trouble is on VM reboots, your web app does not start up automatically and you have 10 apps on the box. From time to time, CI/CD breaks because your web app process goes on zombie mode and you’ll have to manually kill it.

    What can you do? Move it from an initd to a systemd service. As to the why the Linux folks replaced or moved from initd to systemd, I’ll let you google that around. Here are the steps to make your app run as a systemd service.

    Create the SystemD Service File

    [jpllosa@rocky-balboa ~]$ cat /etc/os-release
    NAME="Rocky Linux"
    VERSION="9.7 (Blue Onyx)"
    
    ...snipped...
    
    [jpllosa@rocky-balboa systemd-stuff]$ cat my-web-app.service
    [Unit]
    Description=My Web App service
    After=network.target
    StartLimitIntervalSec=0
    
    [Service]
    Type=simple
    Restart=always
    RestartSec=1
    User=codesamples
    ExecStart=/usr/bin/java -jar /opt/codesamples/my-web-app/my-web-app.jar --spring.config.location=/etc/codesamples/my-web-app/my-web-app.properties
    
    [Install]
    WantedBy=multi-user.target
    [jpllosa@rocky-balboa systemd-stuff]$

    What do all the mumbo jumbo above mean?

    All .service files start with a Unit section which provides basic information about the service. The Description must not exceed 80 characters and must describe the service. The After tells systemd to only activate this service after this prerequisite. In this example, the service is activated after network connectivity is established. We have disabled any kind of rate limiting by setting StartLimitIntervalSec to 0. This rate limiting works in conjunction with Restart.

    The Service section provides instructions on how to control the service. The simple Type means to start the service without any special considerations. The ExecStart clearly shows the command to run to start the service. The full path to the command and arguments are declared. User specifies the user under which the service should run. RestartSec configures the time in seconds to sleep before restarting the service. Restart is set to always, as the word says, the service will be restarted no matter what (e.g. process is terminated by a signal, non-zero exit code, termination due to out of memory, etc). There is a default timeout for starting, stopping and aborting of units, as well as a default time to sleep between automatic restarts of units. If the restart times out after several tries, the system will not try to restart the service. Therefore, we have set above StartLimitIntervalSec to 0, so it will try to restart the service to infinity and beyond.

    WantedBy is used to create symlinks in .wants/ directories when the service is enabled. In this case, a symlink will be created under multi-user.target.wants. This indicates that the service should be started as part of the multi-user system.

    Copy the above service file to where systemd service files reside. As seen below.

    [jpllosa@rocky-balboa system]$ pwd
    /etc/systemd/system
    [jpllosa@rocky-balboa system]$ ls -ali
    total 24
     67738686 drwxr-xr-x. 10 root root 4096 Mar 17 13:27 .
       863730 drwxr-xr-x.  6 root root 4096 Feb 10 13:45 ..
     67824144 drwxr-xr-x.  2 root root   65 Feb 13 13:43 basic.target.wants
     67750396 lrwxrwxrwx.  1 root root   37 Feb 10 12:27 ctrl-alt-del.target -> /usr/lib/systemd/system/reboot.target
     67824045 lrwxrwxrwx.  1 root root   41 Feb 10 12:28 dbus-org.fedoraproject.FirewallD1.service -> /usr/lib/systemd/system/firewalld.service
     67823100 lrwxrwxrwx.  1 root root   57 Feb 10 12:28 dbus-org.freedesktop.nm-dispatcher.service -> /usr/lib/systemd/system/NetworkManager-dispatcher.service
     67750469 lrwxrwxrwx.  1 root root   43 Feb 10 12:27 dbus.service -> /usr/lib/systemd/system/dbus-broker.service
     67750393 lrwxrwxrwx.  1 root root   41 Feb 10 12:29 default.target -> /usr/lib/systemd/system/multi-user.target
     67736707 -rw-r--r--.  1 root root  394 Mar 17 13:27 my-web-app.service
       905723 drwxr-xr-x.  2 root root   32 Feb 10 12:27 getty.target.wants
     68554611 drwxr-xr-x.  2 root root   56 Feb 13 13:43 graphical.target.wants
     34039637 drwxr-xr-x.  2 root root 4096 Mar 17 13:32 multi-user.target.wants
     67823101 drwxr-xr-x.  2 root root   48 Feb 10 12:28 network-online.target.wants
     67750466 drwxr-xr-x.  2 root root   71 Feb 10 12:28 sockets.target.wants
    101399263 drwxr-xr-x.  2 root root 4096 Feb 10 12:28 sysinit.target.wants
       956462 drwxr-xr-x.  2 root root   56 Feb 10 12:28 timers.target.wants

    Starting and Enabling the Web App

    Now that the service is ready. Let’s start up the web app.

    sudo systemctl start web-app

    If there are no error, you can then enable the web app so it will start at boot. You don’t need to worry about reboots. The web app will automatically start up now.

    sudo systemctl enable web-app
    [jpllosa@rocky-balboa system]$ cd multi-user.target.wants/
    [jpllosa@rocky-balboa multi-user.target.wants]$ ls -ali
    total 8
    34039637 drwxr-xr-x.  2 root root 4096 Mar 17 13:32 .
    67738686 drwxr-xr-x. 10 root root 4096 Mar 17 13:27 ..
    34113015 lrwxrwxrwx.  1 root root   38 Feb 10 12:28 auditd.service -> /usr/lib/systemd/system/auditd.service
    34113143 lrwxrwxrwx.  1 root root   39 Feb 10 12:28 chronyd.service -> /usr/lib/systemd/system/chronyd.service
    34039686 lrwxrwxrwx.  1 root root   37 Feb 10 12:27 crond.service -> /usr/lib/systemd/system/crond.service
    34125258 lrwxrwxrwx.  1 root root   50 Mar 17 13:31 my-web-app.service -> /etc/systemd/system/my-web-app.service
    34113189 lrwxrwxrwx.  1 root root   41 Feb 10 12:28 firewalld.service -> /usr/lib/systemd/system/firewalld.service
    34124734 lrwxrwxrwx.  1 root root   37 Mar 17 13:29 httpd.service -> /usr/lib/systemd/system/httpd.service
    34113963 lrwxrwxrwx.  1 root root   42 Feb 10 12:28 irqbalance.service -> /usr/lib/systemd/system/irqbalance.service
    34112994 lrwxrwxrwx.  1 root root   37 Feb 10 12:28 kdump.service -> /usr/lib/systemd/system/kdump.service
    34131546 lrwxrwxrwx.  1 root root   43 Feb 10 12:41 nessusagent.service -> /usr/lib/systemd/system/nessusagent.service
    34112403 lrwxrwxrwx.  1 root root   46 Feb 10 12:28 NetworkManager.service -> /usr/lib/systemd/system/NetworkManager.service
    34039638 lrwxrwxrwx.  1 root root   40 Feb 10 12:27 remote-fs.target -> /usr/lib/systemd/system/remote-fs.target
    34111121 lrwxrwxrwx.  1 root root   39 Feb 10 12:28 rsyslog.service -> /usr/lib/systemd/system/rsyslog.service
    34347699 lrwxrwxrwx.  1 root root   43 Feb 10 13:44 sentinelone.service -> /usr/lib/systemd/system/sentinelone.service
    34113102 lrwxrwxrwx.  1 root root   36 Feb 10 12:28 sshd.service -> /usr/lib/systemd/system/sshd.service
    34112926 lrwxrwxrwx.  1 root root   36 Feb 10 12:28 sssd.service -> /usr/lib/systemd/system/sssd.service
    [jpllosa@rocky-balboa multi-user.target.wants]$

    More Commands

    Try the commands below to check the status, stop, or restart your web-app service.

    sudo systemctl status web-app
    sudo systemctl stop web-app
    sudo systemctl restart web-app

    Run App as SystemD Service

    You can now sit back and relax. No more panic mode after VM reboots and when other people complain why things aren’t working as they are supposed to. Goodbye zombie processes. Congratulations, you have automated yourself out of a job.

    More Rocky Linux tips here…