[Linux] ssh 접속 시, 환경변수를 읽어오지 못하는 이슈

Yangchef·2024년 6월 2일
2

Trouble Shooting

목록 보기
1/1
post-thumbnail

개요

산보실록 서비스를 올릴 물리 서버가 들어오면서, 드디어 운영 단계를 앞두게 되었다.

이후, 운영과 유지보수를 위해 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

Trouble shooting

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 명령어를 사용했을 경우에 발생하는 문제로 보인다.

해당 문제의 원인을 파악하기 위해 다음과 같은 과정을 시도해보았다.

1. 환경 변수 출력 시도

source ~/.bashrc.bashrc를 로드한 후, echo $DATABASE_NAME 명령어를 workflow에 추가해 환경 변수 출력을 시도해보았다.

아무것도 출력되지 않았다.

프로젝트 빌드 파일에 문제가 있는 것이 아닌, 애초에 .bashrc의 환경 변수에 접근하지 못하는 것으로 보인다.

2. 권한 확인

환경 변수에 접근하지 못하는 이유가 권한 문제인가 싶어 .bashrc의 권한을 확인해보았다.

권한은 정상적으로 부여되어 있는 것을 확인할 수 있었다.

3. 환경 변수가 정의된 파일 내용 출력

다음으로, workflow에서 환경 변수가 정의된 파일의 내용을 읽을 수 있는지 확인하기 위해 .bashrc의 내용을 출력하는 스크립트를 추가해보았다.

잘 출력되는 것으로 보아, 환경 변수가 정의된 파일에 접근하는 것에는 문제가 없었다.

4. 시스템 전체 환경 변수로 변경

Linux 환경 변수는 동작 범위에 따라 3가지로 나뉜다.

  1. 로컬 환경 변수
    • 현재 세션에서만 동작.
  2. 사용자 환경 변수
    • 특정 사용자에 대해 정의된 환경 변수로, 로그인할 때마다 로드됨.
    • .bashrc, .bash_profile, .bash_login, .profile 등에 정의된다.
  3. 시스템 전체 환경 변수
    • 해당 시스템의 모든 사용자가 사용 가능.
    • /etc/evironment, /etc/profile, /etc/profile.d, /etc/bash.bashrc 등에 정의된다.

기존에는 .bashrc에 사용자 환경변수를 정의했었다.

sshpass를 이용하여 원격 접속할 때와 같은 사용자로 접속했기 때문에 문제가 없을 것이라 생각했지만, 혹시 몰라 시스템 전체 환경 변수로 다시 환경 변수를 작성해보았다.

/etc/environment 에 정의한 환경변수를 다시 sshpass로 출력해보았지만, 제대로 출력되지 않았다.

5. login shell

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 또한 환경 설정 파일을 로드하는데 영향을 미칠 수 있다는 점을 알 수 있었다.

친절하게 주석까지 달려있었다니,,,
앞으로 오류를 만나면 꼭 !! 파일을 잘 분석해봐야겠다 !

References

Github-Actions
Login Shell vs Non-Login Shell

0개의 댓글