Starting Spring boot applications from script - java

Using normal spring mvn commands, I can start a spring boot application from command line and terminate it with Control+c. I however have created a bunch of services which I will dockerize later. For now they are plain java jar files generated by mvn. How do I use a python script or a Bash script to start them one by one and then use a script to terminate them. Is there some way where i start it and script won't block and the app will have a name that i can later use to stop the app?

I would follow the documentation to install Spring-Boot application as a Unix/Linux service.
All you have to do is to add this dependency to your pom.xml:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
After adding the plugin you should install and create a symlink to your application (exact part of documentation):
Assuming that you have a Spring Boot application installed in
/var/myapp, to install a Spring Boot application as an init.d service
simply create a symlink:
$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp
Once installed,
you can start and stop the service in the usual way. For example, on a
Debian based system:
$ service myapp start
Then you are able to create a bash script to start, stop or restart your applications in a clean way.

You could use a script to achieve this. For example a startup.sh may look like this. It will start the application and write the process id to /path/to/app/pid.file
#!/bin/bash
nohup java -jar /path/to/app/hello-world.jar > /path/to/log.txt 2>&1 &
echo $! > /path/to/app/pid.file
And a shutdown.sh may look like this.
#!/bin/bash
kill $(cat /path/to/app/pid.file)
You can find more detail in my post. https://springhow.com/start-stop-scripts-for-spring-boot-applications/

You can launch each jar with the following command (in a bash script):
java -jar service1.jar &
Then, you can kill each process with the following command (in a bash script):
pkill -f service1.jar
pkill will terminates all processes containing the provided name. Be careful that your keyword only identifies your process, so you don't terminate other processes by mistake.

This script make it easy, auto find newest version of jar file:
https://github.com/tyrion9/spring-boot-startup-script
./bootstrap.sh start
./bootstrap.sh stop
./bootstrap.sh restart

Related

How to automatically start 2 Java jars on AWS EC2?

I'm learning to deploy Spring Boot apps on AWS EC2. And I know how to automate app launch, when I start the EC2 instance, I don't need to manually use the command java -jar java-service.jar, I just add this command in the /etc/rc.local file and that is all. But I have 2 microservice, and I want to start both of them automatically, but if I try to add both commands in the /etc/rc.local it's not working, only the first service will start, the second service will not start.
So I have the commands added like this:
And after I start the EC2 instance only the first service is started:
Thank you!
I am not a unix expert, but I see the only issue in running 2 java commands from terminal is that unless the first command returns, the next command is not executed. So, I think the solution would be run the 1st command in some interactive mode so that the other commands can be executed simultaneously.
There are ways in unix shell to run a command in background. I found this useful link - https://www.maketecheasier.com/run-bash-commands-background-linux/
In bash terminal, a command can be made to run in background by appending it with &. So, I think you should be able to start both jars if you do something like -
java -jar /home/ec2-user/first.jar &
java -jar /home/ec2-user/second.jar
I recommend to use Systemd.
Create a Systemd unit file for every microservice, save it in /etc/systemd/system/my-app.service. Something like that:
[Unit]
Description=My Java app
After=syslog.target network.target
[Service]
EnvironmentFile=/etc/sysconfig/my-app-env
WorkingDirectory=/my/app/home
ExecStart=/usr/bin/java $JAVA_OPTS -jar my-app.jar
KillMode=process
User=my-app-user
Restart=on-failure
[Install]
WantedBy=multi-user.target
Then, run:
systemctl daemon-reload
systemctl enable --now my-app
After that, you can use:
systemctl status my-app
systemctl stop my-app
systemctl start my-app
Another solution is to bundle your jars into Docker images. This of course requires Docker runtime and adds an overhead, but it also has some benefits:
Complete separation of jar files. Easily use different java versions.
No need to worry about differences of local and ec2 environment.
Easily scale to 3 or more jars.
Use Docker Cli to build and start containers. Works great in a Devops Pipeline.
You can read here to learn how to create Spring Boot Docker images. After you build an image. You start it like this.:
docker run -p 8080:8080 springio/gs-spring-boot-docker
You can run as many docker run commands you need, one after another.
I am not sure which system you are using in starting application:
For linux base system, you can use crontab to schedule the task when the server reboot.
Follow this steps:
Download crontab
#apt-get install cron
Edit the file file to enable the task
crontab -e
(Choose Vim or nano to edit the task)
Add this code to your server
#reboot /usr/bin/java -jar XXXXX.jar
Save your file
Check the result
crontab -l
#systemctl status cron
This method works in my Debian system. For more details, you can refer to
How to automatically run program on Linux startup
If you are running from bash, then join two jar commands with "&" like below.
java -jar /home/ec2-user/first.jar&java -jar /home/ec2-user/second.jar
coupon service
Run the command 'java -jar /home/ec2-user/coupon-service-0.0.1-SNAPSHOT.JAR'
Press CTRL+Z, type bg, press Enter, type disown, press Enter.
product service
Run the command 'java -jar /home/ec2-user/product-service-0.0.1-SNAPSHOT.JAR'
Press CTRL+Z, type bg, press Enter, type disown, press Enter.
NOTE: Both services should have different ports.

Syntax Error After deploy SpringBoot jar as service on ubuntu 14.04.1

I have a springboot web application packaged as a jar file. And the product server is Ubuntu 14.04.1 with openjdk-8-jdk installed.
I can successfully run the application using:
sudo java -jar /home/myUser/my_web_app.jar
Then I make this appliaction as a SystemV service by following commands:
sudo useradd webUser
sudo passwd webUser
sudo chown webUser:webUser /home/myUser/my_web_app.jar
sudo chmod 500 /home/myUser/my_web_app.jar
sudo ln -s /home/myUser/my_web_app.jar /etc/init.d/my_web_app
After that, when I run:
sudo service my_web_app start
And error raise as:
/etc/init.d/my_web_app: 1: /etc/init.d/my_web_app: Syntax error: ")" unexpected.
I wonder what cause this error and how to reslove it. Thanks.
BTW, Same method works on my devlopment machine (Ubuntu 14.04.6).
The problem is these two lines:
sudo chmod 500 /home/myUser/my_web_app.jar
sudo ln -s /home/myUser/my_web_app.jar /etc/init.d/my_web_app
Problem #1: regular executable JAR files are not an executable format that the OS recognizes1.
Setting the execute bit on a regular JAR file won't help. The OS kernel does not know how to run it. To run a regular JAR, you have to execute the command java -jar /path/to/the.jar. If necessary, you can create a simple wrapper script to do this.
1 - There is a way to generate a special "fully executable" SpringBoot JAR file which has an shell script prepended to it; see "Installing Spring Boot Applications". This is one way to get around this problem, though the documentation states that these special JAR files cause problems for some tools.
Problem #2: The files in /etc/init.d are supposed to be service scripts.
They are not simply the executable for a service. The scripts are supposed to be shell scripts that understand verbs such as start, stop, restart, reload and so on. And (AFAIK) they must be coded as sh compatible shell scripts. Here is an article that describes the structure of service scripts:
https://www.linux.com/learn/managing-linux-daemons-init-scripts
(But read Problem #4 first!!)
Problem #3: Running a service as root can be a security risk.
It is better to create a (non-privileged) service account to run the service. This is especially important if the service is exposed to the network. (If the bad guys can "hack" the service over the network and cause it to do undesirable things, the fact that it is running as root places the entire system at risk.)
Problem #4: /etc/init.d/ scripts are obsolete.
If you are using a recent Ubuntu release (15.04 or later), those /etc/init.d/ scripts are the "legacy" way of configuring. The current iteration of the initd mechanism is systemd. It uses systemd unit files files rather than service scripts. The following article gives more information:
https://www.linux.com/learn/managing-linux-daemons-init-scripts
The systemd service includes for legacy service scripts, but they are not as powerful, flexible and ... concise ... as unit files.
Problem #5: Ubuntu 14.04 LTS has reached end-of-life.
You should upgrade to 16.04 LTS or preferably 18.04 LTS. It is unwise to use an end-of-life operating system for your production server(s).
Note that there is a lot of documentation, and many articles on the web about both the old and new ways of configuring services. ( Google is your friend. )
Much thanks to #Stephne C's detailed answer. After some seach I found spring boot offer an out-of-box service practice Here for Ubuntu and CentOS.
The main mistake I made is not package my project as executable jar.
To make springboot jar executable, edit POM file, add <executbale> tag into <configuration> tag of spring-boot-maven-plugin as blow:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
Package and upload the new executable jar to the server
chown the jar to a nologin user, the service will run by it's owner.
chmod 500 the jar to give it executable permission.
add a soft link to /etc/init.d to regsiter it as a service.
run the service, so far so good.
But as #Stephen C said, the default option is neither secure enough nor very up-to-date. I think is better to just package a fat jar and configure the service by hand in production enviornment.

How to properly start a script generated by gradle using upstart?

I'm trying to deploy an Java app onto VPS. I'm using Gradle build system with 'application' plugin. I want the app to start up with the server.
During deployment process I run ./gradlew install to prepare run scripts. When ran directly, they work properly.
I used http://www.whiteboardcoder.com/2014/02/ubuntu-upstart-job-with-java-jar.html as a base for upstart configuration:
description "the test server"
start on runlevel [2345]
stop on runlevel [!2345]
expect fork
script
cd /opt/testserver/
exec ./build/install/testserver/bin/testserver
end script
But the PID reported by upstart after running start testserver is different then the one found using ps. My guess is that the reason for that is the last line of generated script:
exec "$JAVACMD" "${JVM_OPTS[#]}" -classpath "$CLASSPATH" mypackage.TestServer"$#"
As a result Upstart is not able to stop the app. Is there a way to make upstart see the right PID?
Well it looks like there is no forking going on here, so you should try removing the expect fork bit.

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?
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:
Installation as an init.d service
Installation as a systemd service
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
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.
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
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.
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 .
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
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.
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.

Run a java program in backend

Hi all i want to run a java application as backend process.that is like tomcat server.For that i had developed one application.and made one class as main class and calling from one script file .i.e(startup.sh) file.in startup.sh file i was calling one class.that is MainMethodClass.In main method class i had written my business logic.when i am running this app in linux server from using putty is is working until putty window is not closed.As closed after putty window it is also stopped.but i need to run this app even i closed also.How can i achieve this.
Nohup will detach a process you run from your current console and let it continue when you close the terminal. Run something like this.
nohup java -jar my.jar &
By default it will pipe the output to nohup.out, so if you don't want that you could try:
nohup java -jar my.jar > /dev/null &
This problem is not related to java, its actually something related to the way linux operates.
You need to do following:
nohup <your_application_command> &
Note the "nohup" and "&" at start and end respectively.
You should be able to do something like:
nohup java -jar MyApplication.jar &
On a linux machine you can create a service for your jar( executable jar like spring boot )
# Set the Application as Service
ln -s $APP_BASE/bin/$APP_NAME.jar /etc/init.d/$APP_NAME
echo "Starting the application as service"
service $APP_NAME start

Categories

Resources