우테코 레벨3 프로젝트에서, 프론트엔드 인프라 구성은 팀원인 에디가 담당하여 진행하였습니다. 그러던 중, 팀 회의에서 에디 이외의 구성원이 프론트엔드 인프라에 대한 문서화를 맡아 해당 내용을 학습하면 전반적인 프로젝트 이해에 도움이 될 것이라는 의견이 나왔습니다. 이에 따라, 저희 팀 프론트엔드 인프라에 대해 알아보고 구성도를 그려보면서 학습한 내용을 정리해보았습니다.
Merge
가 되면 Webhook이 동작하여 zipgo-infra
서버의 젠킨스의 파이프라인이 실행됩니다.frontend
디렉토리 내의 파일들을 사용하여 도커 이미지를 빌드합니다.zipgo-prod
서버에서 도커 이미지를 pull
받은 후 도커 컨테이너를 생성합니다.docker run
)할 때 호스트 서버의 3000포트
와 컨테이너 내부의 3000포트
를 바인딩하여 호스트 서버의 3000포트
로 들어오는 요청이 컨테이너의 3000포트
로 전달되도록 합니다.deleteDir
메서드를 통해 이전 빌드의 잔여 데이터나 파일을 제거합니다.2023-zipgo
깃허브 레포지토리 develop
브랜치를 복사해옵니다.npm i -g yarn
: Yarn 패키지 매니저를 설치합니다.cd frontend && yarn
: frontend
디렉토리로 이동한 후 yarn
명령어를 실행하여 프로젝트에 필요한 패키지를 설치합니다.docker build -t [이미지 이름]:[빌드 번호] ./frontend
:docker build
명령어를 통해 도커 이미지를 만듭니다.-t
옵션으로 [이미지 이름]:[빌드 번호]
형식으로 도커 이미지의 태그를 설정합니다../frontend
: frontend
디렉토리를 도커 컨텍스트 경로로 설정하여 이 디렉토리 내의 파일들을 사용하여 이미지를 빌드합니다.[이미지 이름]:latest
태그를 가진 도커 이미지를 Docker Hub에 업로드합니다.docker rmi
: 원격 서버에서 기존 도커 이미지를 삭제합니다.docker stop
: 원격 서버에서 실행되고 있는 기존 컨테이너를 중지합니다.docker rm
: 원격 서버에서 기존 컨테이너를 삭제합니다.docker pull
: 도커 허브에서 도커 이미지를 가져옵니다.docker run -d -p 3000:3000 --name $CONTAINER_NAME $IMAGE_NAME:latest
docker run
: 도커 컨테이너를 생성합니다.-d
: 컨테이너를 백그라운드 모드로 실행하는 옵션입니다.-p 3000:3000
: 호스트 서버의 3000포트와 컨테이너 내부의 3000포트를 매핑하는 옵션으로 이를 통해 호스트 서버의 3000포트로 들어오는 요청이 컨테이너의 3000포트로 전달됩니다.—name
: 컨테이너에 이름을 지정하는 옵션입니다.$IMAGE_NAME:latest
: 해당 이미지를 사용하여 도커 컨테이너를 생성합니다.클라이언트가 서버로 요청할 때 직접 요청하지 않고 먼저 프록시 서버를 통해 요청하는 방식입니다. 서버에게 클라이언트가 누구인지 감추는 역할을 합니다. 서버가 응답받은 IP는 포워드 프록시 서버의 IP이기 때문에 클라이언트가 누군지 알 수 없습니다.
클라이언트가 서버를 호출할 때 리버스 프록시 서버를 호출하게 되고 프록시 서버가 서버에 요청하여 받은 응답을 클라이언트에게 전달하는 방식입니다. 리버스 프록시는 서버가 누구인지 감추는 역할을 합니다. 클라이언트는 리버스 프록시 서버를 먼저 호출하게 되기 때문에 실제 서버의 IP를 알 수 없습니다.
클라이언트와 서버 사이에 위치한 Nginx는 api.zipgo.pet
과 같은 특정 경로로 요청이 왔을 때 실제 백엔드 서버(8080포트
)로 요청을 전달하고 응답을 클라이언트에게 반환하는 역할을 하는 Reverse Proxy 서버로 활용합니다.
React의 프로덕션 빌드를 생성하면 정적 파일 (HTML, CSS, JavaScript 등)이 생성됩니다. 이때 브라우저에서 액세스할 수 있는 하나의 Index.html만 사용하게 됩니다. 그래서 특정 경로에서 새로고침을 했을 경우 서버가 해당 파일을 찾을 수 없어 404에러메시지를 사용자에게 반환하게 되는 문제가 있습니다.
이를 해결하기 위해 React 웹을 경량 웹 서버인 Nginx를 통하여 실행되도록 만들었습니다.
즉, 위 인프라 구성도에서 도커 컨테이너 내부의 Nginx는 클라이언트로부터 요청을 받았을 때 요청에 맞는 정적 파일을 응답해 주는 HTTP Web Server로 활용합니다.
nginx.conf
: nginx의 기본 설정 파일로 워커 프로세스 설정 또는 로그 저장 위치 등을 작성할 수 있고 다른 server 설정들을 불러오는 역할을 합니다.[파일명].conf
: nginx를 통해 구동되는 서버의 설정 값을 작성한 후 /etc/nginx/conf.d
경로에 [파일명].conf
라고 저장하면 nginx.conf
에서 해당 파일을 import
하여 적용합니다.https://zipgo.pet
이 이에 해당합니다.)https://zipgo.pet/storybook
이 location 라우팅에 해당합니다.)# /etc/nginx/conf.d/default.conf in Docerk Container
server {
listen 3000;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri /index.html;
}
location /storybook {
alias /usr/share/nginx/html/storybook;
index index.html
try_files $uri /index.html;
}
}
listen 3000
: 3000포트로 들어오는 요청을 해당 server{}
블록의 내용에 맞게 처리합니다.location /
: /
로 접속했을 경우 /usr/share/nginx/html/index.html
을 보여줍니다.location /storybook
: /storybook
으로 접속했을 경우 /usr/share/nginx/html/storybook/index.html
을 보여줍니다.try_files $uri /index.html;
: nginx가 해당 경로의 정적 파일을 찾아보고 없으면 index.html을 반환하도록 구성합니다. 이후에는 React Router가 해당 경로를 처리하고 해당 페이지를 표시할 수 있게 됩니다.try_files $uri $uri/ /index.html;
로 설정한 경우,
글 잘 보았습니다~ 저희 프로젝트랑 인프라가 비슷하여 복습할 수 있었어요