시작하기
최근 꽤 흥미로운 이슈 하나가 프론트엔드에 나타났다. 바로 빌드된 Docker 이미지의 재사용에 관한 이야기였다. 현재 프로젝트들은 여러 개발 단계를 거쳐 배포로 이어지는데, 이 단계마다 이미지를 빌드하고 사용하는 방식으로 활용되고 있었다. 생각해보면 참 이상한 일이다. Docker image를 빌드하는 이유 중 하나는, 애초에 같은 이미지를 재사용하여 여러 컨테이너로 실행시킬 수 있다는 부분이다. 그래. 재사용. 이 핵심 기능에 대하여 지금 제대로 활용되고 있는가에 대해 생각해본다면, 당연히 아니오였다. 우리는 매번 새로운 빌드로 만들어진 이미지를 배포하고 있었고, 무언가 거대한 변경사항이 있는 것이 아닌, 주입되는 환경변수 몇 글자를 바꾸기 위해 빌드를 위한 리소스와 빌드 시간을 낭비하고 있었다. 분명 개선이 필요한 부분이라는 점은 분명하다.
파고들기
우리가 해결해야 하는 부분은 단순하다. 빌드 타임에 환경변수를 사용하는 것이 아닌, runtime에 환경변수를 추가하는 방법을 통해 배포 환경에 따라 서로 다른 환경변수를 사용할 수 있게 하는 것이다. 도커에서는 ENV를 통해 런타임에 환경변수를 주입할 수 있다. 그렇다면 이 환경변수를 runtime에 next14에서도 사용할 수 있어야 한다는 것인데, 도커 container runtime에 next14가 이 환경변수를 받을 수 있을까?
한번 next14 app router의 runtime에서 실제 환경변수를 받아오는지에 대해 가볍게 테스트를 해보자.
Next14 + app router + SSR
Next14에 대해 뜯어볼 때 마다 사용하는 만능 샘플 프로젝트, next-trello 레포지토리를 다시 불러와봤다. 기본적으로 app router는 'use client'가 명시되어 있지 않는다면 자동으로 SSR 방식으로 랜더링된다. 한번 runtime에 직접 환경변수를 넣을 경우 정상적으로 받아내는지 확인해보도록 하겠다.
<h1>{process.env.TEST_ENV}</h1>
간단하게 위와 같은 태그를 page.tsx에 두고 한번 yarn start를 하면서 환경변수 TEST_ENV를 넘겨보겠다.
TEST_ENV=HelloWorld npm run build
TEST_ENV=HelloWorld npm run start
위와 같이 build 시에 환경변수를 넘겨 함께 빌드를 수행하고 start를 진행하면 정상적으로 나타나는 것을 볼 수 있다. 하지만 그냥 build만 하고 start 때 환경변수를 넘겨본다면 어떻게 될까?
npm run build
TEST_ENV=HelloWorld npm run start
음. 환경변수를 build 때 넘기지 않고 start 때 넘기게 되면 제대로 읽어내지 못한다. 이유는 환경변수가 next 빌드 시점에 캐시되어 .next에 포함되어버리기 때문이다. 하지만 우리는 build 시점이 아닌 start에서 환경변수를 설정하고 싶다. 우리의 목적은 어디까지나 빌드된 이미지에 서로 다른 환경변수를 주입하여 재사용 하는 것에 있기 때문이다.
Next.js 14의 고질적인 문제
위에서 말했다시피, next14에서의 start는 빌드된 .next 디렉토리를 기반으로 실행되기 때문에 반드시 npm run build와 같은 단계가 먼저 이뤄져야 한다. 때문에 빌드 시점에 들어간 환경변수에 대해서는 제아무리 런타임에 환경변수를 주입하려 해도 변하지 않는다. 특히 SSG 형태로 output:export로 static HTML 형태, 혹은 standalone의 경우에는 동적으로 가져올 방법이 없다. 하지만 그나마 SSR과 CSR로 랜더링되는 환경에 대해서는 어떻게든 build시점과 페이지가 랜더링되는 시점 사이에서 환경변수를 주입할 수 있는 방법을 찾을 수 있었다.
Server Side Rendering일 경우
다행스럽게도 app router에서 runtime에 주입된 환경변수에 대해 접근할 수 있도록 하는 라이브러리가 지원되고 있다. 바로 next-runtime-env라는 라이브러리이다. 기존에 next에서 이미 runtime에 환경변수를 사용할 수 있도록 지원한다고는 하지만, 공식 docs에서는 그다지 추천하지 않기도 하고, 오버헤드가 발생할 수 있다고 언급되기도 하여 라이브러리를 사용하는 쪽으로 진행해볼 예정이다.
Client Side Rendering
이에 대해 여러 블로그들을 참고해 본 결과, 카카오에서 관련하여 자세한 설명을 남겨두었다. 바로 환경변수 URL 방식을 이용하는 것이다. 이 것을 한번 따라보자. 물론 코드가 누락된 부분도 많고, 전체적인 흐름에 대해서만 다루다 보니, 자체적으로 누락된 부분에 대해 내용을 채워가며 동작하게 만든 부분들에 대해 정리해볼 예정이다.
https://fe-developers.kakaoent.com/2021/211125-create-12factor-app-with-nextjs/
https://fe-developers.kakaoent.com/2022/220505-runtime-environment/
위의 두 가지 방법을 적절하게 섞어 Client Side와 Server side에서 모두 잘 동작할 수 있도록 한 코드를 바탕으로 도커에서 develop와 production마다 다른 결과를 볼 수 있도록 해보겠다.
'개발 > 스터디' 카테고리의 다른 글
Grafana와 Prometheus (0) | 2024.10.01 |
---|---|
AWS 용어를 알아보자 (4) | 2024.09.28 |
Docker+Jenkins 동작 방식 (0) | 2024.08.11 |
Docker와 Standalone (0) | 2024.08.10 |
AWS EC2와 ECS 그리고 Docker (0) | 2024.07.29 |