springboot 배포 스크립트 이해

시작하며

f-lab 멘토링을 시작한지 어느덧 2개월이 지났다. 이제 프로젝트를 해야하는데 CI/CD를 구성하며 배포 스크립트를 구성하며 잘 모르는 내용들이 많아 정리를 해보려고 한다. 회사에서는 AWS의 Elastic Beanstalk를 사용해서 배포 스크립트를 작성할 필요가 없없는데 프로젝트에서는 ncloud 서버를 이용하기 때문에 배포 스크립트를 작성해주어야 했다.

 

배포 스크립트

echo "> write-now pid 확인"

JAR_PATH=/deploy
CURRENT_PID=$(ps -ef | grep java | grep write-now | grep -v nohup | awk '{print $2}')

echo "$CURRENT_PID"

if [ $CURRENT_PID -z ]; then
    echo "> 현재 구동중인 어플리케이션이 없으므로 종료하지 않습니다."
else
    echo "> sudo kill -9 $CURRENT_PID"
    sudo kill -9 $CURRENT_PID
    sleep 3
fi

echo "> write-now 배포"

JAR_NAME=$(ls -tr /deploy/ | grep jar | tail -n 1)

echo "> JAR Name: $JAR_NAME"

nohup java -jar $JAR_PATH/$JAR_NAME > /deploy/nohup.out 2>&1 &

 

JAR_PATH = /deploy

sh 파일에서 변수를 지정하는 방법은 변수명 = 값 이다. 위 타이틀의 의미는 jar파일이 위치한 경로가 /deploy라는 것이다.

CURRENT_PID=$(ps -ef | grep java | grep write-now | grep -v nohup | awk '{print $2}')

똑같이 변수명을 할당하는 코드이다. CURRENT_PID 변수명에 값을 할당하는 것인데 값이 복잡해보인다. 하나씩 살펴보자.

  • ps -<option>
    • ps는 서버에서 구동 중인 프로세스를 조회할 때 사용하는 명령어이다.
    • ps 명령어를 쳤을 때 나오는 항목은 UID(프로세스 소유자), PID(프로세스 식별자) 등이 있다.
    • -e는 커널에서 구동 중인 프로세스를 제외한 모든 프로세스를 출력하라는 옵션이다.
    • -f는 full 포맷으로 출력하라는 옵션이다. 유닉스 스타일이라고 한다.
    • 이외에도 다양한 옵션들이 있다.
  • |
    • 해당 명령어는 파이프 역할을 한다. 즉 | 왼편의 명령어의 표준 출력을 | 오른편으로 전달하는 역할을 한다.
  • grep <값> 
    • grep은 필터링을 하는 명령어이다. 예를들어 "grep java" 명령어의 의미는 입력 값에서 java 라는 단어가 있는 문자열을 출력하라는 의미이다.
    • -v는 <값>을 포함하지 않는 문자열을 출력하라는 의미이다. 예를들어 배포 스크립트에서 "grep -v nohup" 은 nohup을 포함하지 않는 문자열을 출력하라는 의미이다.
  • awk pattern {action}
    • awk는 여러 행(record)과 열(field)로 구성되어 있는 입력 값에서 pattern 또는 action에 따른 출력을 하는 명령어이다.
    • 배포 스크립트를 예시로 보면 awk '{print $2}' 는 입력으로 넘어온 프로세스 항목들 중 2번째 열의 값을 출력하라는 의미이다. ps -ef를 하면 두번째 항목은 PID이다.

종합해서 설명해보자면 현재 구동 중인 프로세스 항목 중에 필터링을 거쳐 결론적으로 PID 값을 출력해 CURRENT_PID 변수에 할당하는 것이다.

if [ 조건문 ]; then ... else ... fi

쉘 스크립트에서 사용하는 조건문이다. [] 안에는 조건문이 위치한다. 조건문에서 -z 는 값이 빈 문자열이면 true를 반환한다는 조건 옵션이다. 배포 스크립트를 예로 설명하자면 CURRENT_PID 값이 빈 문자열, 즉 현재 구동 중인 어플리케이션이 없으면 echo "..."를 수행하고 아니면 else 안에 있는 명령어를 수행한다. fi 는 조건문의 끝을 의미한다.

kill -9 $CURRENT_PID

kill 명령어는 프로세스에 특정한 시그널을 보낼 때 사용하는 명령어이다. 보통 프로세스를 종료시킬 때 사용한다.

-9 옵션은 프로세스를 종료하는 시그널 옵션이다. kill -9 $CURRENT_PID는 CURRENT_PID에 해당하는 프로세스를 종료시키라는 의미이다.

ls -tr /deploy/

ls 명령어는 디렉토리 안에 있는 파일, 디렉토리를 출력할 때 사용한다. ls 명령어에는 다양한 옵션이 있는데 그 중 많이 사용되는 옵션에 대해 알아보자

  • -a : 숨겨져 있는 파일 또는 디렉토리를 포함해 출력한다.
  • -r : 파일 또는 디렉토리를 역순으로 보여준다. 기본적으로는 알파벳 순으로 보여준다.
  • -l : 자세한 내용을 출력한다. 퍼미션(권한), 포함된 파일수, 소유자, 그룹, 파일크기, 수정일자, 파일이름
  • -h : 파일 사이즈 등을 사람이 보기 좋게 변환하여 출력한다.
  • -t : 수정시간에 따라 정렬한다. 새로 만들어진게 첫번째이다.

이외에도 다양한 옵션들이 있으니 필요 시에 찾아보자. 그럼 ls -tr /deploy/ 의 의미는 무엇일까? ls 명령어는 기본적으로 현재 위치 기준으로 작동한다. ls -옵션 <file> 이렇게 하면 file 기준으로 ls 명령어를 실행한다. 리눅스에서는 디렉토리도 개념적으로 하나의 파일로 취급한다고 한다. 결론적으로 deploy 디렉토리를 기준으로 수정시간 순, 알파벳 역순으로 출력하라는 의미이다.

tail -n 1

tail 명령어는 로그 파일과 같이 실시간으로 변하는 파일에 정보를 출력할 때 유용하게 사용되는 명령어이다. -n은 마지막 줄부터 인자 만큼까지를 출력하게 하는 옵션이다. 즉 tail -n <숫자> 이런 식으로 사용한다. 따라서 tail -n 1은 마지막줄만 출력하라는 의미이다.

 

JAR_NAME=$(ls -tr /deploy/ | grep jar | tail -n 1) 이 명령어를 위해서 살펴본 바에 따라 해석해보자면

 

1. deploy 디렉토리를 수정시간순, 알파벳 역순으로 출력하고 이를 파이프로 넘긴다.2. jar 문자열이 포함된 문자열을 출력한다. 즉 jar 파일을 찾는다.3. jar 파일이 여러개일 수 있으므로 그 중 하나를 찾는다. 

 

이런 의미이다.

nohup과 & 

nohup java -jar $JAR_PATH/$JAR_NAME > /deploy/nohup.out 2>&1 & 

 

위 명령어에서 맨 처음 nohup 명령어가 있고 맨 마지막에 & 명령어가 있다. 이 두 명령어는 비슷한 역할을 한다. 바로 리눅스 터미널과의 연결이 끊겨도 프로세스가 지속되게끔 한다. 엄밀히 말하면 프로세스의 지속은 nohup 명령어에 해당하고 &는 백그라운드에서 실행되게끔 하는 것이다. 그러나 & 명령어의 디폴트 옵션에 세션이 끊겨도 프로세스가 지속되게끔 반영 되었다고 한다. 

 

nohup 명령어로 프로세스를 실행하면 프로세스에서 실행되는 프로그램의 표준출력을 nohup 명령어가 실행된 경로에 nohup.out 파일에 출력한다. 그런데 nohup java -jar $JAR_PATH/$JAR_NAME > /deploy/nohup.out 이렇게 하게 되면 프로그램의 표준출력을 deploy 디렉토리의 nohup.out으로 리다이렉트 하겠다는 의미이다.

 

그럼 2>&1 의 의미는 무엇일까? 프로그램의 표준입출력, 에러는 숫자로 나타내어진다. 0이 표준입력, 1이 표준출력, 2가 표준에러이다. > 는 리다이렉트하는 명령어이고 &1에서 &는 1이 표준 출력 일련번호로 인식되도록 붙여주는 것이다. 즉 2>&1의 의미는 표준에러도 표준출력이 쓰여지는 곳으로 리다이렉션하겠다는 의미이다. 

 

한편 배포 스크립트 예시들을 보면 nohup ... > /dev/null 이런 명령어가 자주 보인다. dev 디렉토리는 리눅스 운영체제가 관리하는 장치들에 대한 내용들이 담긴 곳이다. /dev/null 에서 null은 데이터를 없애는 휴지통? 같은 역할을 한다. 즉 프로그램 실행 시 표준출력에 대해 화면에 출력하거나 파일에 보관하지 않고 날려버리겠다는 명령어이다.

 

결론적으로 nohup java -jar $JAR_PATH/$JAR_NAME > /deploy/nohup.out 2>&1 &  명령은

 

1. jar 파일을 실행하는데 실행 시 표준출력을 /deploy/nohup.out에 저장하고

2. 표준에러도 표준출력이 보관되는 곳에 리다이렉트 하며

3. 백그라운드로 실행하고 세션이 끊겨도 실행이 유지되게

 

한다는 것이다.

마치며

리눅스 명령어는 할 때마다 많이 찾아보는 것 같다. 잘 사용하지 않아서 익숙해지지 않는 듯하다. 하지만 백엔드 개발자라면 대부분 리눅스 서버를 이용하기 때문에 리눅스 명령어에 익숙해지고 쉘 스크립트에 대한 이해도 갖춰야 할 것 같다. 공부 할 게 참 많다!

 

참고자료

https://yozm.wishket.com/magazine/detail/2103/

 

백엔드 개발자라면 알아야 할 리눅스 필수 명령어 21개 | 요즘IT

백엔드 개발자가 아니면 리눅스를 사용할 일이 거의 없습니다. 그러므로 백엔드 입문자인 여러분께 리눅스 명령어는 낯설기 마련입니다. 명령어는 방대하기 때문에 처음부터 모든 명령어를 다

yozm.wishket.com

https://blog.naver.com/PostView.nhn?blogId=tmk0429&logNo=222318530824

 

ps 명령어 및 옵션 - 리눅스 프로세스 관리 [Linux 명령어]

리눅스는 여러 프로세스가 동시에 수행될 수 있는 시스템입니다. 프로세스는 두 가지로 나뉘게 되는데 하나...

blog.naver.com

https://nice-engineer.tistory.com/entry/Linux-%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%AA%85%EB%A0%B9%EC%96%B4-%ED%8C%8C%EC%9D%BC-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EB%AA%85%EB%A0%B9%EC%96%B4grep

 

[Linux] 리눅스 명령어 - 파일 입출력 명령어(grep)

✅ grep 명령어 입력으로 전달된 파일의 내용에서 특정 문자열을 찾고자할 때 사용하는 명령어 파일의 문자열을 검색할 때, 단순 문자열 매칭이 아닌 정규 표현식에 의한 패턴 매칭 방식을 사용

nice-engineer.tistory.com

https://withcoding.com/89

 

리눅스 ls 명령어 사용법, 옵션 정리 (디렉토리 내용 출력 명령어)

리눅스 ls 명령어 (list) 리눅스(Linux)에서는 ls 명령어를 사용하여 디렉토리(directory)에 있는 내용(디렉토리, 파일 등)을 확인한다. 윈도우(또는 도스)의 dir 명령과 비슷하다. (리눅스에도 dir 명령이

withcoding.com

https://coding-factory.tistory.com/801

 

[Linux] 리눅스 tail 명령어 사용법 (실시간 로그 보기)

리눅스에서 tail 명령어는 일반적으로 로그와 같이 시간에 따라 변하는 파일들을 grep과 같은 명령어로 조합해서 실시간으로 업데이트되는 로그를 분석하는데 많이 사용됩니다. tail 명령어 tail 명

coding-factory.tistory.com

https://joonyon.tistory.com/entry/쉽게-설명한-nohup-과-백그라운드-명령어-사용법

 

쉽게 설명한 nohup 과 &(백그라운드) 명령어 사용법

안녕하세요. 린아저씨 입니다. 리눅스를 사용하다 보면 프로그램을 백그라운드에서 세션과의 연결이 끊어져도 돌려야할 일이 많이 발생합니다. 그럴때 주로 사용하는 명령어가 바로 nohup 과 &

joonyon.tistory.com

https://inpa.tistory.com/entry/리눅스-devnull-리다이렉션-기호-종류

 

🐧 /dev/null 2>&1 명령어 의미 - 완벽 이해하기

리눅스 리다이렉션 2>&1 는 표준에러를 표준출력으로 redirection 하라는 의미이다. 보통 프로그램에서 에러가 발생하면, 화면에 에러메세지를 표시해서 사용자에게 경고를 주게 된다. 이러한 기본

inpa.tistory.com

 

'Infra' 카테고리의 다른 글

모니터링 환경 구축(Spring actuator, Prometheus, Grafana)  (0) 2023.12.16
HTTP란?  (0) 2023.12.14
Auto scaling 작동원리  (1) 2023.11.30