프로젝트/장기 프로젝트

MOTI #2. AWS 프리 티어 종료 후 새로운 프리 티어 계정으로 이동하기

Chipmunks 2023. 6. 3. 20:59
728x90

안녕하세요!

저번 게시글 이후 오랜만에 포스팅하네요.

 

2022.01.27 - [프로젝트/장기 프로젝트] - MOTI #1. iPhone 13 Pro 에서 디자인이 깨지는 버그 ( feat. VStack & ZStack )

 

MOTI #1. iPhone 13 Pro 에서 디자인이 깨지는 버그 ( feat. VStack & ZStack )

안녕하세요. 하루하루 모은 이야기로 나만의 꿈을 담은 카드, 모티 개발자인 다람쥐입니다. 모티 신기능도 만들어보고 싶고 코드 개편도 해보고 싶고, 유저와의 소통도 마구마구 해보고 싶은데

itchipmunk.tistory.com

 

모티는 AWS 서비스에서 프리 티어 계정으로 매 달 호스팅 비용 500원으로 서버를 운영하고 있는데요.

아쉽게도 프리 티어 기간은 계정 생성 이후 1년 밖에 되지 않습니다.

1년이 넘어가면 RDS(데이터베이스)와 EC2(인스턴스) 비용으로 4~5만원 정도 과금되기 시작합니다.

저도 늘 까먹어서 매 달 이메일로 넘어오는 과금 내역을 보고 갈아탈 때가 됐구나, 를 깨닫네요.

 

이메일로 넘어온 2023.04 월 영수증

더이상 과금을 막으려면 프리티어 계정을 새로 만들어 기존 서버와 데이터베이스, S3, 도메인을 모두 이전해야 합니다.

AWS 에서 기존 서버와 데이터베이스를 백업하여 다른 AWS 계정으로 전송할 수 있습니다.

다른 AWS 계정에서 받은 정보로 서버 인스턴스와 데이터베이스 인스턴스를 생성합니다.

S3 도 AWS 콘솔로 다른 계정으로 일괄 복사할 수 있습니다.

 

도메인도 AWS Route 53 을 이용하여 관리하고 있는데요.

한 계정에서 관리하려고 새로 만든 프리티어 계정으로 도메인을 이전하려고 합니다.

 

1. 새로운 AWS 프리 티어 계정 생성

새로운 AWS 프리 티어 계정을 만드려면, 구글 계정이 필요합니다.

구글 계정은 휴대폰 인증만으로 빠르게 생성할 수 있습니다.

새로운 구글 계정 생성

벌써 세 번째 계정이네요. 감개무량하네요. ☺️☺️

AWS 계정과 관련 있는 계정이다 보니 비밀번호 보안을 강화하면 좋습니다.

 

구글 계정을 생성했다면, AWS 에서 프리 티어 계정을 생성할 수 있습니다.

AWS 사이트 에서 새 계정을 만듭니다.

방금 만든 이메일 계정으로 루트 계정을 생성합니다.

이메일 인증을 받으면 결제 정보를 입력해야 합니다.

체크 카드 및 신용 카드 정보를 입력합니다.

이후 결제 정보를 검증합니다.

AWS 측에서 100원 결제를 시도하여 잘 되는지 확인하게 됩니다.

그 100원 결제는 이후 취소가 되어 되돌아옵니다.

 

이후 휴대폰 번호를 입력하여 문자 인증을 받습니다.

문자 인증까지 마치면 회원 가입이 완료됩니다.

곧이어 AWS 서포트 플랜을 선택합니다.

무료 프리 티어 계정을 사용하기에, Basic support - Free 옵션을 선택합니다.

2. AWS EC2 AMI 생성하여 다른 계정으로 옮기기

기존 서버의 AWS EC2 인스턴스를 이미지로 만들 수 있습니다.

작업 > 이미지 및 템플릿 > 이미지 생성을 눌러 AMI 이미지를 생성합니다.

이미지 생성 화면으로 넘어가면 아래와 같습니다.

이미지 이름과 설명을 입력하고 이미지를 만듭니다.

참고로 프라이빗으로 만들어야 검색이 되지 않아 노출이 되지 않습니다.

AWS EC2 메뉴에서 이미지 > AMI 메뉴를 클릭합니다.

AMI 목록에 아래와 같이 생성된 걸 확인할 수 있습니다.

만드는 데 시간이 걸려 아직 상태가 '대기 중' 이네요!

15분 ~ 16분 정도 기다리면 사용 가능으로 변경됩니다!

그럼 이제 프리 티어 계정으로 보내볼까요?

AMI 이미지 상세 페이지로 이동합니다.

권한 탭에서 공유 계정 ID 를 추가합니다.

위 팝업이 뜨면 프리 티어 계정의 ID 를 입력합니다.

계정 ID 는 우측 상단의 이름을 클릭하여 나타나는 메뉴에서 확인할 수 있어요!

계정 ID 오른쪽에 있는 복사 버튼으로 복사하여 입력합니다.

추가가 잘 되었다면 변경 사항을 저장합니다!

이제 프리 티어 계정에서 위 AMI 이미지가 보이는지 확인합니다.

EC2 메뉴 중 이미지 > AMI 카탈로그 > 내 AMI > 나와 공유됨 체크하여 확인할 수 있습니다.

 

해당 AMI 이미지를 선택하여 'AMI로 인스턴스 시작' 버튼을 누릅니다.

인스턴스 시작 설정 페이지로 넘어갑니다.

이름 및 태그를 먼저 설정해줬어요.

그 외에 설정은 건들지 않고 기본 설정으로 인스턴스를 시작했습니다.

새로운 PEM 키를 생성하고 인스턴스를 시작합니다.

인스턴스 세부 설정 중 보안 그룹 > 인바운드 규칙은 기존 서버와 동일하게 맞췄습니다.

 

다음으로 탄력적 IP를 생성하여 연결합니다.

탄력적 IP 페이지에서 우측 상단의 '탄력적 IP 주소 할당' 버튼을 누릅니다. 

 

탄력적 IP 주소 상세 페이지에서 우측에 '탄력적 IP 주소 연결' 버튼을 눌러 인스턴스와 연결합니다.

해당 인스턴스 상세페이지에서 퍼블릭 IP 와 퍼블릭 도메인 주소가 탄력적 IP 와 같이 변경된 걸 확인할 수 있습니다.

 

3. AWS EC2 인스턴스에 접속하여 환경 설정 및 서버 실행하기

첫 번째로 프로젝트에 들어가 의존성을 설치합니다.

그리고 서버 시작 명령을 실행합니다.

$ npm i
$ npm run pm2 # 직접 만든 스크립트 명령어

[PM2] Applying action deleteProcessId on app [all](ids: [ 0 ])
[PM2] [main](0) ✓
[PM2] [v] All Applications Stopped
[PM2] [v] PM2 Daemon Stopped
[PM2] Spawning PM2 daemon with pm2_home=/home/ubuntu/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/ubuntu/moti-backend/dist/main.js in fork_mode (1 instance)
[PM2] Done.
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ main               │ fork     │ 0    │ online    │ 0%       │ 25.9mb   │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

그 후 접속이 잘 되는지 확인합니다.

EC2 환경에서 NestJS 빌드가 메모리 부족으로 안되어서 로컬에서 빌드 후 EC2 으로 파일을 업로드했습니다.

$ scp -i "~/.ssh/moti/moti-23-05-05.pem" -r ~/.../moti-backend/dist ubuntu@ec2-~.compute.amazonaws.com:/home/ubuntu/moti-backend/

아직 새로운 RDS 연결 정보를 변경하지 않아 기존 데이터베이스 주소를 사용하고 있습니다.

이는 이후 새로운 데이터베이스를 복제한 뒤 변경하도록 하겠습니다.

 

4. 기존 EC2 인스턴스 중지

1년동안 고생한 인스턴스를 종료시킵니다.

5. RDS 데이터베이스 이동

기존 계정의 RDS 인스턴스의 스냅샷을 생성합니다.

스냅샷 생성 이후 수동 스냅샷 화면으로 이동됩니다.

스냅샷 이름을 클릭하여 세부 페이지로 이동합니다.

작업 > 스냅샷 공유 버튼으로 공유 화면으로 이동합니다.

Private 으로 아까 만든 AWS 계정 ID 를 추가하여 공유합니다.

저장 버튼을 누른 다음 새 계정에서 '나와 공유됨' 메뉴를 누릅니다.

공유된 스냅샷을 확인할 수 있습니다.

작업 버튼을 눌러 스냅샷을 복원합니다.

DB 인스턴스 식별자를 입력하고 퍼블릭 액세스 여부, 보안그룹 설정을 하여 복원합니다.

DB 인스턴스 클래스는 필수 칸이지만 선택이 되지 않습니다.

스냅샷 그대로 인스턴스 클래스가 만들어지니 신경 쓰지 않아도 됩니다.

 DBeaver 데이터베이스 클라이언트 애플리케이션에서 연결 시도를 테스트합니다.

로컬에서 연결이 성공한 걸 확인했습니다!

기존 데이터베이스 인스턴스는 보내줍니다.

6. AWS S3 버킷 이전

AWS S3 스토리지 버킷을 새 계정 쪽으로 옮깁니다.

새 계정에서 버킷을 만들고 AWS CLI 도구를 이용하여 다른 계정으로 모두 옮깁니다.

aws configure
# 새 계정 IAM 으로 설정

aws s3 sync s3://기존계정버킷이름 s3://새계정버킷이름 --source-region ap-northeast-2 --region ap-northeast-2

aws s3 sync 명령어로 기존 계정 버킷의 모든 파일을 새 계정 버킷으로 복사합니다.

 

AWS S3 버킷 정책을 모든 사람이 Read 할 수 있게 변경합니다.

{
  "Id": "Policy1685771003230",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1685771001157",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::moti-media-storage/*",
      "Principal": "*"
    }
  ]
}

 

7. AWS Route53 도메인 이전

AWS Cloudfront 배포와 Route53 설정을 이전할 때 도메인이 필요하므로

기존 계정에서 도메인을 이전합니다.

AWS Route53 도메인 화면에서 도메인 이전 버튼을 누릅니다.

이전에 사용하던 도메인을 입력하면 이전 계정에서 해야할 일을 알려줍니다.

 

첫 번째로 이전 잠금을 해제해야 합니다.

확인해보니 이미 비활성이라 건드리지 않았습니다.

두 번째로 연락처 정보를 가져올 수 있도록 개인 정보 보호를 비활성화합니다.

개인 정보 보호가 활성화되어 있어서 비활성화를 변경한 후 저장합니다.

연락처 업데이트 요청을 제출하고 나서 한 5분 정도 지나면 AWS Route53 측에서 업데이트 완료 이메일이 옵니다.

 

AWS CLI Route53Domains 의 Transfer-domain-to-another-aws-account 연산으로 새 계정ID 로 도메인을 옮깁니다.

aws route53domains --region us-east-1 transfer-domain-to-another-aws-account --domain-name 도메인명 --account-id 계정ID
{
    "OperationId": "11cfe974-90a7-43ba-b1e0-2ed32caa296b",
    "Password": "..."
}

여기서 나온 Password 를 메모합니다.

새 계정ID 에서 수락할 때 입력해야 합니다.

 

새 계정의 도메인 > 대기 중인 요청에서 아래와 같이 확인할 수 있습니다.

 

AWS CLI Route53Domains 의 accept-domain-transfer-from-another-aws-account 연산으로 수락합니다.

aws route53domains accept-domain-transfer-from-another-aws-account --region us-east-1 --domain-name 도메인명 --password 비밀번호

대기 중인 요청 목록에서 사라지고 등록된 도메인으로 이동됩니다.

성공적으로 도메인 이전을 성공했습니다.

기존 계정에서 등록된 도메인 목록을 확인하면 사라진 걸 확인할 수 있습니다.

이후 새 계정에서 개인 정보 보호를 활성화하고 이전 잠금을 활성화합니다.

 

8. AWS Route53 호스팅 영역 생성 & 도메인 네임서버 등록

이제 AWS Route53 호스팅 영역과 도메인을 이어봅니다.
AWS Route53 호스팅 영역 페이지에서 새 호스팅 영역을 생성합니다.

도메인 이름에 이전한 도메인 이름을 넣고 생성합니다.

 

생성한 호스팅 영역에 들어가봅니다.

아래 처럼 NS(네임 서버)가 등록되어 있습니다.

 

이 네임서버를 이전한 도메인에 등록해야 합니다.

네임 서버를 복사하거나 새 탭으로 다음 작업을 합니다.

 

다시 도메인 > 등록된 도메인 페이지로 이동합니다.

그리고 이전한 도메인 상세 페이지로 이동합니다.

 

작업 버튼을 눌러 '이름 서버 편집' 버튼을 누릅니다.

예전 호스팅 영역의 네임 서버를 모두 지우고, 현재 복사한 네임 서버를 하나씩 등록해줍니다.

네임 서버가 적용되기 까지 시간이 조금 소요될 수 있습니다.

 

9.  AWS Cloudfront 배포 생성

AWS S3 스토리지 캐싱을 위해 AWS Cloudfront 배포를 생성합니다.

원본 도메인으로 아까 생성한 S3 버킷 도메인 주소를 선택합니다.

뷰어 프로토콜 정책으로 HTTPS only 를 선택하여 HTTPS 프로토콜만 허용합니다.

아시아(한국) 에서만 사용하므로 '북미, 유럽, 아시아, 중동 및 아프리카에서 사용' 으로 선택합니다.

대체 도메인 이름(CNAME) 을 추가합니다.

HTTPS 프로토콜을 사용하기 위해 사용자 정의 SSL 인증서를 선택합니다.

새 계정에선 아직 ACM 에서 생성한 인증서가 없으므로 인증서 요청을 클릭합니다.

인증서 요청하는 페이지가 새로 나타납니다.

이 때, 인증서는 미국 동부(버지니아 북부) 리전(us-east-1) 에만 있어야 하므로 해당되는지 다시 한 번 확인합니다.

도메인 이름을 입력하고 검증 방법과 키 알고리즘을 선택한 후 요청합니다.

인증서 목록에서 '검증 대기 중' 상태로 된 인증서가 나타납니다.

인증서를 클릭하여 세부 페이지에서 Route 53에서 레코드 생성 버튼을 누릅니다.

그러면 호스팅 영역에 자동으로 추가해줍니다.

약 3분 정도의 시간이 지나면 발급됨으로 변경됩니다!

다시 CloudFront 생성 화면에서 인증서를 새로고침 해봅시다.

아래에 새로운 ACM 인증서가 나타난 걸 확인할 수 있습니다.

선택해줍니다.

그 다음 배포 생성 버튼을 누릅니다.

10. AWS Route53 설정 이전

이전 계정에서 설정한 AWS Route53 설정을 이전합니다.

클라우드 프론트 배포와 연결하고 EC2 인스턴스 탄력적 IP 주소와 연결하고 기타 이전에 사용했던 설정으로 만듭니다.

 

저는 이전에 사용했던 CloudFront 서브도메인이 안되어, 다른 서브도메인으로 만들었습니다.

그에 따라 서버 코드와 DB 저장된 주소를 아래와 같이 치환했습니다.

UPDATE files
SET cardUrl = Replace(cardUrl, "https://storage.moti.company/", "https://cdn.moti.company/"),
cardSvgUrl = Replace(cardUrl, "https://storage.moti.company/", "https://cdn.moti.company/"),
cardPngUrl = Replace(cardUrl, "https://storage.moti.company/", "https://cdn.moti.company/")
WHERE id > 0;

UPDATE answers
SET imageUrl = Replace(imageUrl, "https://storage.moti.company/", "https://cdn.moti.company/")
WHERE id > 0;

 

11. 이전 계정 해지

이전 계정을 모두 정리하고 계정을 삭제합니다.
EC2 인스턴스를 삭제하고 탄력적 IP 를 릴리스합니다.
RDS 인스턴스, S3 버킷, CloudFront 배포, Route 53 호스팅 영역 등등 모두 삭제합니다.

 

계정을 삭제하는 방법은 아래와 같습니다.
우측 상단 내 계정 이름을 눌러 계정 버튼을 누릅니다.

스크롤을 맨 아래로 내리면 계정을 해지하는 버튼이 있습니다.

해지 버튼을 눌러 계정을 해지합니다.

계정을 완전히 해지하기 까지 시간이 걸립니다.

로그아웃 하고 계정이 삭제되기 까지 기다리면 됩니다.

 

마무리

꽤 오랜 시간이 걸렸습니다.

원래 노션에 부분 부분 정리해 뒀다가, 이번에 이전 작업 하면서 정리해두려고 했는데요.

시간이 지나면서 예전과 다른 부분도 많아졌어요.

생각보다 고려할 사항이 많아 분량이 많아졌네요.

 

여러 시행착오를 거치면서 글이 완성됐습니다.

혹시 중간에 모르는 부분과 궁금한 점이 있으시면 언제든지 댓글로 달아주시기 바랍니다.