요약
시간이 급하신 분은 가장 아래로 내리셔서 문제 해결만 보시면 됩니다.
이 글은 저의 삽질일기를 적어뒀습니다.
문제 상황
어느날 갑자기 프론트 팀원에게 다음과 같은 연락이 왔다.
그럴리가 없는데,, 간단한 Dto 변경을 진행하고 머지를 했었다. 그리고 그 변경사항이 스웨거에 제대로 반영된 걸 확인했기 때문에 이런 문제가 생길리가 없다고 생각했다.
현재 내 개발환경은 aws에 개발 서버를 올려두고 개발을 진행하고 있다.
CI/CD 설정을 github Action을 사용해서 설정해뒀고, AWS CodeDeploy를 사용해서 개발을 진행한다.
main 브랜치에 push 되는 경우에 action이 감지해서 배포를 진행한다.
CICD.yml 파일
# 1 워크플로의 이름 지정
name: CI and Deploy to Amazon EC2
# 2 워크플로가 시작될 조건 지정
env:
AWS_REGION: ap-northeast-2
S3_BUCKET_NAME: github-action-s3-joeunsai-bucket
CODE_DEPLOY_APPLICATION_NAME: my-codedeploy-app
CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: my-codedeploy-deployment-group
permissions:
contents: read
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest # 3 실행 환경 지정
#4 실행스텝지정
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '17'
# db.properties 파일 생성
- name: Make application.properties
run: |
cd ./src/main/resources
mkdir -p ./config/prod
cd ./config/prod
touch ./application-db-prod.yml
touch ./application-oauth-prod.yml
echo "${{ secrets.DATABASE_PROPERTIES }}" >> ./application-db-prod.yml
echo "${{ secrets.AUTH_PROPERTIES }}" >> ./application-oauth-prod.yml
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: EditorConfig Format
run: ./gradlew editorconfigFormat
- name: Build with Gradle
run: ./gradlew clean build
# (4) AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
# (5) 빌드 결과물을 S3 버킷에 업로드
- name: Upload to AWS S3
run: |
aws deploy push \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--ignore-hidden-files \
--s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \
--source .
# (6) S3 버킷에 있는 파일을 대상으로 CodeDeploy 실행
- name: Deploy to AWS EC2 from S3
run: |
aws deploy create-deployment \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
--s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip
appspec.yml
version: 0.0
os: linux
# destination에 아티팩트가 unzip된 결과가 생성될 디렉토리명을 넣어준다.
files:
- source: /
destination: /home/ec2-user/build/
overwrite: yes
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks:
AfterInstall: #AfterInstall에서 기존에 실행중이던 어플리케이션 종료시키고 ApplicationStart에서 새로운 어플리케이션 실행
- location: scripts/stop.sh
timeout: 60
runas: ec2-user
ApplicationStart:
- location: scripts/start.sh
timeout: 60
runas: ec2-user
start.sh
#!/usr/bin/env bash
PROJECT_ROOT="/home/ec2-user"
JAR_FILE="$PROJECT_ROOT/good_relation-0.0.1.jar"
APP_LOG="$PROJECT_ROOT/application.log"
ERROR_LOG="$PROJECT_ROOT/error.log"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
TIME_NOW=$(date +%c)
# build 파일 복사
echo "$TIME_NOW > $JAR_FILE 파일 복사" >> $DEPLOY_LOG
cp $PROJECT_ROOT/build/build/libs/*.jar $JAR_FILE
# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &
CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG
stop.sh
#!/usr/bin/env bash
PROJECT_ROOT="/home/ec2-user"
JAR_FILE="good_relation-0.0.1.jar"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
TIME_NOW=$(date +%c)
# 현재 구동 중인 애플리케이션 pid 확인
CURRENT_PID=$(pgrep -f $JAR_FILE)
# 프로세스가 켜져 있으면 종료
if [ -z $CURRENT_PID ]; then
echo "$TIME_NOW > 현재 실행중인 애플리케이션이 없습니다" >> $DEPLOY_LOG
else
echo "$TIME_NOW > 실행중인 $CURRENT_PID 애플리케이션 종료 " >> $DEPLOY_LOG
kill -15 $CURRENT_PID
fi
다음과 같은 설정을 가지고 있다.
문제 구체화
참고로 내 코드는 다음과 같이 환경변수를 따로 관리하고 있어서 가장 유력하게 의심이 가는 부분은 역시 환경변수가 잘못 들어가는 문제였
다.
문제 가능성 생각하기. (삽질의 기록)
그래서 문제의 가능성을 다음과 같이 생각해봤다.
1. 내가 코드를 잘못 짰다.
2. 환경 변수에 오타가 발생했다.
3. 카카오 코드가 만료돼서 지금 로그인이 안된다.
4. github action이 이전에 잘못된 파일을 캐싱하고 있다.
5. aws에서 이전에 잘못된 파일을 캐싱하고 있다.
일단은 문제를 확인하기 위해 로컬에서 프론트 코드를 돌려봤다. 음 역시 에러가 나는군.
1. 로컬에서 프론트 서버 돌려보기
아래는 프론트 서버 에러이다. Next라서 에러가 저기 서버에 나와서 살짝 불편하긴 하다.
프론트 서버에서는 다음과 같이 로그인 api에서 에러가 나서 오류가 난 것을 볼 수가 있다.
그래서 ssh로 ec2에 접속한 후 로그를 살펴봤다.
카카오에서 no authentication Key! 에러가 났다.
이건 보통 코드를 잘못 보낸 경우에 에러가 발생하는데 일단 이것만 봐서는 무슨 원인인지 알 수 없다.
2. 로컬에서 백엔드 빌드 후 SCP로 파일 올리기.
로컬에서 백엔드 코드를 빌드하고 scp로 ec2에 빌드한 파일을 올려줬다.
해당 파일을 ec2에 올려서 돌려봤다. 그랬더니 놀랍게도..! 로그인이 정상 동작한다?
그러면 1번과 3번의 가능성은 없어졌다.
이로서 내 코드는 문제가 없다는게 확정 났다.
그렇다면 남은 문제는 아래 3가지로 추려졌다.
2. 환경 변수에 오타가 발생했다.
4. github action이 이전에 잘못된 파일을 캐싱하고 있다.
5. aws에서 이전에 잘못된 파일을 캐싱하고 있다.
이렇게 3가지의 경우를 봤다.
3. 환경변수 오타 확인.
그래서 가장 생각하기 쉬운 환경변수 오타가 있을까봐
여기에 있는 action에 사용하는 환경변수들을 최신으로 업데이트 해줬으나 돌아오는 결과는 여전히 로그인은 실패했다.
[스포 : 사실 여기서 2번은 배제해선 안됐다.]
결국 어딘가에서 잘못된 파일을 캐싱하고 있다는 결론에 도달했다.
4. 혹시 모를 깃허브 액션 캐싱 확인
근데 액션이나 코드 디플로이에서 캐싱이 되는 것이라면 이것도 안 들어가야하는데?
이것도 아닌데?
근데 바로 개발서버에서 업데이트 되는게 확인되었다.
이상하다? 그럼 그것도 아닌 것 같은데?
5. aws 캐시 날리기.
그래서 혹시나 aws가 뭐 최적화 하다가 꼬인걸까 싶어서 아래 게시물을 따라서 모든 파일을 날려버리고 다시 진행해봤다.
https://jaykos96.tistory.com/46
혹시나 혹시나 해서 aws 캐시가 문제인가 싶어서 이걸 따라해봤다.
에러 발생. 내가 저거 다 지워서 이미 있는 파일이 있을 때 당황하며 못 지운거다.
그래서 ec2에 있는 파일을 지웠다.
다 지움.
배포 재시도 누르고.
배포는 성공
절망. 모든 가능성의 실패
근데 여전히 로그인은 실패했다.
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 3일내내 원인을 모르겠어서 팀원께 너무 죄송해서 그냥 scp로 올리고 CICD는 다음생에나 할까 갈등했다.
문제 발견 및 해결.
근데 아무리 생각해도 일반 서버는 올라가는데 로그인만 고장이 나는게 이상했다.
만약 설정파일이 안 들어간거면.... 애당초 실행때 런타임 에러가 나는게 맞아서 설정파일에서 문제가 없을거라고 생각했다.
설정에 디비 설정도 들어있어서 당연하게 그게 안 들어가면 실행이 될리가 없었다.
걍 어디가 캐싱 되서 문제가 된다는 옵션도 말이 안 됐다. 설정파일을 바꿔서 올리면 코드가 아에 안 돌아갔기 때문이다.
하지만 초심으로 aws에 ssh로 접속한 후에 천천히 살펴보기 시작했다.
자포자기 하는 심정으로 aws 내부의 빌드 파일을 봤다.
근데 눈을 씻고 봐도.. 왜 따옴표가 없지?!!??
여기에 원래 이렇게 문장을 감싸줘서 됐는데 왠지 모르겠는데 이 쌍따옴표가 사라졌다!!!!
둘의 차이점이 보이는가?
비밀 환경변수라 모른걸 캡쳐하지는 못하지만 쌍따옴표로 로컬에 붙혀준게 깃헙 액션을 거치면서 사라졌었다.
이러니까 데이터베이스는 연결이 되고 요청은 안되는 거였다.
즉 요청을 보낼때 Bearer token.~~
이렇게 보내야하는데, 지금 Bearertoken~~ 이렇게 보내고 있던거다.
이게 내 얘기가 될 줄은 전혀 몰랐지~
- name: Make application.properties
run: |
cd ./src/main/resources
mkdir -p ./config/prod
cd ./config/prod
echo "${{ secrets.DATABASE_PROPERTIES }}" > ./application-db-prod.yml
echo "${{ secrets.AUTH_PROPERTIES }}" > ./application-oauth-prod.yml
내 깃헙액션 워크플로우에 다음과 같이 값을 넣기 때문에 쌍 따옴표는 전부 사라지게 만들어 버린거다.
즉 echo 명령으로 진행하기 때문에 알아서 여기 환경변수가 쌍 따옴표를 삭제해서 진행해버렸다.
에코 명령에 쌍따옴표를 계속 받으면 파싱에 오류가 생기니 여기 config에서는 알아서 지워버린 것 같다.
그래서 결국 모든 쌍따옴표를 작은 따옴표로 바꿔서 해결했다.
성공!!
생각보다 허무한 삽질이기만 누군가에겐 도움이 되는 글이 되면 좋겠다.
'Backend' 카테고리의 다른 글
sqs spring boot 사용법 (0) | 2024.08.13 |
---|---|
[문제해결] Spring webSocket Test 삽질 일기 (생성자 직렬화 문제) (0) | 2024.08.07 |
Spring Security 단위 테스트 (0) | 2024.08.07 |
서블릿이란 무엇인가 [서블릿 실행 흐름 편] (0) | 2024.05.08 |
Servlet 이란 무엇일까 [개념편] (0) | 2024.05.07 |