본문 바로가기
도커/개발자를 위한 쉬운 도커

5.5 컨테이너 애플리케이션 구성: vue.js 프론트엔드 컨테이너

by limdae94 2024. 7. 23.
 

개발자를 위한 쉬운 도커 강의 | 데브위키 - 인프런

데브위키 | 현업 개발자가 도커를 사용한 경험을 녹여낸 새로운 커리큘럼으로 기존 교재 및 강의와 차별된 강의를 제공합니다. 단순한 명령어 사용법이 아닌 도커를 왜 사용해야하는지 대한 근

www.inflearn.com

 

1. 프론트엔드 컨테이너 생성하기

프론트엔드 빌드 프로세스

이번 파트에서는 leafy 프론트엔드 이미지를 빌드한다. leafy 애플리케이션은 Vue.js로 개발된 프론트엔드 애플리케이션이다. 어떤 프레임워크를 사용하던 간에 프론트엔드 소스 코드는 HTML, JavaScript, CSS와 같은 파일들로 결과물을 빌드할 수 있다. 빌드한 파일들은 루트 디렉토리(./)dist라는 폴더에 만들어진다. 이 파일들을 nginx와 같은 웹서버의 특정 경로에 업로드하면 클라이언트가 브라우저를 통해서 웹서버에 접속했을 때 개발자가 개발한 웹페이지를 응답할 수 있다.

 

프론트엔드 Vue.js 프로세스 구성

이제 프론트엔드 이미지를 빌드하는 과정을 정리한다. 먼저 OS에 nginx 웹서버가 설치되어 있어야 한다. 그리고 소스코드를 빌드하기 위해서 Node.js와 npm이 설치되어 있어야 한다. 그리고 소스코드를 git 클론으로 다운로드 받는다. 이 소스코드가 참조하는 외부 라이브러리들을 다운받아야 한다. 이 외부 라이브러리를 설치하는 명령은 npm ci 명령으로 다운로드 받을 수 있습니다. 그리고 이제 소스코드를 빌드하는 명령어는 npm run build 명령이다. npm run build 명령을 사용하면 dist라는 폴더에 결과 파일들이 만들어진다. 이 파일들을 우리가 nginx에서 많이 사용했었던 폴더인 /user/share/nginx/html 폴더로 복사하면 된다. 그리고 nginx 웹서버를 실행시키면 정상적으로 프론트엔드 컨테이너를 빌드할 수 있다. 마찬가지로 프론트엔드 애플리케이션도 멀티스테이징 빌드 기술을 활용해서 불필요한 파일 크기를 최소화한다. 빌드 과정에서 생성되는 파일은 웹서버에서는 사용하지 않는 파일들이기 때문에 빌드 과정을 node 14 이미지에서 실행시키고, 결과 파일인 dist 디렉터리만 실행 이미지인 nginx로 복사해오면 이제 nginx에 접속했을 때 사용자의 애플리케이션 페이지를 응답한다.

 

이재 VScode를 열어주자. leafy 프론트엔드 폴더로 이동한다. 이 src 폴더 안에는 실제로 개발된 애플리케이션 소스들이 들어 있다. 그리고 루트 경로에는 Dockerfile과 package.json 파일이 있다.

 

package.json 파일에는 dependencies 쪽에 이 소스 코드가 빌드 되기 위해 필요한 라이브러리 정보들이 있다. 그리고 src 폴더를 열어보면 components, router, views 폴더가 있다.

 

router 폴더 안에 있는 router.js 파일은 어떤 경로로 요청이 왔을 때 어떤 파일을 제공해 줄지를 정의한다. 스프링 부트의 컨트롤러와 비슷한 역할을 수행한다. 이 router.js 파일을 열어보면 이 요청을 처리하는 경로와 전달할 파일을 정의하는 부분이 있다.

 

views, components 폴더에 위치한다. 이 views 폴더 안에 홈페이지.vue 파일을 열어보면 최근 일기라고 표시되어 있는 부분을 확인할 수 있다. 여기에 나오는 데이터가 백엔드 애플리케이션으로 가장 최근 일기 5건을 불러와서 화면에 표시하는 부분이다. for문을 통해서 최근 일기를 출력한다.

 

for문에서 사용하는 logs 부분은 아래로 쭉 내려 보시면 fetchRecentLogs 메서드에서 데이터를 불러오고 있다. 이 데이터를 불러오는 부분에서 백엔드 애플리케이션의 URI를 정의하고 있다. 즉, 여기에 정의된 부분은 홈페이지라는 페이지로 접근했을 때 백엔드 애플리케이션으로 데이터 조회 요청을 보내서 API의 결과로 전달된 응답을 화면에 출력하는 것이다.

 

leafy 애플리케이션에서 제공하는 라우터들은 로그인 페이지와 메인 페이지, 전체 식물 페이지와 식물을 추가하고, 일기를 조회하고, 사용자 설정을 변경하는 페이지들이 router.js에 정의되어 있다.

 

그럼 이제 이미지를 빌드하기 전에 빌드 과정을 관찰한다. 쉘을 두 개 띄워주자. 두 쉘 모두 /leafy-frontend/ 경로로 이동하고 실습을 시작한다.

 

# node.js 임시 컨테이너 실행
docker run -it --name node node:14 bin/bash

첫 번째 셀에서는 docker run 명령을 사용해서 node 컨테이너를 실행시킨다. docker run –it --name 이름은 node로 지정한다. 이미지는 node:14로 지정하고 bin/bash로 실행과 동시에 셀로 접근한다. 정상적으로 실행이 된다.

 

# app 폴더 생성 및 이동 (WORKDIR 지시어와 동일한 효과)
mkdir /app && cd /app

ls

mkdir /app && cd /app으로 폴더를 만들고 만들어진 폴더로 이동한다. 그리고 ls 명령을 사용해서 파일이 없는 걸 확인하자.

 

# leafy-frontend 경로의 모든 파일들 node 컨테이너의 app으로 복사
docker cp . node:app

이제 오른쪽 셀에서 docker cp 명령을 사용해서 현재 폴더에 있는 모든 파일(.)들을 노드 컨테이너의 앱 경로(node:app)로 복사한다.

 

ls

# 의존 라이브러리 다운로드
npm ci

정상적으로 복사를 한다. 그리고 다시 ls 명령을 실행하면 이렇게 소스 코드 파일들이 업로드 된 것을 확인할 수 있다. 그럼 이제 npm ci 명령을 사용해서 의존 라이브러리들을 다운로드 받는다.

 

ls

ls 명령을 다시 입력해 보시면 이렇게 node_modules 폴더가 만들어진 것이 보인다. lsnode_modules 폴더의 내용을 확인해 보면 이 폴더의 라이브러리 파일들이 다운로드 되어 있는 것을 확인할 수 있다. 아직은 애플리케이션이 빌드된 상태는 아니기 때문에 dist 폴더는 존재하지 않는다.

 

# 프론트엔드 애플리케이션 빌드 
npm run build

ls

여기서 애플리케이션 빌드 명령어인 npm run build 명령을 실행하면 이제 결과 파일들을 dist 폴더에서 확인할 수 있다.

 

ls

ls dist

ls 명령을 사용해 보시면 dist 폴더가 만들어져 있다. ls dist를 확인해 보시면 이 안에 css와 자바스크립트, index.html 파일을 확인할 수 있다. 그러면 이 파일들을 nginx로 옮겨야 한다. 먼저 nginx 컨테이너를 실행하기 전에 이 빌드 결과인 dist 파일들을 임시로 옮겨와 보자.

 

# node 컨테이너에서 빌드한 결과물인 app/dist 폴더를 호스트 머신으로 복사
docker cp node:app/dist .

docker cp 명령으로 node 컨테이너에 있는 앱의 dist 폴더(node:app/dist)를 현재 폴더(.)로 복사한다.

 

ls

ls 명령을 확인해 보면 node 이미지에서 빌드한 결과물인 dist 폴더가 호스트 머신으로 복사된 것을 확인할 수 있다.

 

# node 컨테이너 삭제
docker rm -f node

이제 node 컨테이너는 역할을 다 했기 때문에 docker rm 명령을 사용해서 삭제한다.

 

# nginx 컨테이너 실행
docker run -d -p 80:80 --name nginx nginx

그럼 이제 nginx 웹서버를 실행시켜 보자.docker run -d -p 80:80을 지정해 준다. --name에 컨테이너 이름을 nginx로 지정하고 이미지는 nginx를 사용한다. 엔터를 눌러서 컨테이너를 실행시켜 주자.

 

docker ps

docker ps 명령을 사용하면 이렇게 nginx 컨테이너가 정상적으로 실행된 것을 확인할 수 있다. 그러면 이제 node 이미지에서 빌드 결과물로 복사해온 dist 폴더를 방금 실행시킨 nginx 컨테이너로 복사해 보자.

 

# node 컨테이너에서 빌드한 결과물인 dist 폴더를 nginx 컨테이너로 복사
docker cp ./dist/. nginx:usr/share/nginx/html

docker cp ./dist/.으로 이 dist 폴더 안에 있는 파일들을 지정해 주자. 이 실행 중인 nginx 컨테이너의usr/share/nginx/html 경로로 복사해 주자. 정상적으로 복사가 될 것이다.

 

이제 브라우저를 열어 주고 localhost:80로 접속해 주면 이렇게 leafy 로그인 페이지를 확인할 수 있다.

 

docker logs nginx

Docker logs의 nginx로 로그를 확인해 보면 이렇게 로그인 페이지에 대한 요청을 확인할 수 있다.

 

docker rm -f nginx

이제 docker rm 명령을 사용해서 컨테이너를 삭제한다.

 

다음으로 Dockerfile을 작성한다. 마찬가지로 이전 실습에서 작업한 내용들을 떠올려 보면서 도커 파일을 이해하면 이후에 도커 파일을 스스로 작성하실 때도 도움이 될 수 있을 것이다. 다른 애플리케이션과 마찬가지로 루트 경로의 도커 파일을 작성해 준다. 먼저 FROM 지시어를 사용해서 노드 14 버전을 베이스 이미지로 실행시킨다. AS를 통해서 빌드 스테이지라는 것을 명시한다. WORKDIR로 /app을 폴더로 지정하신 다음에 COPY 명령을 사용해서 빌드 컨텍스트의 파일을 /app으로 복사한다. 그리고 이 애플리케이션의 경로에서 npm ci 명령을 사용하면 package.json 폴더의 내용을 참고해서 의존 라이브러리들을 다운로드 받는다. 그리고 npm run build 명령을 실행하면 이 소스 코드를 웹서버에서 사용할 수 있는 dist 폴더로 빌드한다. 그리고 이제 실행 이미지는 nginx:121.4-alpine 이미지를 지정한다. COPY 지시어를 통해서 빌드 스테이지에서 빌드를 통해서 만들어진 /app/dist 폴더를 nginx에서 기본적으로 설정되어 있는 폴더인 /usr/share/nginx/html로 복사한다. 그리고 EXPOSE로 80 포트를 지정한다. ENTRYPOINT"nginx"를 지정하고, CMD"-g", "daemon off;"로 지정하면 된다.

 

cat Dockerfile

그럼 이제 도커 파일을 통해서 프론트엔드 이미지를 빌드한다. cat 명령을 사용해서 도커 파일이 정확하게 작성되어 있는지 확인해 주자.

 

# leafy-frontend 이미지 빌드
docker build -t 레지스트리계정명/leafy-frontend:1.0.0 .

docker build -t에 레지스트리계정에leafy-frontend:1.0.0에 점(.)을 입력해서 이미지를 빌드해 준다.

 

# leafy-frontend 이미지 푸시
docker push 레지스트리계정명/leafy-frontend:1.0.0

정상적으로 이미지가 빌드 되었으면 docker push 명령을 사용해서 이미지를 push해 주면 된다. push가 정상적으로 완료된다. 이제 docker run 명령을 사용해서 프론트엔드 컨테이너를 실행시키자.

 

# leafy-frontend 컨테이너 실행
docker run -d -p 80:80 --name leafy-frontend --network leafy-network 레지스트리계정명/leafy-frontend:1.0.0

docker run -d -p 80:80으로 지정해 주자. 그리고 --name leafy-frontend --network leafy-network 레지스트리계정명/leafy-frontend:1.0.0 이미지를 컨테이너로 실행하자.

 

다시 시크릿 창을 열자. 새롭게 생성한 프론트엔드 컨테이너로 접속한다. 아이디는 john123의 qmail.com으로 지정하고 패스워드는 password123으로 지정한다.

 

이제 정상적으로 로그인이 된 것을 확인할 수 있다. 최근 일기와 식물 리스트가 조회되는 것으로 보아서 백엔드 컨테이너와 데이터베이스 컨테이너까지 정상적으로 동작하고 있다는 것을 확인할 수 있다. 다른 기능들도 정상적으로 동작하고 있다. 다이어리도 추가가 잘 되고 식물도 추가가 되는 것을 확인할 수 있다.

 

이제 leafy 애플리케이션을 성공적으로 구성한다. 각각의 모듈들을 이미지로 빌드해보고 컨테이너로 실행시켰다. 이 처음에 메인 페이지에 접근했을 때의 로직을 확인해 보면 첫 번째로 로그인 후에 클라이언트 브라우저에서 이 프론트엔드 컨테이너의 루트 경로로 접속한다. 그러면 이 프론트엔드 애플리케이션에는 router.js에 루트 경로로 접속했을 때 홈페이지.vue 페이지를 응답하도록 정의되어 있다. 이 홈페이지.vue 페이지에 있는 api.get()에 정의된 URI에 따라서 leafy-backend 애플리케이션에 API 요청이 전달된다. 총 2개의 API 요청이 전달된다. 이 API 요청이 처리되는 과정에서 컨트롤러와 서비스를 통해서 PostgreSQL 서버로 데이터 조회 요청이 전달된다. 실제로 클라이언트가 데이터베이스에 직접 접근할 수는 없다. leafy-backend 애플리케이션을 통해서만 접근할 수 있다. 그래서 leafy-backend 애플리케이션은 최근 식물 다이어리 5건과 사용자의 식물 리스트를 클라이언트의 브라우저로 응답해준다. 이 홈페이지.vue 파일은 브라우저가 백엔드로부터 전달받은 데이터를 모두 포함해서 사용자에게 페이지를 제공해준다. 이렇게 프론트엔드와 백엔드 애플리케이션, 데이터베이스 서버가 유기적으로 상호작용하면서 사용자에게 웹 애플리케이션을 제공할 수 있다.

 

# 실습 컨테이너 삭제
docker rm -f leafy-frontend leafy leafy-postgres

docker rm -f leafy-frontend leafy leafy-postgres로 3개의 컨테이너를 모두 삭제한다. 컨테이너가 잘 삭제된다.

 

이번 파트에서는 실제로 애플리케이션을 컨테 이너로 구성해 보자. 보통 엔터프라이즈 애플리케이션은 이렇게 프론트엔드, 백엔드, 데이터베이스 서버로 구성되어 있다. 어떤 언어로 개발되어 있고 어떤 DB 서버를 사용하냐에 따라서 디테일한 부분은 달라질 수 있지만 기본적인 아키텍처와 빌드 프로세스는 대부분 유사하기 때문에 강의에서 학습한 내용을 활용해서 심의에서도 적용하는 데 도움이 될 수 있을 것이다. 지금까지 실습에서 포트나 URL처럼 네트워크와 관련된 부분은 대부분 설명을 생략하고 진행했다. 다음 파트에서는 이제 이 컨테이너 간의 네트워크 구성과 네트워크 통신에 대해서 학습한다.