STUDY/Web

배포 자동화 (2) 백엔드, 프론트엔드 도커 이미지 빌드

sinawi95 2021. 10. 8. 17:44
728x90

(1) Docker 설치 및 Jenkins 설정

(2) 백엔드, 프론트 엔드 도커 이미지 빌드

(3) 원격 서버에서 도커 이미지 실행: Jenkins 파이프라인 작성

(4) HTTPS 적용 및 Nginx 설정 : letsencrypt와 certbot을 사용한 SSL 인증서 설치, 리버스 프록시 적용


지난 포스팅에서 배포 자동화를 한다고 이야기 했고 자동화를 위해 도커와 젠킨스를 설치했다.

이번 포스팅은 각각의 부분을 도커 이미지로 만들고 실행하는 것을 목표로한다.

프로젝트에서 프론트엔드는 Vue의 빌드 파일과 Nginx를, 백엔드는 Express.js를 사용한다.

 

1. Docker + Node.js(Express)

우선 백엔드 서버를 도커 이미지를 만들어보자

node와 npm이 설치 되어있는 상태에서 bash창을 열고 Express generator로 간단한 프로젝트 파일을 생성한다. (이미 프로젝트가 있으면 넘어가도 된다.)

$ npm install -g express-generator # 설치
$ express server # 프로젝트 생성
$ cd server 
$ npm install # 프로젝트 패키지 설치
$ npm start # 프로젝트 실행

프로젝트 실행 이후 localhost:3000에 접속했을 때 welcome to express라는 페이지가 보이면 된다.

다음 단계는 Docker 이미지를 생성하기 위한 준비이다.

생성한 프로젝트의 최상위 폴더(<저장된 주소>/server )에 Dockerfile이라는 이름으로 확장자 없이 파일을 생성한다. 이미지를 만들 때 사용하는 파일이다. 주의할 점은 첫글자는 대문자여야한다.

FROM node:14          # node 14 버전을 사용해서 이미지 생성
WORKDIR <저장된 주소>/server  # 컨테이너 작업공간 위치

COPY package*.json ./  # 호스트 계정에 있는 package.json, package-lock.json 파일을 컨테이너 작업 공간에 복사
RUN npm install # 앱 의존성 설치

COPY . . # 호스트 계정에 있는 소스파일 전체를 컨테이너로 복사

EXPOSE 3000 # binding port 3000

CMD ["npm", "start"] # 서버 실행

이미지를 만드는 순서를 보면 위에서 서버를 실행하는 것과 똑같다. 중간중간에 컨테이너에 복사해주는것을 제외하면 npm install 하고 포트 열고 서버를 실행한다.

같은 위치에 .dockerignore 도 생성한다. 이미지를 만들때 포함하지 않아야 할 것을 작성하면 된다.

node_modules
npm-debug.log

Dockerfile을 만들었으면 이미지를 빌드 해보자. 다음 명령어를 사용하면 된다.

$ docker build -f Dockerfile -t node_server .

여기에 두개의 옵션이 들어간다. -f는 도커이미지를 빌드할 때 사용할 파일을 지정한다. 여기에선 생략 가능하다. -t는 이미지에 태그를 추가한다. 이미지에 고유값들이 저장되지만 꽤 길어서 별명을 사용한다고 생각하면 된다.

만들어진 이미지는 $ docker images 를 사용해서 쉽게 찾을 수 있다.

이미지 빌드까지 했으니 실행만 남았다. 다음 명령어를 실행하자

$ docker run -it -d --rm \\
-p 3000:3000 --name backend_server \\
 node_server

명령어의 기본 형식은 이렇다.docker run [OPTIONS] IMAGE [COMMAND] [ARG...] .

작성한 옵션을 한번 살펴보자.

-it는 두 개의 옵션이 합쳐져있는 형태이다. -i는 Bash에 명령을 입력하기 위해 사용하고 -t는 Bash를 사용하기 위해 사용한다. 두개의 옵션은 보통 같이 사용된다.

-d는 컨테이너를 백그라운드로 실행시킨다. 이 옵션도 한번에 작성해도 된다.( -itd )

--rm는 컨테이너가 중지되면 자동으로 삭제한다. 우리는 자동 통합, 자동 배포를 할거니까 자주 배포 될수 있으니 이 옵션을 켜서 중지할때마다 삭제하자

-p는 호스트의 포트와 컨테이너 내부의 포트를 포워딩한다. 외부 포트는 호스트에서 겹치지 않는 포트를 사용하고 내부 포트는 Dockerfile에 바인딩한 포트로 사용한다.

옵션들은 사용하는 기본 형식에 맞게 작성해야한다. 이미지 뒤쪽에 작성하면 커맨드로 인식하여 옵션이 안들어갈수 있으니 주의해야한다.

여기까지 진행하고 http://localhost:3000으로 접속했을 때 welcome to express가 보이면 된다.

aws 환경이면 접속해서 curl 명령어로 확인할수 있다. curl -X GET http://localhost:3000

2. Docker + Nginx (Vue project)

백엔드를 컨테이너로 만들었으니 프론트엔드도 컨테이너로 실행해보자. 프론트엔드도 백엔드처럼 직접 실행할수 있지만 Vue는 SPA이므로 정적파일로 만들어서 Nginx가 제공하는 방식으로 만들 것이다.

Nginx는 공식 이미지를 가져온다.

$ docker pull nginx

그리고 vue 프로젝트 생성하자. 얘도 마찬가지로 기존 프로젝트가 있으면 넘어가자

$ npm install -g @vue/cli
$ vue create client
Preset: Default [Vue 2] babel, eslint
Package manager : NPM

$ npm run serve

npm run serve 이후 localhost:8080 으로 접속했을때 vue 로고가 뜨면 된다.

Client 디렉토리에 Dockerfile 생성하자

FROM node:14 as build-stage 
WORKDIR <저장한 주소>/client

COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx:stable-alpine as production-stage
COPY --from=build-stage ./dist /usr/share/nginx/html
EXPOSE 80

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

백엔드의 도커파일이랑 크게 다른점은 7번째 줄부터이다.

npm run build 명령어를 사용하면 전체 프로젝트가 dist 폴더에 정적 파일로 만들어진다. 이 파일을 컨테이너에 옮기고 Nginx를 백그라운드로 실행하게 한다.

이미지를 빌드하고 실행한뒤 http://localhost에 접속하면 npm run serve와 같은 페이지가 보이면 된다.

$ docker build -f Dockerfile -t vue_client .
$ docker run -itd --rm \\
--name vue-client -p 80:80 \\
vue_client

지금까지 도커 이미지를 만들고 컨테이너를 실행시켜 백엔드와 프론트엔드를 확인할수 있었다. 여기까지 진행하는 과정이 어렵진 않아도 시간이 걸리는 작업이라고 생각한다. 배포를 할때마다 해당 작업을 직접 하게 된다면 시간이 많이 낭비될 것이므로 처음 한번만 고생해서 자동화 시켜면 효율이 높아지지 않을까?

다음 포스팅에서 jenkins를 사용해서 자동 배포를 진행해보자.


참고한 글
https://vuejs.org/v2/cookbook/dockerize-vuejs-app.html#Simple-Example
https://waspro.tistory.com/671
https://kdeon.tistory.com/6
https://kinggrmoon.tistory.com/45
https://velog.io/@co323co/Node.js-Express-프레임워크-공부
https://www.daleseo.com/docker-nodejs/
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=pjt3591oo&logNo=222010156379
https://nodejs.org/ko/docs/guides/nodejs-docker-webapp/