Nginx+PM2+Multer의 환장하는 502에러

Gomi·2022년 6월 20일
0

🚧 문제상황


프로젝트에서 백엔드를 하게 되었다.
일단 프로젝트가 완성될 때 까지 배포는 localtunnel로 잠깐 미뤄놨었는데,
너무 불편해서 EC2에 배포를 하게 되었다.

EC2에서는 도커를 통해 nginx이미지 까지올리려 했으나...잘 되지않아서 nginx는 로컬로 설치했다.
Docker file에는 새롭게 pm2 까지 세팅해서 무중단으로 움직이게끔 해두었다.

문제는 새롭게 배포를 하고나서 포스팅 기능이 작동하지 않는 것이었다.

도커 로그를 찍어봐도 이상하게 다른 API들은 잘 작동하는데
유난히 포스팅 요청만 보내면 에러로그도 보여주지 않고 502 에러를 내보낸 뒤 재시작 시켜버린다.


👀 원인파악


포스팅 기능과 관련된 라이브러리들에서 문제가 생겼을 것으로 판단했다.
502에러 자체는 nginx너머 서버앱에서 문제가(app crashed) 생겼기 때문에 발생했다.
결론부터 말하자면 pm2와 nodemon이 문제였는데, 문제를 발견하기도 어려웠 것이 저 두 패키지는
오류메시지까지 덮어써서 재시작을 시켰기 때문에

$ sudo docker logs

명령어로 살펴봐도 에러 메시지가 나오지 않았기 떄문이다. 물론 로그를 따로 저장하면 다를것이다.
multipart form data를 발송하게 되면 각각의 form data가 하나씩 요청을 보내면서 들어간다.

원인을 제공한 코드는 다음과 같다.

import multer from 'multer'
import path from 'path'
import fs from 'fs'

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    const dir = path.join(__dirname, '../uploads')
    const author = req.currentUserId
    if (!fs.existsSync(dir)) fs.mkdirSync(dir)
    if (!fs.existsSync(path.join(dir, author))) fs.mkdirSync(path.join(dir, author))
    cb(null, path.join(dir, author))
  },
  filename: function (req, file, cb) {
    const fileName = new Date().valueOf() + '_' + file.fieldname + '_' + file.originalname
    cb(null, fileName)
  }
})

const fileServer = multer({ storage })

export { fileServer }

파일을 저장하며, 저자에 따라 폴더를 동적으로 생성하기도 한다.
따라서 파일 요청이 올 때마다 서버 내부의 파일구조에 변화가 생긴다.
앞선 두 패키지(nodemon, pm2)는 파일구조가 바뀌면 서버를 재가동하기 때문에 각각의 파일 요청은 모두 끊어진다.


  • pm2


이녀석의 재가동을 멈추게한 코드는 다음과 같다.
업로드 폴더 내의 파일 갱신을 감지하지 못하도록 한다.
ecosystem.config.js

module.exports = {
  apps: [
    {
      name: 'fcgserver',
      script: 'npm start',
      watch_delay: 5000,
      ignore_watch: ['node_modules', './uploads']
    }
  ]

}

Dockerfile

FROM node:16
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm i
RUN npm i -g pm2
COPY . ./
EXPOSE 4000
CMD ["pm2-runtime", "start", "ecosystem.config.js"]



  • Nodemon


개발환경에서는 노드몬으로 시작해도 파일구조를 감지하지는 않았는데
왜 배포환경에서는 파일구조를 감지하고 재시작 시키는지 모르겠다.

package.json(수정 전)

"scripts": {
    "start": "nodemon index.js --exec babel-node",
  },

package.json(수정 후)

"scripts": {
    "start": "babel-node index.js",
  },

애초에 노드몬은 개발용 프로그램이라 아무래도 배포환경에서는 쓰는법이 없는 것 같다.
개발환경과 프로덕션환경에 대한 분리가 절실해지는 하루였다....

profile
터키어 배운 롤 덕후

2개의 댓글

comment-user-thumbnail
2022년 7월 27일

노드몬 vs pm2몬

답글 달기
comment-user-thumbnail
2022년 7월 27일

노드몬 vs pm2몬 vs 아구몬

답글 달기