catsridingCATSRIDING|OCEANWAVES
Ops

AWS EC2 재부팅시 자동으로 Spring Boot 애플리케이션 구동하기

jynn@catsriding.com
Feb 03, 2024
Published byJynn
999
AWS EC2 재부팅시 자동으로 Spring Boot 애플리케이션 구동하기

Run Spring Boot Application Automatically on AWS EC2 Reboot

AWS EC2 인스턴스가 예기치 못한 장애나 서버 문제로 인해 재시작되는 상황에 대비하여, Spring Boot 애플리케이션을 자동으로 구동되도록 설정하는 것은 중요합니다. 이러한 설정은 애플리케이션의 안정적인 운용을 보장하며, 예상치 못한 상황에도 불구하고 애플리케이션의 지속적인 가용성을 유지하는 데 큰 도움이 됩니다.

Automatic Script Execution on Reboot

Linux 시스템이 재시작될 때 스크립트가 자동으로 실행되도록 하는 방법은 주로 rc.local을 사용하는 방법과 systemd 서비스로 등록하는 방법이 있습니다.

  • rc.local
    • 이전 Unix System V의 초기화 스크립트 시스템의 일부입니다. 이 rc.local 파일은 시스템이 부팅될 때마다 자동으로 실행되며, 완전히 초기화된 시스템에서 마지막에 실행되는 스크립트입니다.
    • 이 방법의 장점은 가장 간단하며 편리하게 사용할 수 있습니다. 그러나, 해당 서비스의 시작 시간이나 종료 시간을 제어하거나 로깅 등을 관리하기 어렵다는 단점이 있습니다.
  • systemd
    • 대다수의 최신 Linux 배포판에서 사용되는 init 시스템입니다. 서비스를 시작, 종료, 관리하거나 로깅 등 다양한 관리 기능을 제공합니다.
    • 이 방법은 서비스의 종속성을 관리하고 로깅, 오류 처리 등의 고급 기능을 사용할 수 있다는 장점이 있습니다. 그러나 설정이 더 복잡하다는 단점이 있습니다.

rc.local 방식은 해당 위치에 스크립트만 추가하면 되기때문에 간단하지만, 이번 포스팅에서는 다양한 상황에 대비할 수 있는 systemd에 새로운 서비스를 추가하는 방식으로 진행하였습니다.

Registering as a System Service

systemd를 활용하여 지속적으로 실행되어야 하는 애플리케이션을 기본적인 Linux 서비스로 등록하는 과정에 대해 살펴봅니다.

  • OS: Amazon Linux 2023
  • Connection: SSH

Writing Script to Execute Jar

EC2 인스턴스 구동시 .jar 파일을 실행할 스크립트를 작성합니다. 서비스에서 바로 java -jar 명령어를 실행하도록 설정 할 수 있지만, 파일명이 변경된다거나 추가적인 작업이 필요한 경우를 대비하여 스크립트로 작업하였습니다.

실행하려는 .jar 파일과 동일한 경로에 .sh 스크립트를 생성합니다:

start.sh
JAR_NAME=$(ls -tr | grep jar | tail -n 1)
java -jar -Dspring.profiles.active=prod $JAR_NAME >> nohup.out 2>&1
  • 가장 최근에 수정된 .jar 파일의 이름을 변수 JAR_NAME에 저장합니다.
    • ls -tr: 현재 디렉토리의 파일들을 오래된 것부터 새로운 순으로 나열합니다. -t 옵션은 시간 순으로 정렬하라는 의미이고, -r 옵션은 내림차순 정렬을 의미합니다.
    • grep jar: 이름에 jar라는 문자열이 포함된 파일들만 필터링합니다.
    • tail -n 1: tail 명령은 파일의 마지막 부분을 출력하는데 사용되며, -n 1 옵션은 마지막 1라인만 출력하라는 의미입니다. 이렇게 해서 가장 최근에 수정된 jar 파일 하나를 선택하게 됩니다.
  • 선택한 jar 파일을 Java 애플리케이션으로 실행합니다.
    • $JAR_NAME: 위에서 설정한 jar 파일 이름을 참조합니다.
    • >> nohup.out: 표준 출력(Standard Output)을 nohup.out 파일로 리디렉션하며, 기존 파일 내용에 이어서 출력이 기록됩니다.
    • 2>&1: 표준 에러 출력(Standard Error)을 표준 출력(Standard Output)으로 리디렉션 합니다. 이는 표준 에러와 표준 출력이 모두 같은 위치, 즉 󰈮 nohup.out 파일로 이동하게 됩니다. 여기서 2는 표준 에러를, 1은 표준 출력을 나타냅니다.

이 스크립트는 가장 최근에 수정된 .jar 파일을 찾아서, Spring의 prod 프로파일로 실행하며, 그 로그를 nohup.out 파일에 저장하는 역할을 합니다.

Creating System Daemon Service

다음은 새로운 서비스를 등록하기 위한 .service 파일을 생성합니다:

$ sudo vim /etc/systemd/system/{service-name}.service
  • /etc/systemd/system/ 디렉토리는 systemd가 시스템 시작 시 자동으로 스크립트를 실행하도록 하기 위한 서비스 파일들을 저장하는 위치입니다. 여기에 서비스 파일을 추가하면, 해당 서비스는 시스템 부팅 시에 자동으로 시작하도록 설정할 수 있습니다.
  • *.service 파일은 특정 서비스를 실행하고 관리하는 방법에 대한 systemd에게 가이드를 제공하는 설정 파일입니다.

그리고 여기에 서비스 실행에 필요한 스크립트를 작성합니다:

waves.service
[Unit]
Description=Waves Application
After=network.target multi-user.target

[Service]
WorkingDirectory=/home/ec2-user
ExecStart=/bin/bash /home/ec2-user/start.sh
SuccessExitStatus=143
TimeoutStopSec=15
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
  • [Unit]:
    • 서비스의 메타 정보와 해당 서비스가 언제 실행되어야 하는지에 대한 의존 관계를 설정합니다.
    • Description: 해당 서비스에 대한 설명을 제공합니다.
    • After: 해당 서비스가 어떤 대상을 기다렸다가 실행되어야 하는지 나열합니다. 여기선 주요 서비스들이 실행된 이후에 지정한 스크립트가 실행되도록 network.targetmulti-user.target을 추가하였습니다.
  • [Service]:
    • 해당 서비스의 작동 방식을 정의합니다.
    • WorkingDirectory: 서비스가 실행될 때 작업 디렉토리를 지정합니다.
    • ExecStart: 서비스 시작 시 실행할 명령을 지정합니다. 앞서 작성한 start.sh 스크립트가 실행되도록 구성하였습니다.
    • SuccessExitStatus: 서비스가 성공적으로 종료되었다는 신호를 보내는 데 사용되는 종료 상태 코드를 지정합니다. 여기에서는 143을 성공적인 종료 코드로 지정하였습니다.
    • TimeoutStopSec: 서비스를 중지시키기 위해 systemd가 기다리는 최대 시간을 설정합니다.
    • Restart: 서비스가 실패했을 때 자동으로 재시작되어야 하는지 지정합니다.
    • RestartSec: 서비스가 실패한 후 재시작 전에 대기해야 하는 시간을 지정합니다.
  • [Install]:
    • 서비스가 어떻게 설치되어야 하는지에 대한 정보를 제공합니다. 이는 systemctl enable 명령을 사용할 때 적용됩니다.
    • WantedBy: 이 서비스가 활성화되는 대상을 지정합니다. 여기선 multi-user.target에 의해 활성화되도록 설정하였습니다. 즉, 시스템이 multi-user run level로 변경될 때 해당 서비스가 시작되도록 설정하는 것입니다.

변경 사항을 저장하고 나서 systemd에 새 서비스 파일이 있다는 것을 알려야 합니다:

$ sudo systemctl daemon-reload

그리고 서비스를 자동 시작 설정에 추가합니다:

$ sudo systemctl enable waves

이제 EC2 인스턴스 리부팅 시에 추가한 waves.service가 자동으로 시작됩니다. 작성한 서비스가 정상적으로 동작하는지 확인하려면 아래 명령어를 통해 수동으로 서비스를 시작할 수 있습니다:

$ sudo systemctl start waves
  • Spring
  • Linux
  • AWS