이번에는 github actions로 CICD를 적용하는 과정에서 발생한 문제를 공유하려고 한다. 프로젝트 배포를 위해 AWS EC2 인스턴스를 사용하고 있으며, GitHub Actions로 SSH를 통해 EC2 서버에 연결한 뒤 빌드 및 배포를 자동화하고 있다.
하지만 이 과정에서 환경변수가 제대로 적용되지 않아 발생한 문제를 겪었고, 이를 해결하는 방법을 찾는 데 시간이 좀 걸렸다.
같은 문제로 고민하는 분들이 있다면 이 글이 도움이 되었으면 좋겠다. 😊
프로젝트 환경 및 배포 방식
토큰 값 같은 민감한 정보를 보안상 환경 변수로 관리하는 것이 좋기 때문에 application.yml에 아래와 같이 환경 변수를 설정하였다.
jwt:
access:
secret: ${JWT_SECRET_KEY}
expiration: ${JWT_ACCESS_EXPIRATION}
refresh:
secret: ${JWT_SECRET_KEY}
expiration: ${JWT_REFRESH_EXPIRATION}
이 환경 변수들을 EC2 서버에 적용하기 위해, EC2의 ~/.bashrc 파일에 환경 변수를 등록했다.
export SERVER_URL=http://example.com
export JWT_SECRET_KEY=super-secret-key
export JWT_ACCESS_EXPIRATION=3600
export JWT_REFRESH_EXPIRATION=86400
GitHub Actions 배포 파이프라인 설정
name: Branch Push Check
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Connect to EC2 via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
script_stop: true
script: |
cd ~/{프로젝트명}
git pull origin main
./gradlew clean build
sudo fuser -k -n tcp 8080 || true
nohup java -jar build/libs/*SNAPSHOT.jar > ./output.log 2>&1 &
배포는 문제없이 완료되었고, GitHub Actions에서도 CD 파이프라인이 성공적으로 완료되었다고 나왔다.
하지만... 막상 서버 URL로 접속해 보니 오류가 발생하였다.
문제 원인 분석
토큰 값을 위해 환경 변수를 추가하기 전까지는 배포가 잘 이루어졌기 때문에, 환경 변수 설정에 무언가 문제가 있지 않을까 추측하고 있었다.
조금 더 정확한 이유를 찾기 위해 EC2 서버의 output.log 파일을 확인해보니 환경변수 적용이 제대로 되지않아 오류가 발생하고 있다는 사실을 확인하였다.
🤯 이게 무슨 일이지?
나는 이미 EC2 서버의 ~/.bashrc 에 환경 변수를 설정해 둔 상태였고, echo 명령어를 통해 잘 적용되었는지 확인도 마쳤다. 왜 환경변수 에러가 뜨는지 모르겠어서 직접 EC2 서버에 접속해 수동으로 다시 배포를 해봤다.
놀랍게도... 수동 배포 시에는 문제가 전혀 없었다.
서버 URL에 접속해보니 정상적으로 서비스가 실행되었다.
그렇다면 cd 과정에서 문제가 있다는 뜻이지 않을까 하고 생각했다.
문제 발견: SSH 연결 시 환경변수가 적용되지 않는 이유
문제를 분석하다가 중요한 사실을 알게 되었다.
🔎 비로그인 셸 세션 문제
GitHub Actions에서 SSH로 EC2 서버에 접속하는 세션은 비로그인(non-login) 셸 세션이다.
이때, 비로그인 셸 세션에서는 ~/.bashrc 파일이 자동으로 로드되지 않는다!
따라서, 내가 EC2 서버의 ~/.bashrc에 환경 변수를 설정했더라도, GitHub Actions가 비로그인 세션으로 접속하면 해당 환경 변수가 적용되지 않았던 것이다.
문제 해결하기
처음에는 GitHub Actions 배포 스크립트에서 .env 파일을 생성하고 이를 source 명령어로 로드하는 방식을 사용했다.
script: |
echo "SERVER_URL=${{ secrets.SERVER_URL }}" > .env
echo "JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }}" >> .env
echo "JWT_ACCESS_EXPIRATION=${{ secrets.JWT_ACCESS_EXPIRATION }}" >> .env
echo "JWT_REFRESH_EXPIRATION=${{ secrets.JWT_REFRESH_EXPIRATION }}" >> .env
source .env
cd ~/{프로젝트명}
git pull origin main
./gradlew clean build
sudo fuser -k -n tcp 8080 || true
nohup java -jar build/libs/*SNAPSHOT.jar > ./output.log 2>&1 &
하지만 결국 이 방법은 실패했다ㅠㅠ
.env 파일의 로드가 비로그인 셸에서는 제대로 적용되지 않는 것 같았다. 그래서 방법을 바꿔보았다!
.env 파일이 제대로 작동하지 않는 것이라면 .env 파일을 사용하는 대신, export 명령어를 사용해 한 줄씩 환경 변수를 설정하면 되지 않을까? 하고 생각했다.
script: |
export SERVER_URL=${{ secrets.SERVER_URL }}
export JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }}
export JWT_ACCESS_EXPIRATION=${{ secrets.JWT_ACCESS_EXPIRATION }}
export JWT_REFRESH_EXPIRATION=${{ secrets.JWT_REFRESH_EXPIRATION }}
cd ~/{프로젝트명}
git pull origin main
./gradlew clean build
sudo fuser -k -n tcp 8080 || true
nohup java -jar build/libs/*SNAPSHOT.jar > ./output.log 2>&1 &
위와 같이 GitHub Actions 배포 스크립트에서 환경 변수를 직접 export 명령어로 설정하니 문제없이 환경 변수가 적용되었다!
해결 완!
'Develop' 카테고리의 다른 글
디스코드 알림봇 만들기: 반복 메시지, 슬래시 커맨드, 자동 등록까지 (0) | 2025.04.08 |
---|---|
[ React ] useInsertionEffect 참조 에러 ( @emotion/react ) (0) | 2025.03.06 |
[ React Native ] Error while updating property 'borderTopLeftRadius' of a view managed by: RCTImageView (0) | 2025.01.08 |
[ SpringBoot ] 회원가입 API 설계 고민 (0) | 2025.01.04 |
[ React Native ] com.android.builder.testing.api.DeviceException: No connected devices! (1) | 2024.12.27 |