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

JavaLinuxSpringSpring Boot

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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:

Solution 2 - Java

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 openjdk:8-jdk-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

An even better approach for building Docker images is to use Jib, an open-source Java tool maintained by Google for building Docker images of Java applications. Jib does not need a Dockerfile, you just invoke it with Maven (official quickstart here) or Gradle (official quickstart here).

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

Solution 3 - Java

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.

Solution 4 - Java

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

Solution 5 - Java

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.

Solution 6 - Java

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 .

Solution 7 - Java

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

Solution 8 - Java

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.

Solution 9 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCleber GoncalvesView Question on Stackoverflow
Solution 1 - JavacorleoneView Answer on Stackoverflow
Solution 2 - JavamrtsView Answer on Stackoverflow
Solution 3 - JavaVinod MohananView Answer on Stackoverflow
Solution 4 - JavaStéphane GRILLONView Answer on Stackoverflow
Solution 5 - JavaspstoreyView Answer on Stackoverflow
Solution 6 - JavaunnikView Answer on Stackoverflow
Solution 7 - JavaisijaraView Answer on Stackoverflow
Solution 8 - JavaScrayosView Answer on Stackoverflow
Solution 9 - JavaBeeNoisyView Answer on Stackoverflow