AWS를 활용한 무중단 배포

박양원·2024년 2월 20일
0

Trouble Shooting

목록 보기
2/16
post-thumbnail
post-custom-banner

해당 포스팅은 사이드 프로젝트 진행 중 겪은 크고 작은 이슈들에 대한 기록입니다.

AWS와의 연동

  • 사이드로 진행한 프로젝트 서버 개발 환경을 로컬에서 AWS로 이전하는 과정에서의 Trouble Shooting 과정에 관한 기록
  • AWS EC2, RDS, S3, CodeDeploy, nginx 활용

01. 처음 부딪힌 난관 : application.yml의 profile 설정

  • 이 때까지 개발 과정은 별다른 구분없이 로컬에서만 개발을 진행하였기에 문제가 없었으나, AWS에 배포 서버를 옮기게 되면서 yml 파일의 profile 설정에 대한 무지함이 발목을 잡았다.

  • spring의 profile 기능을 활용하여 로컬 개발 환경과 AWS의 배포 환경을 나누어 관리할 수 있다.

  • 이 과정에서 SpringBoot 2.4.0 이전의 방법과 이후의 방법이 달라졌음을 알게 됐고, 구글에서 찾은 게시글이 이를 명확히 구분하여 사용하지 않고 있는 것을 깨달아 혼자 직접 헤딩하면서 profile 관리법을 익혔다.

  • SpringBoot 2.4.0 이전

    • spring:
        profiles: local
        include:
        	real_db, local_db
    • spring.profiles.[name] 형식처럼 사용할 프로필을 명시하고, include 키워드를 이용하여 명시한 프로필에 포함시킬 다른 프로필을 선언해줌

    • 처음 이 방식을 사용했으나, deprecated 됐다는 경고를 보고 아래와 같이 변경

  • SpringBoot 2.4.0 이후

    • spring:
        profiles:
          active: local
          group:
            "local": "local_db, default, oauth"
            "real": "real_db, default, oauth"
            
      --- # (yml 구분선)
      
      spring:
        config:
          activate:
            on-profile: default
            
            # 밑으로 yml 설정들 기재
      ---
      
      spring:
        config:
          activate:
            on-profile: local_db
            
      ---
      
      spring:
        config:
          activate:
            on-profile: real_db       
    • spring.config.activate.on-profile.[name] 의 형식으로 프로필을 선언한다.

    • spring.profiles.group 기능을 활용하여 그룹을 부여, 그룹명을 이용하여 해당 그룹에 속한 모든 요소들을 한 번에 프로필로 사용할 수 있다.

    • spring.profiles.active.[name]으로 별다른 호출이 없는 경우 초기에 불러 사용할 프로필 값을 정해준다.

    • EC2의 스크립트 단에서 아래의 스크립트를 통해 profile 명을 호출하면 위에서 on-profile에 설정한 yml profile 설정들을 맞춰 사용할 수 있다.

      • nohup -jar -Dspring.profiles.active=[프로필 명]
  • 2.4.0 이후 프로필 버젼 관리 방법을 터득한 후, EC2에서 서버를 구동시키면 아래에서 보는 것과 같이 원하는 profile 설정들이 등록된 것을 확인할 수 있었다.

    • The following 4 profiles are active: "real", "real_db", "default", "oauth"

02. 배포 성공은 하지만, 테스트 코드는 계속 실패

  • 배포까진 힘겹게 성공했지만, 이상하게 테스트 코드는 계속 실패로 뜬다 (로컬에선 성공)

  • gradle build를 --debug 옵션을 부여하여 debug 로그를 모두 보게 설정

  • gradleError

  • 위처럼 무수히 많은 로그가 찍히는 중... (구글링을 해봐도 이유를 파악하지 못 했음)

  • Test 코드에 Profile을 별도로 설정하여도 똑같이 에러 발생

  • 임시 방편으로 gradle에서 아래 코드를 주석처리 함

    • //tasks.named('test') {
      //	useJUnitPlatform()
      //}
  • 이유를 아시는 분들은 댓글 달아주시면 너무 감사하겠습니다 ㅠㅠ...

03. Travis CI (자동화 배포) 설정 중, Permission denied

  • Travis CI에서 gradlew의 실행 권한이 없어서 발생하는 에러

  • EC2에 실행 권한을 부여했으나, Travis CI 쪽에서의 접근은 별개로 취급하는 것 같다.

  • 아래의 코드들로 해결할 수 있음

  • git update-index --chmod=+x gradlew
    git commit -m "Travis CI Permission 등록"
    
    <!-- 아래의 명령어로 권한 확인 가능  -->
    git ls-tree HEAD
    
    100755 가 나오면 허가가 부여된 것
    
  • 2번에서 Test를 끄지 않으면 위 과정에서도 Test 실패로 인한 에러가 발생함

04. Travis CI 자동화 중, PR 수행 시 Error발생

  • PRErrorr

  • Travis CI가 작동하는 중, Github에서 PR을 완료해버리면 위의 에러가 발생한다.

  • 사실, 작동을 모두 기다려도 어차피 S3과 CodeDeploy는 PR로 인식하여 작동하지 않는다.

  • 따라서 그냥 무시하고 진행해도 상관없을 듯 하다.

05-1. CodeDeploy, S3, Travis CI 연동 과정에서 에러 발생

  • Version 2 of the Ruby SDK will enter maintenance mode as of November 20, 2020. To continue receiving service updates and new features, please upgrade to Version 3. More information can be found here: https://aws.amazon.com/blogs/developer/deprecation-schedule-for-aws-sdk-for-ruby-v2/
    Triggered deployment "d-P0UMRF7JJ".
  • 위의 코드가 나오면서 deployment에 실패. (사실 위의 코드와는 별개로 발생한 문제)

  • 해결법은 아래에서!!

05-2. CodeDeploy 작동 안 함

  • Travis CI, S3, CodeDeploy를 연동하는 과정에서 에러 발생.
  • 정확하겐 S3는 정상 동작하지만, CodeDeploy로 인한 자동화 배포가 하나도 이루어지지 않고 있었다.
  • 참고링크
  • 위의 링크를 통하여 해결 방법을 찾아 해결하였다ㅠㅠ
    • CodeDeploy와 EC2의 연결은 EC2에서 선언한 태그를 사용한다.
    • EC2, RDS, S3 모두 태그를 부여만 했지 부여한 태그를 사용한 적이 없어 이번 경우에도 아무런 생각도 없이 새로운 태그를 부여하듯이 작성하여 에러 발생!!!
    • 즉, Name이라는 태그를 부여한 EC2를 불러와서 CodeDeploy가 동작해야 하는데, 존재하지도 않는 EC2를 찾아서 동작시키려고 했으므로 Deployment에 실패한 것이다.

06. nginx 설치

  • sudo yum install nginx를 통해 nginx 패키지 검색을 할 수 없음
  • sudo amazon-linux-extras install nginx1 을 사용해야 함
  • sudo service nginx start => sudo service nginx status 로 확인까지 해주면 됨

07. 배포 후 사라진 node_modules

  • 현재 node_modules 디렉토리는 .gitignore에 등록돼있어 git이 추적하지 않는다.
  • 생각해보면 이때까지 수동으로 항상 npm install을 해주고 있었다...
  • 이제 배포 과정이 무중단 + 자동이므로 이 부분 또한 내가 맞게 바꿔줘야 한다!!!
  • 참고 블로그
  • 역시 많은 분들이 같은 문제를 겪으셨고, 그렇기에 벌써 Gradle이 Build되는 시점에 npm install을 수행할 수 있는 plugin이 있었다.
    • package.json은 함께 관리되고 있음 => npm install 시, package.json에 있는 패키지들을 설치해줌
  • gradle에 알맞는 코드를 적용 후, 해결 완료!!!

08. S3 이미지 URL Access_Denied

  • S3의 퍼블릭 접근을 모두 다 차단하여서 발생한 문제.

  • S3에 이미지를 업로드 하는 과정에서

  • PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, uploadFile)
                    .withCannedAcl(CannedAccessControlList.PublicRead);
  • 위의 코드로 업로드 하는 각각의 이미지에 PublicRead 권한을 부여해준다.

  • 이 경우에도 Access Denied 403 에러가 발생하였다.

  • 결국 아래의 사진처럼 버킷에 대한 권한 제한을 어느 정도 풀고 나서야 문제를 해결하였다.

  • ACLErrorr

  • ACLErrorr

  • 퍼블릭 액세스 권한을 해제하지 않고 접근하는 방법을 아직까지 찾지 못하여 넘어갔으나, Best Practice를 알게 되면 그 방법으로 접근 권한을 수정해야겠다ㅠㅠ

09. EC2 환경에서 파일 업로드 시 권한 문제로 에러 발생

  • IOException

  • 이미지 업로드 시, createFile로 새로운 File 객체를 생성한다. 하지만 이 과정에서 EC2 파일 생성 권한이 없어서 에러가 발생...

  • 심지어 S3 쪽 권한 문제인줄 알고 한참을 헛돌았다...ㅠㅠ

  • private Optional<File> convert(MultipartFile file) throws IOException {
            File convertFile = new File("/tmp/"+file.getOriginalFilename());
    
            if(convertFile.createNewFile()) {
                try (FileOutputStream fos = new FileOutputStream(convertFile)) {
                    fos.write(file.getBytes());
                }
                return Optional.of(convertFile);
            }
    
            return Optional.empty();
        }
  • 파일을 생성하는 시점에 "/tmp/" 경로를 부여해주니 Permission이 통과됐다.

  • File convertFile = new File(file.getOriginalFilename()); 이렇게 이름만 부여하면 Tomcat 내부에 파일을 임시 생성하고, 그 과정에 파일을 생성하는 권한이 EC2 계정에 부여돼있지 않아 일어난 문제인 것 같다.

  • tmp 디렉토리는 권한이 모두 열려있으므로 파일 생성에 권한이 따로 필요없기에 경로로 선택했다.

10. Access Key 노출로 인한 IAM 권한 제한

  • Github에 application.yml이 올라가는 바람에 EC2 접근 및 IAM Access key 보안에 문제가 생겼다...!

  • AWS Health Dashboard에 경고가 날라와서 문제가 발생했다는 것을 한 눈에 파악이 가능했다.

  • IAM권한

  • 노출이 되면 IAM 사용자 권한에 위의 AWSCompromisedKeyQuarantineV2라는 권한이 하나 추가된다.

  • 위의 친구가 AWS의 정상적인 사용을 금지한다. (Access key 노출로 인한 보안을 위해서)

  • 권한을 제거해주고, 기존의 Access Key는 폐기 후 재발급 받아서 사용하면 된다하여 그대로 진행했으나...

  • 폐기까지 했는데도 Health에 경고가 떠있다. 또한 EC2는 여전히 정상 접근이 불가능했다.

  • AWS의 가이드라인을 보고 Access key를 콘솔로도 교체해보고 웹에서도 교체해봤으나 해결 자체가 되지 않아 결국 EC2 자체를 삭제하고 새로운 EC2를 만드는 무식한 방법으로 해결하였다.

post-custom-banner

0개의 댓글