①, ②, ③ 편은 배포에 쓰일 준비물을 만드는 시간이었습니다. ④ 편에서는 본격적으로 배포하는 방법에 대해서 알아보도록 하겠습니다.
1. Spring Boot
② 편에서 만든 Spring 애플리케이션을 배포하기 위해서는 Jar를 생성해야 합니다. IntelliJ를 사용하시면 아래 사진처럼 Jar를 편리하게 생성할 수 있습니다.

[우측 상단 Gradle 클릭 > Tasks > build > bootJar 클릭]
위와 같은 프로세스를 진행 후에 build > libs로 가면 "member-0.0.1-SNAPSHOT.jar"가 생성된 것을 알 수 있습니다. 그런데 이름이 너무 길기 때문에 build.gradle에서 다음 구문을 추가한 후에 다시 jar 파일을 생성하도록 하겠습니다.
build.gradle에 다음 구문을 추가합니다.
bootJar {
archiveFileName = 'member.jar'
}
bootJar를 다시 실행해보면 기존에 생성했던 긴 이름의 jar와 설정을 통해 이름을 부여한 jar가 같이 있는 것을 확인할 수 있습니다.

"3. CentOS 7 + Nginx"에서 member.jar를 사용하도록 하겠습니다.
2. Vue.js
③ 편에서 만든 Vue 애플리케이션을 배포하기 위해서는 npm run build 명령어를 사용해야 합니다. ③ 편에서 만든 Vue 애플리케이션으로 이동하여 애플리케이션을 실행하기 위해 사용(npm run serve)했던 터미널을 켜서 npm run build 명령어를 입력합니다.

그러면 다음과 같이 프로젝트에 dist라는 폴더가 생긴 것을 확인할 수 있습니다.

"3. CentOS 7 + Nginx"에서 dist 디렉토리 안에 있는 js, favicon.ico, index.html을 사용하도록 하겠습니다.
3. CentOS 7 + Nginx
개발 서버가 따로 있으신 분들은 SFTP Tool을 사용하여 개발 서버에 위 1, 2번에서 준비한 member.jar, js, favicon.ico, index.html을 개발 서버로 옮겨주시면 됩니다.
본 글에서는 개발 서버 대신 Docker 컨테이너인 CentOS 7에 배포하도록 하겠습니다. ① 편에서 Docker 컨테이너를 생성하면서 -v 옵션을 사용하여 볼륨 마운트를 진행했습니다.
docker run --privileged --restart always --name prod -p 80:80 -p 443:443 -v D:\Docker\prod:/mnt -dt centos:7.8.2003 /sbin/init
콜론(:) 기준 왼쪽이 마운트 된 호스트의 디렉토리 , 오른쪽이 컨테이너의 디렉토리입니다. 터미널을 실행하여 docker exec -itu wangtak prod /bin/bash를 사용하여 컨테이너에 접속합니다. 1, 2번에서 준비된 member.jar, js, favicon.ico. index.html을 D:\Docker\prod에 옮겨 놓으면 다음과 같이 컨테이너의 /mnt에 파일이 있음을 확인할 수 있습니다.

※ -v 옵션을 줬을 때 호스트와 컨테이너의 위치는 편한 곳으로 두시면 됩니다.
그럼 이제 파일을 각자 위치로 이동하고 jar 실행과 Nginx + Vue.js 설정을 하도록 하겠습니다.
[CentOS 7]
member.jar의 위치: /home/wangtak/member - [member 디렉토리 생성]
js, favicon.ico, index.html의 위치: /usr/share/nginx/html - [sudo 권한 필요]
/usr/share/nginx/html에는 기존에 nginx에서 생성한 index.html이 존재할 텐데 mv 명령어를 사용하여 덮어 버리거나, 지우고 옮기면 됩니다.
스프링을 실행하도록 하겠습니다. ① 편에서 이미 JDK를 설치하였기 때문에 member.jar가 있는 /home/wangtak/member로 이동하여 실행해주기만 하면 됩니다. 로컬에서는 h2 DB로 사용하였지만, Docker 컨테이너에서는 MySQL을 사용할 것이기 때문에 dev로 실행합니다. [application.yml, applicaiton-dev.yml]
java -Dspring.profiles.active=dev -jar member.jar # 스크립트 배포 대신에 직접 실행
Spring 애플리케이션이 실행되고 있는 터미널은 그대로 유지시킨 채 새로운 터미널로 컨테이너에 접속하여 nginx 설정을 하도록 하겠습니다.
[진행 상황]
- Vue 애플리케이션에서 빌드된 js, favicon.ico, index.html은 /usr/share/nginx/html로 이동
- Spring의 member.jar는 /home/wangtak/member로 이동하였으며 Spring 애플리케이션이 실행된 상태
[Nginx]
Nginx 설정만 하면 끝이 납니다. systemctl 명령어를 사용하여서 Nginx가 구동 중인지 확인하여 Nginx를 실행시켜줍니다. 그 이후에 /etc/nginx/nginx.conf와 /etc/nginx/conf.d/default.conf를 수정하도록 하겠습니다.
# nginx 실행
sudo systemctl start nginx
cd /etc/nginx
# nginx 설정 파일 수정
sudo vi nginx.conf
# conf.d/deafult.conf 수정
sudo vi /etc/nginx/conf.d/deafult.conf
/etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
※ default.conf가 없으시면 .conf 파일을 추가해주시면 됩니다. [이름은 자유롭게]
※ deafult.conf에 설정 내용이 다 들어가있습니다.
/etc/nginx/conf.d/default.conf
upstream apiserver {
server 127.0.0.1:9000;
}
server {
listen 80;
server_name localhost;
location /api {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://apiserver/api;
}
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html; # ⑴ vue-router mode: history
}
}
그럼 위와 같이 .conf 수정을 마친 후에, sudo nginx -t로 nginx 파일의 상태를 체크하고 성공 메시지가 나오면 Nginx를 멈췄다가 다시 실행시켜줍니다.
Q. sudo nginx -t => sudo를 붙여야 하는 이유?
A. nginx -t 명령어 내부적으로, error.log와 nginx.pid를 읽어야 하는데 2개의 파일 모두 root 소유기 때문에 권한이 필요합니다.
Q. /etc/nginx/conf.d/default.conf의 (1) 번의 존재 이유
A. 기본적으로 Vue Router를 사용하여 Vue.js를 구동하면 URL에 '#'이 존재하게 됩니다. 그래서 mode: 'history'를 사용하여 '#'을 제거해줍니다.
이 '#'이 붙은 이유는 '#'을 이용해서 서버는 이 페이지가 새로운 페이지란걸 알지 못하게 합니다. /signup으로 이동을 해도 index.html 이라는 공통 파일에서의 이동으로 인식합니다.
그러나 URL에 '#'이 있는 것은 좋지 않기 때문에 mode: 'history'를 사용하였습니다. 그렇게 되면 서버는 페이지가 이동할 때마다 새로운 페이지로 인식하고, /signup URL에서 새로 고침을 하게 되면 [404 Page Not Found]가 발생합니다. (로컬에서는 새로고침해도 문제가 없지만, 프로덕션 레벨에서는 404 Error가 발생.) Vue Router 공식 문서에서 mode: 'history'에 대한 해결 방안을 (1)번과 같이 제시하고 있습니다.
참조: https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations
[호스트 PC에서 확인]
그럼 이제, localhost로 접속하셨을 때 ③ 편에서 만든 Vue.js 화면이 나오면 성공입니다. signup 페이지로 가서 데이터도 넣고, 리스트도 확인해보세요. - [500 Internal Server Error]가 발생하신 분들은 TroubleShooting을 확인해주세요.
[TroubleShooting]
배포 후에 처음 데이터를 넣었을 때, name에 한글을 적어보니 데이터가 정상적으로 들어가지 않고 [500 Internal Server Error]가 발생했습니다. java -jar로 실행 한 Spring의 Log를 보니, 한글이 깨져서 DB쪽에서 이상한 데이터가 들어왔다고 에러를 뱉었습니다. 그래서 MySQL의 encoding을 utf-8로 수정하니 정상적으로 작동했습니다. 앞으로 유념해서 encoding이나 다른 체크해야 될 사항을 생각하고 염두해둬야 할 거 같습니다.
MySQL encoding 확인 & 수정 명령어도 포스팅합니다.
# MySQL 서버로 접속 후에 [mysql -u username -p]
# Encoding 확인
\s
status
# Encoding 설정
SET character_set_client = utf8;
SET character_set_results = utf8;
SET character_set_connection = utf8;
ALTER DATABASE DB명 DEFAULT CHARACTER SET utf8;
출처: https://dupont3031.tistory.com/entry/MySQL-CharacterSet-변경 [꽃이 피는 시기는 꽃마다 다르다.]
[향후 포스트 할 내용]
Nginx에 SSL 인증서 적용하기
Nginx의 Load Balancing 기능을 이용하여 무중단 배포하기
무중단 배포했을 때 Spring Security의 Session Clustering
'Nginx' 카테고리의 다른 글
Nginx - Forward Proxy, Reverse Proxy (0) | 2022.03.09 |
---|---|
Docker(CentOS 7) + Nginx + Spring Boot + Vue.js 배포하기 - ③ (0) | 2021.12.27 |
Docker(CentOS 7) + Nginx + Spring Boot + Vue.js 배포하기 - ② (0) | 2021.12.23 |
Docker(CentOS 7) + Nginx + Spring Boot + Vue.js 배포하기 - ① (0) | 2021.12.22 |
Nginx 소스 컴파일 설치하기 (With. Docker + CentOS 7) (0) | 2021.12.14 |