I've had a hard time running a resident Java (and a language running on a JVM such as Scala) application as a daemon on AWS EC2 (though not specifically limited to EC2), so I'll leave it here.
Aside from "EC2 ??" ...
Create an rc script to start your Java application as a Linux service.
There are various styles of rc scripts, but I think that at least this is fine. In (Init.d and Start Scripts for Scala / Java Server Apps I customized it a little based on the contents introduced)
, but it is safer to explicitly specify
-Duser.timezone = UTC` as it can change unexpectedly.stop
, do not force the JVM process to be killed. (If you force kill, the shutdown hook will not be executed)/etc/init.d/example
#!/bin/bash
### BEGIN INIT INFO
# Provides: example
# chkconfig: 2345 99 99
# Required-Start: $local_fs $network $named networking
# Required-Stop: $local_fs $network $named networking
# Short-Description: example
# Description: example
### END INIT INFO
DAEMON_NAME=example
DAEMON_DIR=/home/ec2-user/example
MODULE_NAME=example-server
START_SCRIPT="java -Duser.timezone=UTC -jar $DAEMON_DIR/$MODULE_NAME.jar"
#The process ID file is/var/Create under run
PID_FILE=/var/run/$DAEMON_NAME.pid
#Lock file/var/lock/Create under subsys
#If you do not create a lock file, the service will not be stopped when you shut down the machine.
LOCK_FILE=/var/lock/subsys/$DAEMON_NAME
# ***********************************************
# ***********************************************
ARGS="" # optional start script arguments
DAEMON=$START_SCRIPT
# colors
red='\e[0;31m'
green='\e[0;32m'
yellow='\e[0;33m'
reset='\e[0m'
echoRed() { echo -e "${red}$1${reset}"; }
echoGreen() { echo -e "${green}$1${reset}"; }
echoYellow() { echo -e "${yellow}$1${reset}"; }
start() {
# $!Save the process ID of the process started in (Write it to the process ID file later)
PID=`$DAEMON $ARGS > /dev/null 2>&1 & echo $!`
}
case "$1" in
start)
if [ -f $PID_FILE ]; then
PID=`cat $PID_FILE`
echo $PID
if [ -z "`ps axf | grep -w ${PID} | grep -v grep`" ]; then
start
else
echoYellow "Already running [$PID]"
exit 0
fi
else
start
fi
if [ -z $PID ]; then
echoRed "Failed starting"
exit 3
else
#If the service can be started normally, create a process ID file and lock file.
echo $PID > $PID_FILE
touch $LOCK_FILE
echoGreen "Started [$PID]"
exit 0
fi
;;
status)
if [ -f $PID_FILE ]; then
PID=`cat $PID_FILE`
if [ -z "`ps axf | grep -w ${PID} | grep -v grep`" ]; then
echoRed "Not running (process dead but pidfile exists)"
exit 1
else
echoGreen "Running [$PID]"
exit 0
fi
else
echoRed "Not running"
exit 3
fi
;;
stop)
if [ -f $PID_FILE ]; then
PID=`cat $PID_FILE`
if [ -z "`ps axf | grep -w ${PID} | grep -v grep`" ]; then
echoRed "Not running (process dead but pidfile exists)"
exit 1
else
PID=`cat $PID_FILE`
#When stopping the process-Do not kill at 9
#When forced to terminate, the shutdown hook is not executed and the processing being executed ends in the middle.
kill -HUP $PID
echoGreen "Stopped [$PID]"
#If the service can be stopped normally, delete the process ID file and lock file.
rm -f $PID_FILE
rm -f $LOCK_FILE
exit 0
fi
else
echoRed "Not running (pid not found)"
exit 3
fi
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: $0 {status|start|stop|restart}"
exit 1
esac
Deploy the implemented application module and rc script to the EC2 instance.
Here is an example of a template for building EC2 with Cloud Formation.
chkconfig
, the application will be automatically started / stopped when the EC2 instance is started / stopped. (Reference: Run a shell on EC2 at startup or terminate
)EC2AutoScalingConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Metadata:
# CloudFormation:Settings to enable Init to get resources from S3
AWS::CloudFormation::Authentication:
S3AccessCreds:
type: S3
roleName:
Ref: EC2Role
buckets:
-S3 bucket name where modules etc. are stored
#EC2 instance initialization process. Get the module from S3 and deploy it.
AWS::CloudFormation::Init:
configSets:
Setup:
- PreDeploy
- DeployExampleServer
- PostDeploy
- StartApplication
#Preprocessing. Installation of required packages, etc. It is better to keep it in AMI.
PreDeploy:
packages:
yum:
java-1.8.0-openjdk-devel: []
awslogs: []
files:
/home/ec2-user/awslogs-agent-setup.py:
source: https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py
mode: "000755"
/home/ec2-user/awslogs.conf:
content: |+
[general]
state_file = /var/lib/awslogs/agent-state
[/var/log/messages]
log_group_name = /example/ec2
log_stream_name = {instance_id}-sysmsg
file = /var/log/messages
datetime_format = %b %d %H:%M:%S
buffer_duration = 5000
initial_position = start_of_file
commands:
SetDefaultJVM:
command: alternatives --set java /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java
#Deploy application
DeployExampleServer:
files:
#Get module from S3
/home/ec2-user/example/example-server.jar:
source:
Fn::Sub: https://s3-${AWS::Region}.amazonaws.com/S3 bucket name where modules etc. are stored/example-server-1.0.0.jar
owner: ec2-user
group: ec2-user
#Get rc script from S3
/home/ec2-user/example/example:
source:
Fn::Sub: https://s3-${AWS::Region}.amazonaws.com/S3 bucket name where modules etc. are stored/example
owner: ec2-user
group: ec2-user
mode: "000755"
#Transfer the log output by the application to CloudWatch with awslogs
/home/ec2-user/example/conf/awslogs.conf:
content: |+
[example]
log_group_name = /example/example-server
log_stream_name = {instance_id}-{{name}}
file = /root/logs/example.log
encoding = utf_8
datetime_format = %Y/%m/%d %H:%M:%S.%f
time_zone = UTC
buffer_duration = 5000
initial_position = start_of_file
multi_line_start_pattern = {datetime_format}
owner: ec2-user
group: ec2-user
#A cron schedule that automatically restarts the application's JVM process when it goes down
/home/ec2-user/example/conf/cron.conf:
content: |+
*/5 * * * * /sbin/service example start > /dev/null 2>&1
owner: ec2-user
group: ec2-user
#Note that if you write multiple commands in commands, they will be executed in alphabetical order.
commands:
#Place the rc script (/etc/init.d Below symbolic link)
A_RegisterService:
command: ln -s /home/ec2-user/example /etc/init.d/example
#Add with chkconfig and set the application to start / stop automatically when the EC2 instance starts / stops
B_AddChkconfig:
command: chkconfig --add example && chkconfig example on
C_AppendAwsLogsConf:
command: cat /home/ec2-user/example/conf/awslogs.conf >> /home/ec2-user/awslogs.conf
D_AppendCrontab:
command: cat /home/ec2-user/example/conf/cron.conf >> /home/ec2-user/cron.conf
PostDeploy:
commands:
A_PipUpgrade:
command:
pip install --upgrade pip
B_ConfigureAwsLogs:
command:
Fn::Sub: python /home/ec2-user/awslogs-agent-setup.py -n -r ${AWS::Region} -c /home/ec2-user/awslogs.conf
C_ConfigureCron:
command: crontab /home/ec2-user/cron.conf
services:
sysvinit:
awslogs:
enabled: true
ensureRunning: true
crond:
enabled: true
ensureRunning: true
StartApplication:
commands:
A_ManagedContentsSynchronizer:
command: service example start
Properties:
:
UserData:
Fn::Base64:
Fn::Sub: |+
#!/bin/bash
#Give the launched EC2 instance a descriptive name
INSTANCE_ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`
START_TIME=`date '+%Y%m%d%H%M'`
aws ec2 create-tags --region ${AWS::Region} --resources ${!INSTANCE_ID} --tags Key=\"Name\",Value=example-${!START_TIME}
# ---- Run cfn-init
yum -y update
yum update -y aws-cfn-bootstrap
/opt/aws/bin/cfn-init -v --region ${AWS::Region} --stack ${AWS::StackName} --resource EC2AutoScalingConfig --configsets Setup
that's all.
Recommended Posts