multi-stage build React

wangjh789·2022년 8월 27일
0

docker

목록 보기
25/25

리액트의 npm start 는 개발용 명령어이다.
npm start를 입력하면 노드가 자체 개발용 웹서버를 띄워 라이브 리로딩이 가능케 한다.

npm start를 사용하면 자체 웹서버를 제공해 라이브 리로딩이 가능하지만 최적화와는 거리가 멀어 배포환경에는 적절하지 못하다.

리액트를 배포하기 위해 필요한 것은 npm run build 명령어 이다. (최종 제공 가능한 파일은 build폴더에 저장된다.)
이 명령어를 입력하면 최적화된 코드를 생성한다. 하지만 그 코드를 공급하기 위한 웹 서버는 제공하지 않는다. 그렇기 때문에 배포를 위해선 코드를 공급해줄 새로운 웹 서버가 필요하다.
(사실 npm run build 이후 node는 불필요 하다.)

이를 해결하기 위해 Dockerfile의 multi-stage build를 이용한다.
(도커파일의 베이스 이미지는 하나만 존재해야 한다. 만약 새로운 FROM 절이 수행되면 이전 단계는 무시되고 새로운 단계를 만든다.)
1. 코드를 가져오고 종속성을 설치해 빌드하는 단계
2. 최종빌드된 코드를 제공하는 웹서버를 수행하는 단계

FROM node:14-alpine as build

WORKDIR /app

COPY package.json .

RUN npm install

COPY . .

RUN npm run build

FROM nginx:stable-alpine 

COPY --from=build /app/build /usr/share/nginx/html

EXPOSE 80

CMD ["nginx","-g","daemon off;"]

/usr/share/nginx/html는 nginx가 정적 콘텐츠를 제공하려고 시도하는 디폴트 폴더이다.
첫번째 스테이지의 최종결과의 /app/build 의 내용을 /usr/share/nginx/html 로 복사한다.

다음 변경해야 할 것은 리액트 코드중에 백엔드 서버로 요청하는 url 이다. http://localhost/goals
(이 url은 개발환경에선 잘 동작한다. 프론트 컨테이너-> 로컬머신 -> 백엔드 컨테이너 로 비효율적이지만..)
배포를 위해 프론트엔드 컨테이너도 백엔드 컨테이너와 동일한 태스크에 넣을 예정이다.
이전에 동일한 태스크에서 실행되는 컨테이너들은 localhost로 통신할 수 있다고 배웠다.(동작한다고 예상했음)
하지만 이는 코드가 컨테이너 내부의 서버에서 실행되는 경우에만 해당된다.
리액트는 브라우저에서 실행된다. 그렇기 때문에 백엔드 컨테이너로의 요청은 컨테이너 내부에서 전송되는 것이 아니라 브라우저에서 요청되기 때문에 그대로 localhost로 요청된다.

await fetch('/goals');
웹브라우저는 도메인을 생략하면 디폴트로 웹사이트를 제공한 곳과 동일한 서버로 요청을 전송한다.

만약 백엔드와 프론트엔드 가 동일한 포트를 사용하고 있으면?
한 태스크, 즉 하나의 호스트에서 동일 포트를 사용하는 다중 컨테이너는 불가능하다. 그렇기 때문에 새로운 태스크를 만든다. 하지만 그렇게 되면 백엔드와 프론트엔드의 도메인이 삭제되어 goals/ 사용이 불가능하게 된다.

그렇다고 컨터이너 내부에서 코드가 실행되지 않기 때문에 docker env를 이용할 수도 없다. ${process.env.XXX} 가 그대로 브라우저로 나간다.
다행히 리액트에서 npm start 일땐 process.env.NODE_ENV=development, npm run build 일땐 process.env.NODE_ENV=production 으로 변수가 지정된다.

const baseUrl = process.env==='development'?"http://localhost":<백엔드 로드밸런서의 DNS name>;
profile
기록

0개의 댓글