산보실록 서비스를 올릴 물리 서버가 들어오면서, 드디어 운영 단계를 앞두게 되었다.
이후, 운영과 유지보수를 위해 Spring으로 전환하는 과정에서 수월한 유지보수를 위해 CI/CD를 구축하기로 결정했다.
지원 받은 물리 서버의 인프라 구축이 완료되기 전, 프론트엔드 개발자와 원활한 협업을 위해 EC2와 RDS를 이용해 사전 배포를 진행하게 되었다.
그래서 물리 서버에 CI/CD를 구축하기 전 CI/CD 구축과정을 익히고, 개발을 원활히 하기 위해 EC2 서버에 CI/CD를 구축하는 과정에서 발생한 이슈 해결 과정을 기록하고자 한다.
사용 기술 스택 및 버전
- Github Actions
- Spring Boot 3.2.5
- openjdk 17.0.3
- Gradle 8.7
- MySQL 8.1.0
deploy 과정에서 Spring 설정 파일인 application.yml
에서 EC2 서버의 .bashrc
에 정의한 환경 변수가 제대로 들어가지 않는 문제가 발생했다.
문제가 발생한 스크립트는 다음과 같다.
sshpass -p ${{ secrets.EC2_PASSWORD }} ssh -T -o StrictHostKeyChecking=no ${{ secrets.EC2_USERNAME }}@${{ secrets.EC2_HOST }} "pgrep java | xargs kill -9; nohup java -DATABASE_HOST=${{ secrets.DATABASE_HOST }} -jar sanbosillokserver-0.0.1-SNAPSHOT.jar > nohup.out 2>&1 &"
ssh로 직접 접속 했을 때는 해당 문제가 발생하지 않는 것으로 보아, sshpass
명령어를 사용했을 경우에 발생하는 문제로 보인다.
해당 문제의 원인을 파악하기 위해 다음과 같은 과정을 시도해보았다.
source ~/.bashrc
로 .bashrc
를 로드한 후, echo $DATABASE_NAME
명령어를 workflow에 추가해 환경 변수 출력을 시도해보았다.
아무것도 출력되지 않았다.
프로젝트 빌드 파일에 문제가 있는 것이 아닌, 애초에 .bashrc
의 환경 변수에 접근하지 못하는 것으로 보인다.
환경 변수에 접근하지 못하는 이유가 권한 문제인가 싶어 .bashrc
의 권한을 확인해보았다.
권한은 정상적으로 부여되어 있는 것을 확인할 수 있었다.
다음으로, workflow에서 환경 변수가 정의된 파일의 내용을 읽을 수 있는지 확인하기 위해 .bashrc
의 내용을 출력하는 스크립트를 추가해보았다.
잘 출력되는 것으로 보아, 환경 변수가 정의된 파일에 접근하는 것에는 문제가 없었다.
Linux 환경 변수는 동작 범위에 따라 3가지로 나뉜다.
- 로컬 환경 변수
- 현재 세션에서만 동작.
- 사용자 환경 변수
- 특정 사용자에 대해 정의된 환경 변수로, 로그인할 때마다 로드됨.
.bashrc
,.bash_profile
,.bash_login
,.profile
등에 정의된다.- 시스템 전체 환경 변수
- 해당 시스템의 모든 사용자가 사용 가능.
/etc/evironment
,/etc/profile
,/etc/profile.d
,/etc/bash.bashrc
등에 정의된다.
기존에는 .bashrc에 사용자 환경변수를 정의했었다.
sshpass를 이용하여 원격 접속할 때와 같은 사용자로 접속했기 때문에 문제가 없을 것이라 생각했지만, 혹시 몰라 시스템 전체 환경 변수로 다시 환경 변수를 작성해보았다.
/etc/environment
에 정의한 환경변수를 다시 sshpass로 출력해보았지만, 제대로 출력되지 않았다.
ssh
에서 -T
옵션을 부여해, TTY(TeleTYpewriter)
를 할당하지 않았기 때문에 Non-login Shell로 실행되는 것으로 알고 있었다. 따라서 Non-login Shell에서 로드되는 .bashrc
에 환경 변수를 저장하는 것은 문제가 없다고 생각했었다.
'하지만, 혹시 sshpass가 Non-login Shell 방식이 아니라면 ?' 이라는 생각이 스쳐지나갔다.
그래서 아예 Login Shell 방식을 사용해보기로 했다.
우선, 환경 변수를 .bashrc
가 아닌 .bash_profile
에 다시 정의했다.
그리고 마지막 deploy 스크립트를 다음과 같이 수정했다.
bash -l -c 'pgrep java | xargs kill -9; nohup java -jar sanbosillokserver-0.0.1-SNAPSHOT.jar &'
bash 명령어 옵션
1. -l : Login Shell을 사용하는 옵션
2. -c : 사용할 명령어를 설정하는 옵션
결과적으로 Login Shell 방식을 사용하여, 배포에 성공했다.
열심히 조사해본 결과, ssh
에 -T
옵션을 주면 Non-Login Shell로 실행되는 것이 맞았다. 또한, Non-Login Shell은 일반적으로 .bashrc 혹은 etc/bash.bashrc를 로드한다.
하지만 시스템 설정에 따라, 그렇지 않은 경우도 존재할 수 있는 듯 하다.
이를 알아보고자, .bashrc 파일을 내용을 열어보니, 다음과 같은 내용이 작성되어 있었다.
'If not running interactively, don't do anything'
'대화형 shell이 아니면, 아무것도 하지 않음.'case $- in *i*) ;; *) return;; # 대화형 쉘이 아닌 경우, 스크립트 종료 esac
긴 삽질 끝에, Login Shell
or Non-Login Shell
뿐만 아니라 대화형 Shell
or 비대화형 Shell
또한 환경 설정 파일을 로드하는데 영향을 미칠 수 있다는 점을 알 수 있었다.
친절하게 주석까지 달려있었다니,,,
앞으로 오류를 만나면 꼭 !! 파일을 잘 분석해봐야겠다 !