Running your Sprint Boot App on EC2
In this post I wanted to quickly document how you can run your Spring Boot application on an EC2 instance.
Why systemd
There are many ways to run Spring Boot applications in the cloud.
A popular one is using a container orchestration offering like AWS Elastic Container Service, where you would wrap your Spring Boot application in a container and have it deployed via ECS.
Sometimes however you want something setup quick and dirty, without the overhead of setting up ECS , loadbalancers and targetgroups.
That’s where EC2 and systemd come into play.
The use-case here being the need to run a Spring Boot application on an EC2 instance without too much hassle.
I’m going to be using Amazon Linux 2023 as the base EC2 instance image.
ssh ec2
, #_
~\_ ####_ Amazon Linux 2023
~~ \_#####\
~~ \###|
~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023
~~ V~' '->
~~~ /
~~._. _/
_/ _/
_/m/'
systemd is available on the Amazon Linux 2023 as you can see by the output of the systemctl list-unit-files | grep enabled
command.
systemd has the notion of services defined in service files that are located in the /etc/systemd/system
folder
-rw-r--r--. 1 root root 616 Sep 26 15:34 amazon-cloudwatch-agent.service
drwxr-xr-x. 2 root root 6 Oct 25 18:44 httpd.service.d
drwxr-xr-x. 2 root root 50 Nov 10 19:54 network-online.target.wants
lrwxrwxrwx. 1 root root 43 Nov 10 19:54 dbus.service -> /usr/lib/systemd/system/dbus-broker.service
lrwxrwxrwx. 1 root root 48 Nov 10 19:54 dbus-org.freedesktop.resolve1.service -> /usr/lib/systemd/system/systemd-resolved.service
lrwxrwxrwx. 1 root root 48 Nov 10 19:54 dbus-org.freedesktop.network1.service -> /usr/lib/systemd/system/systemd-networkd.service
drwxr-xr-x. 2 root root 35 Nov 10 19:54 basic.target.wants
drwxr-xr-x. 2 root root 32 Nov 10 19:54 getty.target.wants
lrwxrwxrwx. 1 root root 37 Nov 10 19:54 ctrl-alt-del.target -> /usr/lib/systemd/system/reboot.target
drwxr-xr-x. 2 root root 35 Nov 10 19:54 chronyd.service.wants
drwxr-xr-x. 2 root root 109 Nov 10 19:54 sockets.target.wants
drwxr-xr-x. 2 root root 31 Nov 10 19:54 remote-fs.target.wants
drwxr-xr-x. 2 root root 33 Nov 10 19:54 rpc-statd.service.requires
drwxr-xr-x. 2 root root 33 Nov 10 19:54 rpc-statd-notify.service.requires
drwxr-xr-x. 2 root root 33 Nov 10 19:54 rpc-gssd.service.requires
drwxr-xr-x. 2 root root 33 Nov 10 19:54 nfs-server.service.requires
drwxr-xr-x. 2 root root 33 Nov 10 19:54 nfs-mountd.service.requires
drwxr-xr-x. 2 root root 33 Nov 10 19:54 nfs-idmapd.service.requires
drwxr-xr-x. 2 root root 33 Nov 10 19:54 nfs-blkmap.service.requires
drwxr-xr-x. 2 root root 64 Nov 10 19:54 sysstat.service.wants
drwxr-xr-x. 2 root root 212 Nov 10 19:55 sysinit.target.wants
drwxr-xr-x. 2 root root 119 Nov 10 19:55 cloud-init.target.wants
drwxr-xr-x. 2 root root 44 Nov 10 19:55 systemd-homed.service.wants
lrwxrwxrwx. 1 root root 45 Nov 10 19:55 dbus-org.freedesktop.home1.service -> /usr/lib/systemd/system/systemd-homed.service
drwxr-xr-x. 2 root root 74 Nov 10 19:55 timers.target.wants
drwxr-xr-x. 2 root root 16384 Dec 8 15:47 multi-user.target.wants
Defining our Spring Boot service
So lets start our favorite editor and issue the following command to create a new systemd service defintion for our spring-boot-docker-memory-demo
application
sudo vi /etc/systemd/system/spring-boot-docker-memory-demo.service
We’ll provide the following service configuration. Notice how we use the Restart
properties to ensure that our service will always be up and running, even after it has been killed
[Unit]
Description=spring-boot-docker-memory-demo
After=syslog.target
[Service]
User=ec2-user
ExecStart=/spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar
SuccessExitStatus=143
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
There are lots of systemd options to explore but we’re going to be leaving it at that.
To enable our systemd service just issue this command
sudo systemctl enable spring-boot-docker-memory-demo.service
Created symlink /etc/systemd/system/multi-user.target.wants/spring-boot-docker-memory-demo.service → /etc/systemd/system/spring-boot-docker-memory-demo.service.
Now at this point our systemd service is active but hasn’t started yet.
[ec2-user@ip-172-31-0-241 /]$ sudo systemctl status spring-boot-docker-memory-demo.service
○ spring-boot-docker-memory-demo.service - spring-boot-docker-memory-demo
Loaded: loaded (/etc/systemd/system/spring-boot-docker-memory-demo.service; enabled; preset: disabled)
Active: inactive (dead)
For the service to start we need to issue the sudo systemctl start spring-boot-docker-memory-demo.service
command
[ec2-user@ip-172-31-0-241 /]$ sudo systemctl status spring-boot-docker-memory-demo.service
● spring-boot-docker-memory-demo.service - spring-boot-docker-memory-demo
Loaded: loaded (/etc/systemd/system/spring-boot-docker-memory-demo.service; enabled; preset: disabled)
Active: active (running) since Sat 2023-12-09 16:52:29 UTC; 18s ago
Main PID: 5913 (spring-boot-doc)
Tasks: 29 (limit: 1114)
Memory: 109.0M
CPU: 6.160s
CGroup: /system.slice/spring-boot-docker-memory-demo.service
├─5913 /bin/bash /spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar
└─5928 /usr/bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -jar //spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar
Dec 09 16:52:32 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: :: Spring Boot :: (v3.1.4)
Dec 09 16:52:32 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: 2023-12-09T16:52:32.171Z INFO 5928 --- [ main] .s.SpringBootDockerMemoryDemoApplication : Starting SpringBootDockerMemoryDemoApplication v0.0.>
Dec 09 16:52:32 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: 2023-12-09T16:52:32.174Z INFO 5928 --- [ main] .s.SpringBootDockerMemoryDemoApplication : No active profile set, falling back to 1 default pro>
Dec 09 16:52:34 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: 2023-12-09T16:52:34.537Z INFO 5928 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
Dec 09 16:52:34 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: 2023-12-09T16:52:34.560Z INFO 5928 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
Dec 09 16:52:34 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: 2023-12-09T16:52:34.561Z INFO 5928 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.13]
Dec 09 16:52:34 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: 2023-12-09T16:52:34.959Z INFO 5928 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
Dec 09 16:52:34 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: 2023-12-09T16:52:34.961Z INFO 5928 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed>
Dec 09 16:52:36 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: 2023-12-09T16:52:36.241Z INFO 5928 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context >
Dec 09 16:52:36 ip-172-31-0-241.eu-central-1.compute.internal spring-boot-docker-memory-demo-0.0.1-SNAPSHOT.jar[5928]: 2023-12-09T16:52:36.287Z INFO 5928 --- [ main] .s.SpringBootDockerMemoryDemoApplication : Started SpringBootDockerMemoryDemoApplication in 5.1>
[ec2-user@ip-172-31-0-241 /]$
Inspecting log files
When the service is started you can inspect the logs using we can check the logs by issuing the journalctl -u spring-boot-docker-memory-demo
command
Once the service is started, you will see that your service will always be up and running, even
- After restarting your ec2 instances
- Killing your java process using the
kill
command