처음엔 그나마 익숙한 도커를 사용한 자동배포를 시도했으나

가만히 있어도 늘어나는 pull 수와.. 환경변수 관련 에러와 보안 문제를 겪고 인도의 해커가 내 AWS 계정을 탈취해 휴학하고 직접 등록금을 버는 악몽을 꾸고..... CodeDeploy를 사용하는 방향으로 변경함
처음 적용해보는 배포자동화라 멍청한 실수도 많았고 그나마 의미있는 시행착오도 겪었다. 트러블슈팅을 중심으로 적어보려고 한다.
- github actions
- Gradle - build 진행
- zip 파일로 압축
- S3에 zip 파일 업로드
- CodeDeploy
- S3에서 zip 파일 다운로드, build
- appspec.yml -> shell script 실행
- .jar 파일 실행 : 배포 완료!
※ 주의 : 전부 같은 리전에 생성하자
S3FullAccess
AWSCodeDeployRole
AWSCodeDeployFullAccess
사용자 생성 > 해당 권한들 포함하도록 권한 연결
accessKey, secretKey 생성 > 저장
- 보안그룹 : 인바운드 규칙 확인
- 키페어 확인
- 탄력적 IP 연결 확인
- IAM 프로필 연결 확인
※ IAM 프로필 연결
IAM에서
S3FullAccess
AWSCodeDeployRole
AWSCodeDeployFullAccess
세 개의 역할을 포함한 역할 생성

인스턴스 > 작업 > 보안 > IAM 역할수정 > 생성한 IAM 프로필 연결하기

해당 설정 해제해서 퍼블릭액세스 가능하도록 해야 함
모든 S3에 대한 Action allow 하도록 권한설정 편집필요함

이렇게 뜨면 설정 완료


S3FullAccess
AWSCodeDeployRole
AWSCodeDeployFullAccess
세 개의 역할을 포함한 iam 역할 생성 -> arn 추가

wget https://bucket-name.s3.region-identifier.amazonaws.com/latest/install
- bucket-name, region-identifier
https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/resource-kit.html#resource-kit-bucket-names
위 공식문서 참고
나는 bucket-name이 내가 직접 생성한 S3 bucket 이름인 줄 알고.. 시도했으나... 당연히 404 error만 잔뜩 보고 실패했다
위 공식문서의 목록을 보고 작성하자



!! 기존 properties 위치에 맞추는거 주의 !!



- name: Upload to S3
run: aws s3 cp --region ${{ secrets.AWS_REGION }} ./$GITHUB_SHA.zip s3://${{ secrets.S3_BUCKET_NAME }}/$GITHUB_SHA.zip
- name: Code Deploy
run: aws deploy create-deployment --application-name ${{ secrets.AWS_APP_NAME }} --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name ${{ secrets.AWS_GROUP_NAME }} --s3-location bucket=${{ secrets.S3_BUCKET_NAME }},bundleType=zip,key=$GITHUB_SHA.zip
--aplication-name : CodeDeploy app 설정시 설정한 app name --deployment-config-name : 배포구성 AllAtOnce --s3-locaiton -bucket : S3 버켓 이름 - bundleType : zip - key : zip파일 이름

github > aciton 칸에서 이렇게 뜨면 CI까지는 성공!

실패한다면 같은 칸에서 실행 결과 메세지 확인 가능하므로 참고하자
CodeDeploy에서 배포관리에 사용하는 파일

- 기본이름 : appspec.yml
- appspec.yml 위치 : 애플리케이션의 소스 코드 디렉터리 구조의 루트에 배치해야 한다https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/reference-appspec-file.html
: 공식문서 참고

version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/app
hooks:
AfterInstall:
- location: scripts/deploy.sh
timeout: 60
runas: root

배포 자동화는 아예 처음 해보는 만큼 이틀 내내 걸렸으며 정말 어이없고 많은 에러를 만남..
위에 말한 부분, 버켓이름을 지정된 리스트에 있는 걸 써야하는데 내 버켓이름으로 썼더니 에러가 뜸
당연함. 그런 리소스는 존재하지 않으니까~
https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/resource-kit.html#resource-kit-bucket-names
: 이 공식문서를 참고합시다~
Script does not exist at specified location: /opt/codedeploy-agent/deployment-root/9f65c170-dcd0-466d-aa0c-94754940cd0a/d-F4OQQN7Z2/deployment-archive/deploy.sh

말 그대로 deploy.sh의 위치가 틀려서 난 오류
여러 블로그들을 이곳저곳 베끼며 참고하던 난.. 최상단>scripts 폴더 아래 만들면 된다는 말을 그냥 믿고 작성했으나 기준은 프로젝트 최상단이었다~
/scripts/deploy.sh 위치에 만들었다면
appspec.yml 작성시 location에 이렇게 작성해야함
항상.. 공식문서를.. 확인하자...
이 에러에서 가장 많은 시간이 걸렸다
끝나버렸다 아직 시작도 안 해봤는데..
Github actions에서 CI는 성공했지만 CodeDeploy에서는 시작도 못 하고 Application Stop에서 에러가 나버렸다.
CodeDeploy에서 확인할 수 있는 에러는
CodeDeploy agent was not able to receive the lifecycle event. Check the CodeDeploy agent logs on your host and make sure the agent is running and can connect to the CodeDeploy server.
요러했고, 이거로는 단서가 너무 부족해서 EC2 인스턴스에 CodeDeploy 로그가 남는다고 해서 그걸 까보니까 나온 에러.
위치는 ~/etc/var/log/aws/codedeploy-agent/~.log
해당 스텝을 체크해보자
- CodeDeploy에 연결된 권한 확인
- EC2에 연결된 IAM 프로필의 권한 확인
- workflow의 Credentials 부분에 입력된 사용자 액세스키, 시크릿키, + 해당 사용자의 권한 확인
- 모든 권한 확인 후 CodeDeploy Agent restart (권한 갱신을 위해선 재시작 해야 한다고 함)
- 그래도 안 된다면 configure 명령어로 직접 credentials 입력하기
https://goateedev.tistory.com/317 << 이 블로그 참고
: 원래 3의 과정이 해당 명령어 없이 자격증명을 해주는 부분인 것 같은데.. 안되니까 직접 입력해준다- 그리고.. cat 명령어로 인한 착각 ㅜ
: 저 log 파일이 너무너무 길어서 나는 cat ~.log | more로 확인하고 있었다.. 저 log파일은 덮어씌워지는게 아니라 뒤에 덧붙여지기 때문에 저렇게 확인하면... 그냥 맨 처음에 났던 오류만 계속 확인하게 된다
할 만한 방법은 다 해봤는데 도저히 해결이 안 돼서 저 로그를 노려봤는데 위에서 확인했을 때와 시간이 변하지 않는 다는 것을 확인했다 ^-^....
혹시 내가 계속 같은 예전의 에러메시지를 보고 현재의 에러라고 착각하고 있는건 아닌지 확인해보자.............

나 같은 경우에는 workflow에서 정의한
- name: Code Deploy
run: aws deploy create-deployment --application-name ${{ secrets.AWS_APP_NAME }} --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name ${{ secrets.AWS_GROUP_NAME }} --s3-location bucket=${{ secrets.S3_BUCKET_NAME }},bundleType=zip,key=$GITHUB_SHA.zip
// 마지막 key=$GITHUB_SHA.zip
마지막 단계인 deploy에서 key이름을 잘못설정해서 생긴 에러였다.
key는 S3에 올라간 zip파일의 이름을 그대로 쓰면 된다.
CodeDeploy까지 모두 성공을 확인하고 드디어 포스트맨으로 연결을 확인했는데..

눈물이 흐를 뻔 했다.
심지어 아무 에러도 없고.. 뭔가 확인할 건덕지가 없었다..
에러가 없어..? 하고 생각해보니 stdout을 저장하는 /home/ec2-user/nohup.out 파일 자체가 없었다.
그냥 실행이 안 됐나?? 하고 처음에 작성했던 .jar 변수를 직접 인스턴스에서 찍어보니

SNAPSHOT.jar가 아니라 SNAPSHOT-plain.jar가 나왔다
우우우 붐따..
1. tail > head로 바꿔서 올바른 파일명 얻기에는 성공했으나 왜인지 이것도 안 돼서
2. 그냥 위치를 하드코딩 해버렸다

어쨋든 해결!
갑자기 의존성 주입..? spring 에러가 여기서 난다고..?
로컬로 돌릴 땐 스프링관련 에러는 전혀 없었는데 여기서 나서 당황스러웠다.
jsonparseexception : unexpected character : was expecting double quote to start field name

FCM을 사용하는 FCMService 있었는데, 여기서 JSON field name을 ""로 안 해서 JSON parse error가 났다고 한다.
내가 JSON을 썼나..? 여긴 response를 주는 부분도 아닌데..? 라고 고민했다.
글로 정리해보면 당연히 보이는데 codedeploy+JSON+FCM을 전부 연결해서
검색했을 땐 이런 사례가 단 하나도 나오지가 않아서 당황스러웠다.
github action과 codedeploy를 사용해서 배포 자동화를 하며 FCM을 이용해 notification을 만든경우, jsonparseexception : unexpected character : was expecting double quote to start field name가 발생한다면
github.secrets에 저장한 JSON 형식의 firebasekey의 ""를 인식하지 못 하고 plain text로 저장해 발생한 문제다!!
- 해결방법
- "앞에 전부 \를 붙여준다
: 단순히 수작업으로 \를 붙여서 "를 인식하게 해준다- github action에 JSON을 만들어주는 라이브러리를 사용한다
: https://github.com/marketplace/actions/create-json
나는 더 이상 CI단계에서 커밋하고 빨간줄 보고.. 이 과정을 거치고 싶지 않아서 그냥 secrets에 전부 \를 붙여서 수정했다.
해결!

어쨋든 성공!
다음엔 꼭 도커를 사용해보고 싶다