[java] How do I run a spring boot executable jar in a Production environment?

Spring boot's preferred deployment method is via a executable jar file which contains tomcat inside.

It is started with a simple java -jar myapp.jar.

Now, I want to deploy that jar to my linux server on EC2, am I missing something or do I really need to create a init script to properly start the application as a daemon?

If I simply call java -jar the application dies when I log out.

I could start it in screen or nohup but that is not very elegant and a restart in my server would force me to log in and start the process manually.

So, is there something already for the task in spring boot?

This question is related to java linux spring spring-boot

The answer is


You can use the application called Supervisor. In supervisor config you can define multiple services and ways to execute the same.

For Java and Spring boot applications the command would be java -jar springbootapp.jar.

Options can be provided to keep the application running always.So if the EC2 restart then Supervisor will restart you application

I found Supervisor easy to use compared to putting startup scripts in /etc/init.d/.The startup scripts would hang or go into waiting state in case of errors .


My Spring boot application has two initializers. One for development and another for production. For development, I use the main method like this:

@SpringBootApplication
public class MyAppInitializer {

    public static void main(String[] args) {
        SpringApplication.run(MyAppInitializer .class, args);
    }

}

My Initializer for production environment extends the SpringBootServletInitializer and looks like this:

@SpringBootApplication
public class MyAppInitializerServlet extends SpringBootServletInitializer{
    private static final Logger log = Logger
            .getLogger(SpringBootServletInitializer.class);
    @Override
    protected SpringApplicationBuilder configure(
            SpringApplicationBuilder builder) {
        log.trace("Initializing the application");
        return builder.sources(MyAppInitializerServlet .class);
    }

}

I use gradle and my build.gradle file applies 'WAR' plugin. When I run it in the development environment, I use bootrun task. Where as when I want to deploy it to production, I use assemble task to generate the WAR and deploy.

I can run like a normal spring application in production without discounting the advantages provided by the inbuilt tomcat while developing. Hope this helps.


Please note that since Spring Boot 1.3.0.M1, you are able to build fully executable jars using Maven and Gradle.

For Maven, just include the following in your pom.xml:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <executable>true</executable>
    </configuration>
</plugin>

For Gradle add the following snippet to your build.gradle:

springBoot {
    executable = true
}

The fully executable jar contains an extra script at the front of the file, which allows you to just symlink your Spring Boot jar to init.d or use a systemd script.

init.d example:

$ln -s /var/yourapp/yourapp.jar /etc/init.d/yourapp

This allows you to start, stop and restart your application like:

$/etc/init.d/yourapp start|stop|restart

Or use a systemd script:

[Unit]
Description=yourapp
After=syslog.target

[Service]
ExecStart=/var/yourapp/yourapp.jar
User=yourapp
WorkingDirectory=/var/yourapp
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

More information at the following links:


This is a simple, you can use spring boot maven plugin to finish your code deploy.

the plugin config like:

<plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <jvmArguments>-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=${debug.port}
                    </jvmArguments>
                    <profiles>
                        <profile>test</profile>
                    </profiles>
                    <executable>true</executable>
                </configuration>
            </plugin>

And, the jvmArtuments is add for you jvm. profiles will choose a profile to start your app. executable can make your app driectly run.

and if you add mvnw to your project, or you have a maven enveriment. You can just call./mvnw spring-boot:run for mvnw or mvn spring-boot:run for maven.


If you are using gradle you can just add this to your build.gradle

springBoot {
    executable = true
}

You can then run your application by typing ./your-app.jar

Also, you can find a complete guide here to set up your app as a service

56.1.1 Installation as an init.d service (System V)

http://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html

cheers


On Windows OS without Service.

start.bat

@ECHO OFF
call run.bat start

stop.bat:

@ECHO OFF
call run.bat stop

run.bat

@ECHO OFF
IF "%1"=="start" (
    ECHO start myapp
    start "myapp" java -jar -Dspring.profiles.active=staging myapp.jar
) ELSE IF "%1"=="stop" (
    ECHO stop myapp
    TASKKILL /FI "WINDOWTITLE eq myapp"
) ELSE (
    ECHO please, use "run.bat start" or "run.bat stop"
)
pause

By far the most easiest and reliable way to run Spring Boot applications in production is with Docker. Use Docker Compose, Docker Swarm or Kubernetes if you need to use multiple connected services.

Here's a simple Dockerfile from the official Spring Boot Docker guide to get you started:

FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD YOUR-APP-NAME.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

Here's a sample command line to run the container as a daemon:

docker run \
  -d --restart=always \
  -e "SPRING_PROFILES_ACTIVE=prod" \
  -p 8080:8080 \
  prefix/imagename

In a production environment you want your app to be started again on a machine restart etc, creating a /etc/init.d/ script and linking to the appropriate runlevel to start and stop it is the correct approach. Spring Boot will not extend to covering this as it is a operating system specific setup and the are tonnes of other options, do you want it running in a chroot jail, does it need to stop / start before some other software etc.


I start applications that I want to run persistently or at least semi-permanently via screen -dmS NAME /path/to/script. As far as I am informed this is the most elegant solution.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to linux

grep's at sign caught as whitespace How to prevent Google Colab from disconnecting? "E: Unable to locate package python-pip" on Ubuntu 18.04 How to upgrade Python version to 3.7? Install Qt on Ubuntu Get first line of a shell command's output Cannot connect to the Docker daemon at unix:/var/run/docker.sock. Is the docker daemon running? Run bash command on jenkins pipeline How to uninstall an older PHP version from centOS7 How to update-alternatives to Python 3 without breaking apt?

Examples related to spring

Are all Spring Framework Java Configuration injection examples buggy? Two Page Login with Spring Security 3.2.x Access blocked by CORS policy: Response to preflight request doesn't pass access control check Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified Spring Data JPA findOne() change to Optional how to use this? After Spring Boot 2.0 migration: jdbcUrl is required with driverClassName The type WebMvcConfigurerAdapter is deprecated No converter found capable of converting from type to type

Examples related to spring-boot

Access blocked by CORS policy: Response to preflight request doesn't pass access control check Why am I getting Unknown error in line 1 of pom.xml? Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured How to resolve Unable to load authentication plugin 'caching_sha2_password' issue ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified After Spring Boot 2.0 migration: jdbcUrl is required with driverClassName ERROR Source option 1.5 is no longer supported. Use 1.6 or later How to start up spring-boot application via command line? JSON parse error: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value