Rundeck as a Windows Service

Rundeck Evaluation

I’m evaluating a few software packages for workflow automation, control, and logging. Rundeck is a front runner as it seems to do everything I need without a huge array of extra features that I’m not going to use but will clutter the configuration and the GUI. Rundeck is written in java and, although it comes with shell scripts to be run as a Linux/Unix daemon, there is no inbuilt way to run it as a Windows service. I needed to find a way around this as I will be installing into a Windows server 2003 environment.

After a little reading around it turned out to be relatively straightforward to wrap the Rundeck jar as a Windows service and I thought I’d share the resources I used and the exact implementation I chose. I found a couple of different methods that seemed promising by searching ‘jar jar windows service’. A good thread can be found here. I chose to use the Tanuki Software Java Service Wrapper which can be downloaded from their website and which is discussed in this article

Rundeck Installation

The first step was to download and install the latest version of Rundeck in the normal way. Once I’d got the self-contained launcher jar in a c:\rundeck directory I simply ran

java -jar rundeck-launcher-2.1.3.jar

to extract all the Rundeck files. It was important to do this once from the command line as I intended to use the -skipinstall flag on the Windows service to skip the file extraction and speed up the service start time.

Java Service Wrapper Installation and Configuration

I downloaded the latest version of the wrapper and followed the instructions for the most straightforward integration, Method 1 WrapperSimpleApp Integration (Windows). I decided to install the service in C:\Rundeck\ServiceWrapper so that the wrapper was in an obvious place but was completely separate from the Rundeck files. This decision complicated the configuration slightly, but it should mean that I can upgrade Rundeck and copy it from my pre-production to production environments without confusion. I ended up with the following directory structure under C:\Rundeck\ServiceWrapper

  • bin/
    • InstallRundeck-NT.bat
    • RunDeck.bat
    • UninstallRundeck-NT.bat
    • wrapper.exe
  • conf/
    • wrapper.conf
  • lib/
    • wrapper.dll
    • wrapper.jar
  • logs/

After a little experimentation my wrapper.conf looked like this

#encoding=UTF-8
# Configuration files must begin with a line specifying the encoding
#  of the the file.

set.RUNDECK_HOME=C:\Rundeck
set.SERVICE_HOME=C:\Rundeck\ServiceWrapper

Above I’ve just set some env. variable for convenience

# Include file problems can be debugged by removing the first '#'
#  from the following line:
##include.debug

# The Wrapper will look for either of the following optional files for a
#  valid License Key.  License Key properties can optionally be included
#  directly in this configuration file.
#include ../conf/wrapper-license.conf
#include ../conf/wrapper-license-%WRAPPER_HOST_NAME%.conf

# The following property will output information about which License Key(s)
#  are being found, and can aid in resolving any licensing problems.
#wrapper.license.debug=TRUE

#********************************************************************
# Wrapper Localization
#********************************************************************
# Specify the locale which the Wrapper should use.  By default the system
#  locale is used.
#wrapper.lang=en_US # en_US or ja_JP

# Specify the location of the Wrapper's language resources.  If these are
#  missing, the Wrapper will default to the en_US locale.
wrapper.lang.folder=../lang

#********************************************************************
# Wrapper Java Properties
#********************************************************************
# Java Application
#  Locate the java binary on the system PATH:
wrapper.java.command=java
#  Specify a specific java binary:
set.JAVA_HOME=C:\Program Files\Java\jre7
wrapper.java.command=%JAVA_HOME%/bin/java

Above sets an appropriate JAVA_HOME and points to java.exe

# Tell the Wrapper to log the full generated Java command line.
#wrapper.java.command.loglevel=INFO

# Java Main class.  This class must implement the WrapperListener interface
#  or guarantee that the WrapperManager class is initialized.  Helper
#  classes are provided to do this for you.  See the Integration section
#  of the documentation for details.
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp

I’m using the most straightforward integration method, so use the WrapperSimpleApp main class

# Java Classpath (include wrapper.jar)  Add class path elements as
#  needed starting from 1
wrapper.java.classpath.1=%RUNDECK_HOME%/rundeck-launcher-2.1.2.jar
wrapper.java.classpath.2=%SERVICE_HOME%/lib/wrapper.jar
# Java Library Path (location of Wrapper.DLL or libwrapper.so)
wrapper.java.library.path.1=%SERVICE_HOME%/lib

Declare the rundeck launcher and the service wrapper jar on the classpath. Also point to the wrapper.dll as it appears in my file structure

# Java Bits.  On applicable platforms, tells the JVM to run in 32 or 64-bit mode.
wrapper.java.additional.auto_bits=TRUE

# Java Additional Parameters
wrapper.java.additional.1=

# Initial Java Heap Size (in MB)
#wrapper.java.initmemory=3

# Maximum Java Heap Size (in MB)
#wrapper.java.maxmemory=64

# Application parameters.  Add parameters as needed starting from 1
wrapper.app.parameter.1=com.dtolabs.rundeck.ExpandRunServer
wrapper.app.parameter.2=--skipinstall

Declare the main class of the launcher and pass the –skipinstall parameter so that Rundeck launches without the long process of re-extracting all the files from the self-contained launcher jar. Everything below here is standard and I’ve snipped out some sections that apply to other license editions.

#********************************************************************
# Wrapper Logging Properties
#********************************************************************
# Enables Debug output from the Wrapper.
# wrapper.debug=TRUE

# Format of output for the console.  (See docs for formats)
wrapper.console.format=PM

# Log Level for console output.  (See docs for log levels)
wrapper.console.loglevel=INFO

# Log file to use for wrapper output logging.
wrapper.logfile=../logs/wrapper.log

# Format of output for the log file.  (See docs for formats)
wrapper.logfile.format=LPTM

# Log Level for log file output.  (See docs for log levels)
wrapper.logfile.loglevel=INFO

# Maximum size that the log file will be allowed to grow to before
#  the log is rolled. Size is specified in bytes.  The default value
#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=0

# Maximum number of rolled log files which will be allowed before old
#  files are deleted.  The default value of 0 implies no limit.
wrapper.logfile.maxfiles=0

# Log Level for sys/event log output.  (See docs for log levels)
wrapper.syslog.loglevel=NONE

#********************************************************************
# Wrapper General Properties
#********************************************************************
# Allow for the use of non-contiguous numbered properties
wrapper.ignore_sequence_gaps=TRUE

# Do not start if the pid file already exists.
wrapper.pidfile.strict=TRUE

# Title to use when running as a console
wrapper.console.title=Test Wrapper Sample Application

#********************************************************************
# Wrapper JVM Checks
#********************************************************************
# Detect DeadLocked Threads in the JVM. (Requires Standard Edition)
wrapper.check.deadlock=TRUE
wrapper.check.deadlock.interval=10
wrapper.check.deadlock.action=RESTART
wrapper.check.deadlock.output=FULL

# Out Of Memory detection.
# (Ignore output from dumping the configuration to the console.  This is only needed by the TestWrapper sample application.)
wrapper.filter.trigger.999=wrapper.filter.trigger.*java.lang.OutOfMemoryError
wrapper.filter.allow_wildcards.999=TRUE
wrapper.filter.action.999=NONE
#  Ignore -verbose:class output to avoid false positives.
wrapper.filter.trigger.1000=[Loaded java.lang.OutOfMemoryError
wrapper.filter.action.1000=NONE
# (Simple match)
wrapper.filter.trigger.1001=java.lang.OutOfMemoryError
# (Only match text in stack traces if -XX:+PrintClassHistogram is being used.)
#wrapper.filter.trigger.1001=Exception in thread "*" java.lang.OutOfMemoryError
#wrapper.filter.allow_wildcards.1001=TRUE
wrapper.filter.action.1001=RESTART
wrapper.filter.message.1001=The JVM has run out of memory.

# Specify custom mail content
wrapper.event.jvm_restart.email.body=The JVM was restarted.\n\nPlease check on its status.\n

#********************************************************************
# Wrapper Windows NT/2000/XP Service Properties
#********************************************************************
# WARNING - Do not modify any of these properties when an application
#  using this configuration file has been installed as a service.
#  Please uninstall the service before modifying this section.  The
#  service can then be reinstalled.

# Name of the service
wrapper.name=rundeckwrapper

# Display name of the service
wrapper.displayname=Rundeck Application Service

# Description of the service
wrapper.description=Rundeck Application Server as a Windows Service

# Service dependencies.  Add dependencies as needed starting from 1
wrapper.ntservice.dependency.1=

# Mode in which the service is installed.  AUTO_START, DELAY_START or DEMAND_START
wrapper.ntservice.starttype=AUTO_START

# Allow the service to interact with the desktop.
wrapper.ntservice.interactive=false

Installing and using the service

It’s now just a case of running bin/InstallRundeck-NT.bat to install the service and you can use the normal ‘Services’ section of the control panel to start and stop Rundeck manually, as well as setting the service to automatically start when the machine reboots.

If your service fails for some reason the log file in the logs directory should give you some troubleshooting information. Once you’ve made corrections I found it safest to uninstall the service with UninstallRundeck-NT.bat, before reinstalling it, and trying again.

Leave a Comment