RDS 삽질기 (feat. AWS VPC 터널링)

DaeChan Jo·2023년 12월 1일
0

데일리삽질

목록 보기
7/8

개발환경 : macOS(m1) / nestjs / postgres / typeORM

무서운 AWS 과금

최종적으로 원하는 시스템 아키텍쳐를 하나하나 적용시켜보기로 하고, 오락가락하는 EC2 t2.micro 인스턴스의 메모리를 조금이라도 확보하고자 데이터베이스 컨테이너를 내리고 RDS부터 붙여주기로 마음먹었었다.

처음엔 감히건방지게 별다른 설명을 보지 않고 무작정 RDS 인스턴스 생성을 시도했었다가 AWS의 청구 예상 비용 협박으로 잠시 주춤했다.

분명 프리티어 템플릿으로 생성을 진행했고 설명 중 과금요소가 있는 옵션들은 전부 제외했는데도 예상 청구액이 잡혀 이게 뭔가 했다.
다른 사람들의 사용 후기를 찾아보니 RDS프리티어 사용중 요금이 청구되었다는 사례가 종종 보이는걸 보아 내가 설정을 잘못했나 싶어서 이것저것 건드려봐도 예상 청구 비용은 사라지지 않았다.

어차피 부담스러울 정도의 금액도아니고 나오면 납부하자는 생각으로 생성했는데 3일차에 접어드는 지금까지 잡히는 비용이 없는걸 보니 구라 청구 예상 비용이라는게 결론.





기술블로그 꼬ㅊ미남 형들 말만 믿다가 하루를 날렸다

그렇게 과금 이슈를 뒤로한 채, 생성한 RDS를 로컬에서 접근해보기로 했다.
근데 왠걸, 연결이 안된닿...
요청이 가는걸 보니 경로는 맞는데 연결을 거부당했다.

편의를 위해 인바운드 규칙을 anywhere로 설정해놨었고 퍼블릭 엑세스도 허용해놓은 상태였는데 연결이 되지 않는 이유를 도무지 찾을 수 없었다. 그렇게 죄 없는 인스턴스를 지우고 반복하기 시작했다.

수 많은 기술 블로그에선 다들 너무나도 간단하게 연결에 성공하고 있었는데 왜 나는 안될까..
로그라도 상세했으면 좋겠지만 'The connection attempt failed' 가 끝이였고 결국 돌고 돌아 파이널리 공식문서 튜토리얼 첫 페이지에서 이슈의 원인을 찾아버리고 말았다.



공식문서는 생각보다 친절하다 (하지만 죽어도 안보죠?)

but resources outside of the VPC can't access it

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

그렇다. 애초에 RDS는 EC2와 연계해서 사용하기 위한 인스턴스라 EC2의 VPC 내부에서만 접근할 수 있도록 설계되어있다.

하지만 퍼블릭 엑세스를 허용해놨다면 해당 VPC 외부에서도 접속할 수 있는게 맞다고는 하는데 왜 나는 안되는지 의문...

그리고 참고했던 기술블로거들의 글들을 보면 ssh 터널링으로 EC2를 거쳐 RDS에 접속해놓고 그 부분에 대한 설명이 하나도 없었다.
뭐 결국 남들이 차려놓은 밥상에 숟가락 얹었다가 배탈난 꼴이라 할 말이 없긴 함..

그렇게 일단은 데이터베이스 툴에 ssh 터널을 추가해서 연결에는 성공했지만, app.module에 데이터베이스 연결설정에도 ssh 터널링을 추가해주고 배포시엔 다시 삭제해야하는 번거로움이 있기에 로컬 포트포워딩을 사용하기로 했다.




포트포워딩으로 간편하게 RDS에 접속하기

[출처] https://neverfadeaway.tistory.com/42
자세한 설명은 이미 좋은 자료가 너무너무 많기 때문에 생략합니다

간단하게만 설명하자면 localhost+사용할포트 경로를 EC2 VPC 내부의 RDS주소로 요청하게 변환해주는거다.
예를 들면 다음과 같은 방식으로 VPC를 뚫고 RDS에 접근할 수 있게 된다
localhost:15432 -> EC2 -> RDS

이렇게 포트포워딩을 사용하면 매번 ssh터널링 코드를 설정할필요가 사라지고 데이터베이스 툴에 연결할때도 간단하게 로컬호스트와 지정한 포트를 사용하면되니 편리하다.

터미널에 다음을 실행하면 백그라운드에서 포트포워딩이 유지된다.

ssh -f -N -i <pem경로> -L <사용할로컬포트>:<RDS앤드포인트>:<RDS개방포트> <EC2유저>@<EC2퍼블릭IP> -v
  • -f : 백그라운드 실행
  • -N : 셸을 실행하지 않고 포트 포워딩만 설정
  • -i : 개인 키 파일을 지정
  • -L : 로컬 포트포워딩
  • -v : 상세 디버깅 로그

포트포워딩 설정 후 app.module.ts 코드예시

@Module({
  imports: [
    ...modulle,
    TypeOrmModule.forRoot({
      type: "postgres",
      host: process.env.DB_HOST, // localhost
      port: Number(process.env.DB_PORT), // 지정한 포트
      username: process.env.DB_USER_NAME, // rds 마스터 사용자
      password: process.env.DB_PASSWORD, // rds 마스터 암호
      database: process.env.DB_NAME, // DB 이름
      entities: [
       ...entity
      ],
      synchronize: true, // 엔터티 동기화
      ssl: {
        rejectUnauthorized: false, // 포트포워딩시 인증하므로 false로 설정
      },
    }),
  providers: [Logger],
})
export class AppModule {}
profile
BackEnd Developer

0개의 댓글