들어가며
기존에서는 Amplify 또는 vercel로만 배포, 빌드해서 도메인과 관련된 이슈만 해결하면 별다른 이상 없이 배포를 할 수가 있었습니다.
(이게 바로 툴이지!!)
근데 이번에 도커이미지를 직접 생성하여 배포를 해야 하는 상황이라 해당 업무를 진행하면서 삽질했던 간단 경험을 적어보겠습니다.
Next Docker 배포
next 프로젝트를 배포하는 가장 쉬운 방법은 vercel를 이용하는 겁니다.
거의 제로 config에 걸맞는 조합을 자랑하고 (실은 같은 회사인) 공식 문서상에서도 vercel을 이용하라고 조언해줍니다.
근데 개발자 인생 뭐 제가 원하는 스택을 모조리 가져다 쓸 수는 없죠.
그래서 DockerImage 파일을 만들어서 스크립트 수정하고 빌드 프로세스를 만들었죠.
네 다 터집니다..
아 일단 DockerFile 스크립트의 경우 공식레포에서 지원해주는 걸 사용하면 됩니다.
DockerFile 코드
https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
코드 상으로 살펴볼 점이 몇개 정도 있는데
첫 번째로 node:16-alpine을 쓴다는 것입니다.
아직까진 node18 대신에 많이 안정화된 16을 쓰고 용량이 경량화된 alpine을 쓴다는 건 딱 적절한 노드 버전인듯합니다.
두 번째로는 중간에 standalone과 관련된 설정이 보입니다.
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
일반적인 프로젝트에선 standalone를 설정할 일이 없었는데 docker에 던지려면 해당 설정이 필요하다고 합니다.
그리고 그 설정은 next.config.js에서 하면 됩니다.
// next.config.js
module.exports = {
output: 'standalone',
}
실제론 이 구성이 끝입니다. 간단하죠?
package.json과 환경변수
그리고 확인해야 할 부분이 바로 package.json의 스크립트입니다.
대부분의 프로젝트는 개발용, 테스트용, 배포용 이렇게 이뤄집니다.
그리고 그에 따라 환경변수를 나눠놓죠.
그래서 개발할 때 dot env든 cross env는 적절한 환경변수를 먹여서 상황에 맞게 구현을 하고 개발을 합니다.
근데 이게 next dev일 때는 상관이 없는데
next build일 때는. env.production을 강제로 가져가 버리는 문제가 있습니다.
build는 build인 거고 나는 dev모드로 빌드해서 배포한 다음 테스트하고 싶은데 무조건. env.production를 가져가 버리면.. 어떻게 환경변수 주냐..?
이에 대한 해결책으로 여러 가지 방법이 보입니다.
카카오의 경우 별도의 환경변수 주입 스크립트를 통해 이미지를 만들기 전에 세팅을 끝내 놓던데.. 당장 배포가 시급한 저에겐 저런 리소스를 투입할 여력이 없었습니다.
그래서 어떻게 했나?
바로 DockerFile에서 dev 모드일 때. env.develoment를 production을 덮어버리는 전략을 가지게 됩니다.
# DockerFile 중
RUN cp /app/.env.development /app/.env.production
다행히 현재 배포 정책상 각각의 계에 맞춰 dockerfile이 분리되어 있기에 dev에만 해당 코드를 추가하여 잘 배포하고 있습니다.
다시 터지는 이유로 돌아와서
Next Docker 배포 에러 찾기
위에서 보셨다시피 수많은 failed와 함께 멘털도 서서히 failed를 향해 가고 있었습니다.
집단지성의 힘
이제 집단지성의 힘을 빌리기로 합니다.
결국 원인을 근본적으로 딱 찾지 못하고 원론적인 해결책을 제시해주셨습니다.
저도 잠깐 고민을 해보니 계속 안 되는 코드 되게 하려고 붙잡지 말고 되는 코드에서 설정을 추가해보면서 어떤 코드와 설정이 빌드를 실패하게 하는가 찾아가는 방식이 훨씬 빠를듯해 보였습니다.
그에 따라 위에서 확인했던 next의 dockerFile용 레포를 가지고 와서 하나씩 설정을 추가해보고 있었습니다.
팀장님 등판
오전 회의 때 팀장님께 한두 시간이면 배포까지 된다고 호언장담을 했지만 이미 점심을 먹고 3시를 향해가고 있었기에,
바로 보고를 하러 갑니다.
나 : 팀장님 배포가 바로 안 되는데요. 시간 좀 더 주십시오
팀장님 : ㅋㅋㅋㅋㅋㅋㅋ 한두 시간이면 된다며? 뭐가 문제인데 같이 봐보자.
나 : 이러저러쿵 문제가 있는데 정확히 뭔지는 모르겠고 ₩!~!~!~!~!~
팀장님 : OO 일단 하고 있어 봐 나도 따로 코드 살펴볼게
--- 대화 마무리 ---
그리고 코드를 다시 추가하고 있는데 갑자기 쓰윽 제자리로 다가오신 팀장님
팀장님 : 핸디야~ 파일 디렉토리명이 이상한 거 같다. 이거 맞냐?
나 :??? 그게 무슨 말이에요 파일 디렉터리랑 뭔 상관
팀장님 : 빌드 에러 나는 button import 부분 말이다.
팀장님 : git상에서 확인해보니깐 button의 디렉토리명에서 Button인데 로컬에선 내부 코드상으로 button이다
나 :?????????? 나니 뮈시여?
원인(대소문자) 수정
이런 ㅅㅂ....
button 컴포넌트... 실은 빌드 에러상에서 버튼 컴포넌트가 문제라고 이미 알려줬었습니다.
근데 내가 이게 button 컴포넌트의 경로 또는 자체 문제라기 보단 환경적인 문제라고 판단했던 이유는
import order 옵션으로 인해 Button을 가져오는 모든 파일에서 Button이 바로 최상단에 있었기 때문입니다.
그리고 많은 페이지들이 button를 쓰고 있었기에 webpack이 번들링 하다가 특정 순서에 의해 에러를 내뱉다가 터진 거라고 생각했었습니다.
근데 이게 파일 디렉터리의 대소문자의 문제라니..
원인 방지
원인을 방지하기 위한 추가 절차를 도입했습니다.
컨벤션 지키기
컨벤션을 제대로 지키기는 기본입니다.
그래서 실은 저 파일의 디렉터리도 원래는 button이어야 하는데 button 컴포넌트가 하위로 분리되면서 중간 경로가 되었고 코드를 변경했는데 Git 상에서 인식을 못해서 발생한 사건이었습니다.
그래도 근본적인 컨벤션 지키기는 이뤄져야 합니다.
이번 사태처럼 git은 발견하지 못했더라고 컨벤션을 공유한 팀장님이 경로상에 이상함을 인지했으니 발견할 수 있었지요.
git 교육시키기
git 놈은 태생적으로 대소문자를 무시하는 오만한 기질을 가지고 있습니다.
그래서 이걸 예민하게 반응하라는 옵션을 통해 다음부터는 git에 이러한 정보가 반영이 안 되는 걸 막는 과정이 필요합니다.
이에 대한 설정은 다른 분이 잘 정리된 글이 있어 갈음합니다.
git mv 명령어 사용
이 글을 공유했더니 멋진 개발자님께서 하나의 링크를 추천해주셨습니다.
일반적으로 git 프로젝트의 파일명을 변경하기 위해선 아래 코드를 통해 변경하라고 조언합니다.
git mv foo.js temporary-name
git mv temporary-name Foo.js
마치며
오늘 하루의 내용을 한 줄 기사로 정리하자면 다음과 같습니다.
[속보] 배포 한 시간이면 돼요!!.. 오만으로 밝혀져..
마이그레이션 작업이라 스크립트도 전부다 작성했는데 돌아가지 않아 많던 식욕도 사라졌지만,
그래도 원인을 찾고 해결했고 그리고 다음 에러를 방지하기 위한 설정과 사내공유까지 완료했습니다.
"아무래도 하루 정도는 걸리겠지"라는 팀원들의 경험 섞인 말에
"아 금방 됨요!!"라고 했던 나의 오만함을 반성하게 되는 하루였습니다.
끝.
댓글