Devlog/Web

Heroku 배포 - 백엔드 배포 과정 중 나를 당혹스럽게 만들었던 상황 모음집

FATKITTY 2022. 3. 18. 19:58
반응형

프론트 배포는 Netlify로, 백엔드는 Heroku로 배포하기로 했다.

Netlify를 통한 프론트 배포는 나름 easy peasy lemon squeezy였는데,

백엔드 배포는 정말이지 나를 하루웬종일 괴롭혔다. 🤯

내가 무지한 탓에 필요 이상으로 헤매고 고생한거긴 하지만 ㅎ...

어쨌든 정말 산 넘어 산이었다.

 

 

 

1. Heroku Git을 통한 deployment - 뭐 이렇게 복잡하지?

사실 Heroku는 documentation를 정말 친절하고 자세하게 제공해주기 때문에, 

사용방법을 제대로 이해한 후 시키는대로 잘 따라가기만 한다면 헤맬 일이 거의 없다.

하지만 난 떠먹여줘도 못 받아먹었다는 점 🙄

한참을 헤매고 헤매다가 겨우 배포했다.

 

 Heroku CLI 설치가 안 되는 것 같은데?

Install the Heroku CLI

Download and install the Heroku CLI.

 

시키는대로 Windows 64-bit installer를 통해 CLI 설치 시작.

설치가 잘 되는듯 하더니, 막판에 installer가 자기 맘대로 작업 마무리를 안 짓고 꺼져버렸다.

다시 시도해봐도 똑같이 또 꺼짐.

시작부터 버벅버벅...

알고 보니 흔한 증상인듯 했으나, 정확한 원인이 뭔지는 모르겠음.

아무튼 그래서 cmd 창에다가  npm install -g heroku  커맨드를 주고 설치 성공.

 

난 관리자모드에서 설치했지만 꼭 그럴 필요는 없는듯

 

 heroku login?

정말 어이없고 부끄럽게도 첫 단계에서부터 막혔다.

로그인을 어디서 어떻게 하라는거지..?

CLI 설치한 것처럼 cmd 창 키고 냅다 heroku login 치면 되는건가?

되긴 하는데,, 이게 맞나?

 

🙄🙄🙄🤦‍♀️🤦‍♀️🤦‍♀️

그냥 프로젝트 루트 경로에서 해주면 된다.

코드 에디터에서 터미널을 켜주고 루트 경로로 가서

heroku login → Enter → 팝업창에서 로그인버튼 클릭 하면 끝.

괜히 쫄아서 어버버댔다.

 

※ 혹시 로그인 버튼 누른 후에 IP address mismatch 경고문이 떴다면?

당황하지 말고 터미널에  heroku login -i  명령어를 입력해준 후 이메일, 패스워드를 입력해주면 됨.

 

 

error: failed to push some refs to 'https://git.heroku.com/'

이 문제 때문에 몇 시간을 삽질했다.

https://devcenter.heroku.com/articles/troubleshooting-node-deploys 

여기에 적힌 것들도 하나하나 다 확인해봤지만 문제는 해결되지 않았다.

 

도대체 어디서 뭐가 잘못된건지 도저히 모르겠어서 또 다시 뇌정지가 왔는데,

원인을 알고보니 내가 너무 바보같아서 한심해짐..

결국 프로젝트의 폴더 구조 때문이었는데,

초반에 heroku로 push하려던 프로젝트의 구성 요소들은 아래와 같았음.

 

 

한마디로 한 프로젝트 폴더 안에 frontend, backend가 모두 들어있었음.

나는 저 backend만을 배포하려고 heroku를 쓰러 온건데,

무식하게 project 폴더 통째로 push하려고 했던거다.

만약 저대로 배포에 성공했어도, 쓰이지도 않을 frontend 요소들이

resource 용량을 쓸데없이 많이 잡아먹어서 문제가 됐을 것이다.

 

아무튼 그래서 본론으로 돌아오자면, push가 안 됐던 결정적인 이유는 바로

루트 경로에 package.json이 없었기 때문이었다.

 

문제를 해결하기 위해 프로젝트 구조를 뜯어고쳐야 하는 상황.

이참에 프론트는 프론트대로, 백엔드는 백엔드대로 폴더를 만들어 분리시키기로 했다.

 

 

이렇게 백엔드 프로젝트를 따로 만들고 루트 경로에 package.json을 두니까

더 이상 문제가 생기지 않았고, 정상적으로 배포가 완료되었다.

 

반응형

 

2. Deploy는 잘 됐고, 이제 디비만 연결하면 되는데...?

 

❓ Which database server should I use?

이젠 데이터베이스를 어떻게 연결할지가 문제였다.

 

사실 이 문제는 원래 고민거리가 아니었다.

여태 로컬 환경에서 개발하면서 Amazon RDS 프리티어 서비스를 통해 구축한 DB서버를 잘 이용하고 있었기 때문이다.

왜 로컬에서 굳이 DB서버를 이용했느냐고 묻는다면, 집에서는 데스크탑/밖에서는 노트북으로 개발했기 때문에

업데이트 상황이 실시간으로 공유가 안 되는 로컬 DB로는 한계가 있었다.

(이제 와서 보니 AWS EC2/Lightsail 등을 통해 MySQL 원격접속을 하면 해결될 문제였는데 괜히 RDS 씀)

 

그렇게 별 생각없이 RDS를 잘 쓰다가, 어느날 갑자기 등골이 서늘해졌다.

산학프로젝트 때 AWS 서비스들을 신나게 사용하다가 약 $500이 청구됐던게 갑자기 생각나서...

허겁지겁 결제 대시보드를 확인해보니, 아니나 다를까 청구서가 이미 찍혀있었다. 💸

 

그나마 요금이 얼마 안 나와서 천만다행 ㅜㅜ

 

디비에 데이터가 진짜 조금 들어있고, 일주일 정도만 가동한 후에 확인했기에 망정이지...

그냥 아무 생각없이 막 썼다면 정말 큰일날 뻔했다.

프리티어라면서... 이럴거면 "Free"라고 이름 붙이지나 말든가 흑흑

 

이렇게 된 이상 다시 로컬 디비를 쓸 수 밖에 없다고 생각했다.

그래 뭐, 이럴 때를 대비해서 컴퓨터 디스크 용량 넉넉하게 잡아 맞춘거 아니겠어?

전기세도 저렴하니까 컴퓨터도 24시간 켜놓으면 되지 ㅎㅎ (?)

 

 

더 이상 AWS에 삥 뜯기고 싶지 않아서 RDS는 곧바로 shut down 시켰다.

그리고나서 배포된 서버가 로컬 디비에 접속을 할 수 있는지, 돌아가긴 하는지 테스트를 해봤다.

역시 (너무 당연하게도) 안 돌아간다!

에러 로그를 읽어보니 예상대로 로컬 디비 127.0.0.1:3306 에 접속하려던게 문제였다.

 

...

Error: connect ECONNREFUSED 127.0.0.1:3306

...

at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) {
errno: -111,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 3306,
fatal: true
}

...

Error: Cannot enqueue Query after fatal error.

...

heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/api/admin" ~ status=503 bytes=0 protocol=https
...
heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/api/video" ~ status=503 bytes=0 protocol=https

 

이 문제를 해결하려면 디비를 어떻게든 어딘가(AWS 제외)에 배포를 해줘야 하는 상황.

이번엔 내 나름대로의 기준을 세우고 디비 호스팅 서비스 조사에 신중을 가했다.

 

1. 서비스 사용 방법이 과도하게 복잡하면 안 됨

2. DB 서버 구축~유지 비용이 절대로 많이 들면 안 됨 (무료면 매우 감사)

3. 사람들이 많이 쓰는 서비스여야 함 (= 검색했을 때 관련 자료가 많이 나와야 함)

4. RDBMS

 

여러 훌륭한 서비스들이 존재했지만, 개중 가장 눈에 띈 두 가지는 Oracle Cloud와 Firebase.

 

 

하지만 결론부터 말하자면 둘 다 탈락 🥴

 

Oracle Cloud는 평생 무료인 것이 정말 맘에 들었고, 자료도 적당히 많았는데, 

1번을 만족 못 한게 나한테는 너무 치명적이었다.

얼마나 설치할게 많고 환경 설정할게 많던지...

이것저것 설치만 하다가 하루가 다 간게 너무 짜증나서 결국 사용하기를 포기했다.

 

Firebase는 기준 1,2를 만족했지만 3,4는 만족하지 못 했다.

특히 4번. Firebase는 NoSQL을 사용해야해서 탈락.

 

이제 어쩌지, 다른 방법이 없나 싶었던 찰나에 스쳐지나간 생각

'서버 호스팅했던 heroku가 PasS(Platform as a Service)인데, 그럼 당연히 DB 구축도 해줄 수 있는거 아닌가?'

아니 왜 진작에 이 생각을 못 했냐고

 

검색해보니 된다!

복잡하지도 않고 사람들이 많이 잘 쓰고 있다.

거기다 심지어 한 달에 1000시간 무료라니!!

한 달에 41일을 공짜로 쓸 수 있다는 얘기 ㅋㅋㅋ

하지만 용량이 5MB 밖에 안 되는게 맘에 걸린다.

금방 다 쓸거 같지만... 일단은 ㄱㄱ

 

 

근데 로컬 디비를 heroku에 도대체 어떻게 배포(?)하는거지?

이 부분이 정말 난감했던게,

검색해보면 대부분 heroku DB에 접속 후 거기에 테이블을 직접 만드는 방법을 알려준다.

거기다 설상가상으로 MySQL을 많이들 안 쓰는 분위기인 것 같다.

음,, 나는 이미 로컬 환경에 다 만들어져 있는데... 처음부터 다시 다 만들어야 하나...?

나도 MySQL 말고 PostgreSQL을 써야하나?...

고민하던 찰나에 ClearDB add-on을 발견! my lifesaver 😭

 

우선 프로젝트에 ClearDB ignite 옵션을 설치해준다.

> heroku addons:create cleardb:ignite

 

그리고 나서 please enter a credit card 어쩌구 안내가 뜨면 

https://dashboard.heroku.com/account/billing 에서 카드를 등록해준다.

카드를 등록해야 무료 사용시간 450 hours를 더 받아서 한 달에 총 1000시간을 무료로 쓸 수 있다.

 

그 다음, 생성된 DB의 주소를  heroku config  를 통해 확인한다.

로그에 아래와 같은 형식으로 url이 찍힌다.

> heroku config
CLEARDB_DATABASE_URL: mysql://[user name]:[password]@[host name]/[password2]?reconnect=true

 

이 정보로 heroku 환경 변수 설정을 해주고,

> heroku config:set MYSQL_HOSTNAME=us-cdbr-XXXXXXX.cleardb.net

 

로컬 .env 파일에 db connection 정보를 수정해준다.

DB_HOST=host name
DB_USER=user name
DB_PASSWORD=password
DB_DATABASE=password2

 

이제 .env에 포함된 환경변수 설정들을 올려준다.

// heroku env설정 올리는 플러그인 설치
> heroku plugins:install heroku-config

// .env 설정 올리기
> heroku config:push

 

여기까지 하고 heroku config 명령어를 입력해보면 성공적으로 업로드된 환경변수 정보를 확인할 수 있다.

 

 

로그가 잘 찍히면 끝.

※ DB 서버를 연결할 때에도 로그에 찍힌 정보를 그대로 입력해주면 된다.

 

 

 

 

3. 하지만 툭하면 발생하는 Error: Network Error...

성공적으로 배포한 듯 했으나, 또 다른 난관에 봉착.

자꾸 네트워크 에러가 뜨는 것이다.

콘솔을 확인해보니 Status Code 503이 떠있었다.

백엔드 서버가 아예 안 돌아가는 듯 했다.

 

원인을 알아보니, 일정 시간동안 트래픽이 발생하지 않으면

서버가 sleep 상태로 들어가버려서 그랬던 것이다. ㅠㅠ

그렇다고 이 문제를 해결하기 위해 유료 플랜을 사용할 수는 없다.

그럼 어떻게 해결하지?

 

방법은 의외로 간단했다.

DB 문제를 해결했던 것처럼 heroku가 제공해주는 add-ons를 또 활용하면 된다.

이번에는 New Relic APM 이라는 모니터링 add-on을 사용할 것이다.

 

1. New Relic add-on 추가

// 무료 플랜 wayne
> heroku addons:create newrelic:wayne

// 잘 추가됐는지 확인
> heroku config

config 정보에 NEW_RELIC_LICENSE_KEY 랑 NEW_RELIC_LOG 가 잘 찍히면 성공.

 

2. npm 패키지 설치

> npm install newrelic --save

 

3. 메인 모듈 코드 최상단에 New Relic 추가

require ('newrelic');

require ('newrelic');

 

4. git push

> git add .
> git commit -m "Add New Relic"
> git push heroku master

// push 완료 후 deploy 상태 확인
> heroku logs --tail

 

이렇게 하면 더 이상 503 에러가 뜨는 일은 없어진다! 🥳

다만 30분 이상 접속이 없었던 상태라면 sleep 상태에서 깨어나서

npm run build를 다시 하느라 7초 정도의 딜레이가 생기긴 한다.

이게 싫다면 $7/month Hobby Plan을 쓰면 된다. :-)

 

 

 

참고자료

https://nhj12311.tistory.com/276

https://donologue.tistory.com/371?category=919791 

https://velog.io/@broccoliindb/Heroku

https://stackoverflow.com/questions/5480337/easy-way-to-prevent-heroku-idling

https://docs.newrelic.com/docs/apm/agents/nodejs-agent/hosting-services/nodejs-agent-heroku/

 

 

  ❤와 댓글은 큰 힘이 됩니다. 감사합니다 :-)  

반응형