포켓몬 도감을 만들어보자_v2 - BE

이기찬·2024년 4월 12일

프로젝트

목록 보기
5/6
post-thumbnail

📖 내용

  • PokéHub 프로젝트에서 사용되는 백엔드 코드에 관한 내용 입니다.
  • pokeapi 에서 제공 되지 않는 정보들을 DB에 저장하여 사용자에게 제공 합니다.
  • 사용자 인증과 그에 따른 게시판 관련 로직이 작성 됩니다.

혼자서 작업 하는 개인 프로젝트였기 때문에, 단일 코드 베이스에서 작업 하는 것이 효율적일 수도 있겠다는 생각을 하기도 하였습니다. 하지만 어느 정도의 백엔드 플로우를 프론트 개발자가 이해 할 줄 알아야 하고 유지보수와 성능의 개선을 위해 코드를 분할을 하기로 결정하게 되었습니다.



😅 과정 | PokéHub_BE

백엔드 코드가 전반적으로 어떻게 구성되고 진행하였는지에 대한 과정에 대해 작성 해보겠습니다.


서버

  • 백엔드 서버를 구축해본 경험이 많지 않았습니다. 또 코드를 분할해서 작성 해본 적이 없었기 때문에, 가장 익숙한 node.js 환경에서, 이전에 사용 해본 적이 있는 express 를 사용해서 서버를 만들어 보기로 하였습니다.

  • express 를 사용하여 서버를 만드는 간단한 예시 코드 입니다. 보통 node.js 와 같은 commonJS 방식을 사용해서 작성하는 법이 대표적이지만, 작성법이 익숙하지 않거나, ES6 문법을 사용하는 경우 Babel 과 같은 JavaScript 컴파일러를 설치하여 사용하시는 것이 작성하기에 유리 합니다. 제 경우엔 commonJS 보다 ES6 문법을 사용해서 작성하는 것을 선호 하였기 때문에 위와 같은 server.js 를 만들었습니다.



DB

  • pokeapi 에서는 정말 많은 정보가 제공 되지만 존재하지 않는 것들이 있었습니다. 도감 사이트라는 이름에 걸맞게 최대한 다양한 정보를 사용자가 확인할 수 있도록 만들고 싶었습니다. 그 중 하나가 바로 인물 정보였습니다.
  • mongoDB 를 사용하여 DB를 만들기로 하였습니다. JSON 의 구조의 장점을 가져오면서 빠른 속도로 데이터를 가져올 수 있는 BSON 구조로 저장되는 mongoDBpokeapi 와 동일한 익숙한 형태의 정보를 저장 할 수 있다고 생각하였습니다.

  • DB를 생성한 뒤 컬렉션에서 Connect 할 시 URL 정보를 얻을 수 있습니다. mongoose 라이브러리를 사용하여 DB 와 연결 해준 뒤 제가 원하는 정보의 Schema 형태를 생성 해주었습니다.

  • 사용자가 만약 관련된 정보를 찾는다고 하였을 때, 어떤 정보를 위주로 궁금해 할까? 를 생각하며 Schema 를 만들었습니다. 제가 만드는 인물에 관한 정보는 체육관 관장, 사천왕, 챔피언 세가지 종류였는데, 각 Role 에 따라 가지고 있는 정보에 대해서도 차별점을 두고 싶어 형태를 조금씩 다르게 만들어 보았습니다.
    (EX: 체육관 관장 뱃지, 챔피언 전용 BGM, …etc)

  • 인물 정보를 만들어 주는 과정에서 약간의 문제가 있었습니다. 초기에 나무위키에서 정보들을 얻어 DB를 작성 해주었는데, 이미지나 BGM 과 같은 정보들의 주소가 바뀐다는 점이었습니다.

  • 검색 해보니 나무 위키는 정보 보안을 위해 주기적으로 이미지 주소를 바꾼다는 사실을 알 수 있었습니다. 해서 약 2주간 정상적으로 가져와 지던 이미지가 모두 깨지는 현상이 생겼습니다.

  • img src 에 넣어줄 주소가 변하지 않는 이미지, BGM 정보가 필요하다고 생각했기 떄문에, aws-s3 버킷을 생성한 뒤 퍼블릭 액세스가 가능하도록 설정 해주고, DB에 버킷 주소 값을 넣는 방식으로 해결 해주었습니다.


사용자 인증

  • 게시판 기능을 이용하기 위해서 로그인, 회원 가입 등의 절차가 필요했고, UserSchema 를 생성 해주었습니다. mongose.model을 사용하여 User model 을 생성 합니다.

회원 가입

  • Body 로 받은 데이터를 findOne 훅을 사용하여 동일한 데이터를 가진 사용자가 있는지를 검사하고 가입, 이 과정에서 DBuser collection 에 사용자의 정보가 저장 되고 password의 경우 bcrpyt 를 사용하여 해싱 된 값이 저장 됩니다.

로그인

  • 회원가입과 동일하게 findOne 훅을 사용하여 존재하는 사용자인지 검증 합니다. user collection 에 저장된 password 는 해싱 된 값이 들어가 있기 때문에, bcrpyt.compare 를 사용하여 확인 합니다.

  • 로그인 과정에서 조건이 만족하였을 때 세션을 발급, 저장 하기 위해
    express-session , connect-Mongo 라이브러리를 사용하였습니다.

  • session 이 DB에 저장 될 수 있도록 store 옵션에서 를 connect-Mongo 를 사용, cookie 옵션도 적절한 값을 작성 해주었습니다. DB에서 sessions 라는 이름의 컬렉션이 생성 되고, 값이 저장 되는 것을 확인 할 수 있습니다.



게시판

  • 사용자가 직접 CRUD를 할 수 있는 환경을 만들기 위해 게시판 기능을 구현 하였습니다.
  • 게시판의 경우 로그인 된 사용자가 게시글, 댓글, 답글에 대하여 작성, 수정, 삭제가 가능하도록 그리고 좋아요를 저장하거나 취소 할 수 있도록 로직을 구현 하였습니다.


스크래핑

  • 사용자가 좀 더 다양한 정보를 확인 할 수 있도록 포켓몬에 관련 된 이벤트 항목들을 정리한 페이지를 만들고 싶었습니다. 포켓몬 이벤트가 언제 어디서 어떻게 열리는지 조사하거나 최신화 하는 과정은 직접 하기에는 비효율적이라는 생각을 하게 되었고, 잘 정리 된 정보들이 포켓몬코리아에 있다는 것을 알게 되어 puppeeteer 를 사용하여 웹 스크래핑을 하기로 결정 하였습니다.




😓 배포 과정

프로젝트가 제 생각보다 장기화 된 가장 큰 이유는 바로 배포였습니다. 프론트 같은 경우 vercel 을 이용하여 배포 하였는데, 쉽고 간편해서 vercel.json 같은 파일 외에 딱히 더 설정 해줄게 없었습니다.
문제는 백엔드 배포 였는데, 배포 방식부터 코드 구조까지 여러가지를 수정하면서, 제가 예상한 기간보다 시간을 더 잡아먹게 되었습니다. 배포하면서 어떤 문제를 겪었는지 어떻게 해결 하였는지 에 대해서 작성해보도록 하겠습니다.


  • 가장 처음 선택한 방식은 바로 Elastic-Beanstalk 을 사용하여 배포하는 방식 이었습니다. AWS 에서 제공하는 배포 환경 중의 하나 이며, 쉽게 배포하고 확장할 수 있도록 해주는 Paas(Platform as a Service)서비스 입니다.

why EB❓

  • 이전에 배포를 진행 하였던 경험이 있습니다. 코딩을 시작 한지 얼마 되지 않았을 무렵 노마드 코더 사이트에서 [풀스택] 유튜브 클론코딩 이라는 강의의 챌린지를 진행하고 있었습니다. 약 6 주 정도 진행 되는 챌린지 였는데, 약 1주가 남은 시점에 배포라는 마지막 과정이 남아있었습니다.

  • 챌린지 완료 후 우수작을 선정하는 과정이 있었는데, 당시 저는 이 우수작이라는 타이틀에 약간 매몰되어 있는 상태 였습니다. 강의 내용 외의 여러가지 기능을 구현하려고 노력하였고, 종료가 약 2일 정도 남은 시점에서 배포를 진행 하였습니다.

  • 배포를 너무 쉽게 생각한 것이 원인이었습니다. 당시 저는 배포 그냥 다 완성 된 코드 어디에 올리기만 하면 되는 거 아닌가? 라는 생각을 하던 초보였고, Heroku 를 통한 배포 과정에서 완전히 멘탈이 나가버렸습니다. 로컬에서 정상적으로 작동 되던 코드들이 배포 과정에서 여러가지 오류가 나면서, 남은 기간 동안 버그를 고치는데, 온전히 시간을 투자 하였으나 결국 해결하지 못한 채로, 미완성 된 프로젝트 배포 Url 을 제출 할 수 밖에 없었습니다.


  • 당시의 실패로 인한 약간의 배포 울렁증(?)이 생긴 저는 Elastic-Beanstalk 를 사용하여 배포 하기로 하였습니다. 인스턴스를 설정을 변경 할 필요 없이 IAM에서 권한 설정만 조금 만져주면 배포가 가능하고 추가적인 요금(프리티어 기준)이 들지 않는 다는 점에서 배포 초보인 저에게 가장 알맞다는 생각이 들어 진행 하게 되었습니다.

  • 하지만 EB 를 사용하는 배포과정에서 문제가 있었습니다. DB 조회는 정상적으로 되었으나, puppeeteer 를 사용한 웹 스크래핑 데이터를 가져올 수가 없었습니다. 확인해보니 puppeeteer 를 실행 시키기 위해 필요한 종속성이 Elastic-Beanstalk 배포 과정에서 자동적으로 설치 되지 않기 때문에, 생기는 문제였습니다. 로컬에서 실행 시 크롬에서 실행 되지만, EB 인스턴스에는 chromium 종속성이 설치 되어 있지 않기 때문 입니다.

해결 방법 대표 예시 글

  • 문제를 해결하기 위한 검색 과정에서 여러가지 해결 방법 중 가장 자세한 해결 법이 나와있는 글 입니다. EB 인스턴스의 로그를 확인 하면서, 위 해결법 이외에도 여러가지 해결방법을 찾아 적용하였지만 잘 해결되지 않았습니다.

chromiumpackages.config

  • EB 인스턴스 환경에서 배포 시 종속성을 설치하는 방법 입니다.
    배포 시에 종속성이 설치 될 수 있도록 하려면 .ebextentions 폴더와 .config 확장자를 가진 파일을 생성 해주어야 합니다.

  • 로그를 확인 해보니 오류 내용이 조금씩 달라지기는 하지만, 해결 되지는 않았습니다.

  • 이후에도 package.lock 파일을 포함 또는 제외 한 후 배포 하거나, puppeeteer.launch() 의 Headless 설정을 변경 하는 등, 검색하여 나온 방법들을 적용 해보았으나 해결될듯 해결되지 않는 상태로 인스턴스를 [ 배포 - 삭제 - 배포 ] 하는 삽질을 반복하다 보니, 내가 지금 뭘 하고 있는 건가? 싶었습니다.



배포 방식의 변경

  • 문제를 해결하지 못해서 솔직한 심정으로 자괴감이 많이 들었습니다. 쉬운 방식으로 하려고 선택한 Elastic-beanstalk 에서도 막히다 보니 답답 하였습니다. 하지만 드는 자괴감 보다 생산성 없이 해결 되지 않을 것 같은 방법을 계속하는 막막함이 더 크게 다가왔고, 결국 저는 Elastic-beanstalk 를 사용한 배포 방식을 포기하기로 하고 aws-ec2 를 사용하여 처음부터 다시 배포를 하기로 하였고 아래와 같은 방식으로 해결 하였습니다.

aws-ec2 배포 과정

  • aws-ec2 에서 ubuntu 환경의 인스턴스를 생성, 보안 그룹(사용자 지정 TCP PORT)을 설정한 뒤 SSH 키를 사용하여 인스턴스에 접속할 수 있도록 하였습니다.

  • git-hub 백엔드 코드를 클론한 뒤 필요한 의존성을 설치 하였습니다.

  • route53 에서 호스팅 영역을 생성 해준 뒤 https 를 사용하기 위해 가비아 에서 구매한 도메인을 등록, 네임서버를 변경 해주었습니다.

  • amazon-certificate-manager 에서 퍼블릭 인증서를 발급 받은 뒤(DNS 검증), CNAME 레코드를 생성 하였습니다.

  • aws-ec2 인바운드 규칙을 재설정 (http, https), 로드 밸런싱 대상 그룹을 생성, 로드 밸런서를 생성 해주었습니다.

  • route53 에서 A 레코드를 생성, 로드 밸런서 리스너 규칙을 수정 하였습니다.

  • pm2 를 이용, 무중단 서비스를 실행 하였습니다.

  • 정상 배포 된 것을 확인 할 수 있습니다. PokéHub_BE


느낀점

  • 위 방식을 진행하면서 어려운 부분도 많았습니다. 처음 사용해보는 ubuntu 환경과 https 를 사용하기 위하여 nginx.conf 설정 변경 방식에서 애를 먹기도 하였습니다.(ACM SSL 인증서를 발급 받아서 해결 하였습니다.)

  • 또 배포가 모두 완료 된 이후에도 cookie가 제대로 발급되지 않는 문제가 있었습니다. 클라이언트와 서버의 도메인이 다르기 때문에 생긴 이슈 였습니다.

FE | https://pokehub-encyclopedia.vercel.app
BE | https://pokehub-encyclopedia.site

  • 기존에는 로컬 환경에서 작업하다보니 포트 번호가 다를 뿐, 도메인은 동일하여 정상적으로 작동 하였지만, 배포 환경에서는 도메인이 다를 시 쿠키 발급시 제약이 있기 때문에 설정을 다르게 해주어야 했습니다.

  • 검색 후 cors origin 에 클라이언트의 도메인 주소를 넣고, cookie secure (https 통신에서는 true 로 변경) , sameSite , Proxy 설정을 추가 하여 해결 하였습니다.


마무리

  • 사실 Elastic-Beanstalk 배포 부분에서 스크래핑 부분을 제외하면 다른 것들은 의도한 대로 작동 하였기 때문에, puppeeteer 를 사용한 웹 스크래핑 부분을 삭제할까? 라는 생각도 많이 하였습니다.

  • 하지만 이전 프로젝트에서도 초기 기획 하였던 부분을 시간이 부족하다는 이유로 얼렁뚱땅 넘겼던 적이 있었는데, 다시 그런 짓을 반복하고 싶지는 않았기 때문에 혼자 합리화 하지 않고 끝까지 할 수 있었던 것 같습니다.

  • 익숙하지 않은 탓에 예상 시간보다 더 걸리긴 하였으나, 개발이라는 것은 역시 계속 찾으면 답이 나온다는 것을 알 수 있었습니다. 저만의 방식으로 프로젝트를 처음부터 끝까지 작업을 완료한 것은 꽤나 성취감을 느낄 수 있는 일이었습니다.



긴 글을 읽어주셔서 감사합니다!
profile
안녕하세요

0개의 댓글