이번 [면접어때] 프로젝트의 프론트 배포과정에서 겪은 에러를 기록해본다.
도커로 배포하는 것도 3번째인데 매번 배포환경이 달라지다보니 한 번에 성공한적이 없는 것 같다.
저번 [아코하] 프로젝트에서도 Nextjs를 사용해서 배포했지만, 패키지 매니저로 yarn-berry를 쓰면서 도커의 multi-staging-build로 빌드 이미지 최적화를 하려했으나.. yarn-berry pnpMode의 패키지 의존성 문제, Nextjs13과의 호환성 문제 때문에 상당히 애를 먹고 끝내 타협 엔딩으로 막을 내렸었다!
그래서 이번 프로젝트 배포에서는 yarn을 쓰기 때문에 더 최적화 빌드가 간절했다.
배포 준비
이번에 배포한 환경은 크게 yarn + Nextjs + Docker이고 nginx-package-manager를 포함했다.
감사하게도 Nextjs 깃헙에서 Dockerfile 예시 코드를 제공해주고 있었기에 참고했다.
https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
Dockerfile.yml
// Dockerfile.yml
FROM node:18-alpine AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /usr/src/app
COPY package.json yarn.lock ./
RUN yarn --frozen-lockfile
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /usr/src/app
COPY --from=deps /usr/src/app/node_modules ./node_modules
COPY . .
RUN yarn build
FROM base AS runner
WORKDIR /usr/src/app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /usr/src/app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /usr/src/app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /usr/src/app/.next/static ./.next/static
USER nextjs
EXPOSE 3001
CMD ["node", "server.js"]
그리고 nginx-proxy-manager 이미지를 사용하기때문에 docker-compose로 한 번에 빌드하기위해 docker-compose.yml도 작성했다.
docker-compose.yml
// docker-compose.yml
version: '3.8'
services:
npm:
image: jc21/nginx-proxy-manager:latest
container_name: nginx-proxy-manager
restart: always
ports:
- 83:83 #관리포트
- 80:80 #http
- 443:443 #https
volumes:
- ./nginx-proxy-manager/data:/data
- ./nginx-proxy-manager/letsencrypt:/etc/letsencrypt
environment:
DISABLE_IPV6: 'true'
depends_on:
- myeonjeobeottae
myeonjeobeottae:
container_name: myeonjeobeottae
build:
context: .
dockerfile: Dockerfile.yml
ports:
- '3001:3001'
이렇게 준비하고 이제 EC2에 배포하러 달려가본다.
EC2 deploy
나의 계획은 다음과 같았다.
1. EC2 SSH 접속
2. 면접어때 프로젝트 clone
3. 'docker-compose up -d --build'
4. 쨘 성공!
하지만 어림도없지.. 이번 포스팅을 쓰게된 에러가 여기서 발생했다.
500 internal Server ERROR
docker container는 잘 올라갔다. 컨테이너를 올리는 과정에서는 에러가 발생하지 않았다. 하지만 배포 주소로 접속 시 500 internal Server Error가 발생했다. 같이 올린 nginx는 접속도 잘되고 이상이 없다. 뭐가 문제일까?
내가 생각하는 가장 의심가는 부분은 port였는데, 빌드 상에서 문제가 없다면 app을 서빙하는 port가 원인이지 않을까 싶었다.
그래서 docker port 설정 부분을 찾아갔다.
port 설정 부분
port와 관련있는 부분은 두 곳이다. dockerfile과 docker-compose.
// dockerfile.yml
...
EXPOSE 3001
CMD ["node", "server.js"]
// docker-compose.yml
...
myeonjeobeottae:
...
ports:
- '3001:3001'
[면접어때]는 3001 port로 돌아간다. 그래서 dockerfile에서 EXPOSE 3001 로 port를 열어주고 docker-compose.yml에서 '3001:3001'로 nginx가 reverse-proxy해준 3001포트로 들어온 요청을 [면접어때]의 3001 포트로 연결시켜주었다.
여기까지 봤을 때, 이상한 점을 찾지 못했다. port를 3001 외에 다른 포트로 바꾸면서 테스트해봐도 결과는 같았다. 뭐가 문제일까..
생각해봐도 답이안나와서 그냥 nextjs의 standalone 빌드 결과물인 server.js를 까보기로 했다.
//docker container 내부 접속
docker exec -it clinet-myeonjeobeottae /bin/sh
// server.js 내부 확인
cat server.js
server.js 내부를 보자마자 currentPort라는 단어가 눈을 사로잡았다. 그래서 검색해보니 다음과 같은 부분이 나왔다.
바로 process.env.PORT로 nextjs app을 실행하고 있었던 것!
보자마자 왜 앱이 500 internal Server Error를 내뿜었는지 알것 같았다.
const currentPort = parseInt(process.env.PORT, 10) || 3000
→ server.js는 process.envPORT로 지정된 환경변수를 가져와서 currentPort에 할당하고 해당 포트로 앱을 서빙한다. 환경변수가 없다면 기본으로 3000 port로 서빙한다. 그런데 우리의 dockerfile.yml에는 ENV가 없다! 그러므로 앱은 3000port로 서빙되고, nginx가 3001로 reverse-proxying하기 때문에 port가 달라 에러가 발생하는 것이다.
원인은.. 나..
사실.. Nextjs 깃허브에서 참고한 dockerfile.yml에서 원래 해당 ENV 포트 부분이 있었다..!
그치만 server.js의 작동 방식을 모르고 필요없다고 생각한 난 지워버렸던 것이다..
좀 돌아가긴 했지만 어쨌든 문제는 해결될 것 같았다. 깔끔하게 해당 부분을 찾아냈으니.
?????? 그래도 안된다!!
dockerfile.yml에서 ENV PORT 3001 설정을 해주고 한결 가벼워진 마음으로 container를 다시 빌드했다. 그런데 에러는 죽지않고 계속 살아남았다..! 무조건 해결될 줄 알았던지라 카운터 어택을 맞은 느낌이였다. 그래서 이번엔 열심히 구글링을 해보기로했다.
그랬더니 Next.js 깃헙 이슈에 나와같은 500가 발생한다는 글이 이미 올라와 있었다.
역시 이미 형님들께서 먼저 겪고 계셨다.. 답글들을 보니 Next.js 13.4.13 버전에서 해당 문제가 발생했고, 정확하게 [면접어때]의 Next.js 버전도 13.4.13이였다! 그런데 아직 마땅한 해결책은 없고, 13.4.12 버전으로 다운그레이드하는 수 밖에 없다고 한다.
어쩔수 없이 13.4.12 버전으로 다운그레이드 하고 재배포 해보니 더 이상 500 Error가 발생하지 않았다!
+ Next.js 13.4.19 최신 버전에서 해당 Error가 해결됬다고 한다.
에러를 해결하고 나서
패키지 버전때문에 Error를 겪었던 적이 지금까지 별로 없어서 그런지, 해당 문제를 해결 하기까지 시간이 더 걸렸던 것 같다.
배포는 항상 할 때 마다 어려운 것 같지만 그래도 에러를 해결해나가면서 조금씩 자신감이 붙는 느낌이다!
'FRONTEND > 백만가지 ERROR' 카테고리의 다른 글
EC2 - Nginx-proxy-manager 폴더 permission denied (0) | 2024.01.30 |
---|---|
[Jest] react-query + recoil 적용시 에러 (0) | 2023.07.06 |
yarn create next-app 설치 안됨 (0) | 2023.06.28 |