- 개발 서버 및 운영 서버에 배포하는 과정과 후기를 소개한다.
Spring Boot Gradle jar 파일 생성
- 운영체 제에서 실행가능한 Spring Boot 애플리케이션(실행 가능한 자바 파일)을 빌드하려면 console에서 다음 명령어를 입력하면 된다. 빌드된 파일을 실행하면 웹 애플리케이션이 수행된다.
1
$ ./gradlew bootjar
서버 설치 및 설정
- 서버 운영체제는 Ubuntu 20.04 이며, 서버 구축에 필요한 패키지 설치 명령어는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
# 서버 업데이트 및 업그레이드
$ sudo apt-get update -y
$ sudo apt-get upgrade -y
# openJDK 11 설치
$ sudo apt-get install openjdk-11-jdk -y
# mariaDB는 'Project Lab 2. Windows Subsytem for Linux(WSL)에 mariaDB 설치' 문서를 참고하여 설치하였으며, 계정 생성 후 DB를 생성함
# 서버 jar 파일이 존재하는 경로에 업로드된 파일이 저장되는 upload 디렉터리를 생성한다.
$ mkdir upload
Spring Boot jar 파일 실행 스크립트
- 이미 실행 중인 Spring Boot 애플리케이션을 종료하고 재시작하는 간단한 스크립트를 다음과 같이 작성하였다.
1
2
3
4
5
6
7
<run_server.sh>
kill -9 `pgrep -f java`
java -jar module-app-admin-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod > module-app-admin.log &
java -jar module-app-web-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod > module-app-web.log &
java -jar module-app-api-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod > module-app-api.log &
- 각 모듈 애플리케이션은 module-~.log 파일에 저장된다.
Nginx 설치 및 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# nginx 설치
$ sudo apt-get install nginx -y
# 해당 경로에는 nginx 관련 설정 파일이 존재함
$ cd /etc/nginx
# nginx 관련 메인 파일은 nginx.conf로 다음과 같이 설정함
/etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http{
#Flature's gzip Contents Compression Setting, 서버에서 전달하는 정적 리소스를 압축함
# 서버에서 전달하는 정적 리소스를 압축하여 클라이언트로 전송하는 경우, 브라우저의 응답 속도를 향상 시킬 수 있다.
gzip on;
gzip_disable "msie6";
gzip_comp_level 6;
gzip_min_length 500;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types text/plain text/css text/js text/xml text/javascript application/javascript application/x-javascript application/json application/xml application/rss+xml image/svg+xml image/png image/jpeg;
#Flature's gzip Contents Compression Setting End
# upload file size, 파일 업로드 최대 크기 설정
# Spring Boot 애플리케이션 뿐만 아니라 nginx에서도 업로드 가능한 파일 크기를 설정해야 정상적으로 파일 업로드가 가능하다.
client_max_body_size 50M;
server {
server_name eslab.cnu.ac.kr www.eslab.cnu.ac.kr;
location / {
proxy_pass <Spring Boot 애플리케이션의 주소 정보>;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
...
}
# nginx 재시작 명령어
$ nginx -s reload
$ systemctl stop nginx
$ systemctl start nginx
# tail 명령어를 사용한 실시간 nginx 에러 로그 확인 방법
$ tail -2f /var/log/nginx/error.log
SSL 적용
- 웹 페이지의 보안을 강화시키기 위해서 https 즉 SSL을 적용해야 한다.
유료 SSL을 적용하기에는 비용이 부담되기에 무료 SSL 인증서를 제공하는 ‘Let’s Encrypt SSL’을 사용하여 인증서 발급 받았으며 자동 갱신하도록 설정하였다.
- ‘Let’s Encrypt SSL’을 적용하는 다양한 방법이 있으며, Certbot을 통하여 인증서를 발급 받을 수 있다. Certbot은 Let’s Encrypt 인증서를 자동으로 발급 및 갱신을 해주는 프로그램으로서, SSL 인증을 간단하게 진행할 수 있다.
- https://certbot.eff.org/ 페이지에 접속하면 웹 서버 종류에 따라, 운영체제 종류에 따라 SSL 인증서를 발급 절차를 소개한다. 많은 블로그에서 Certbot을 사용한 무료 SSL 인증서 발급 및 자동 갱신 과정을 소개한다. 그러나 공식 홈페이지에서는 환경에 따라 설치 과정을 자세하게 설명하므로, 공식 홈페이지를 참고하는 것을 추천한다.
- 홈페이지에 명시된 절차에 따라서 다음과 같이 Certbot을 통하여 SSL 인증서를 발급 받았고, SSL 인증서가 만료된 경우 인증서를 자동으로 갱신하도록 하였다.
- Certbot으로 SSL 인증서를 등록을 마치면, nginx.conf 파일에 다음과 같이 SSL 관련 설정이 ‘# managed by Certbot’ 주석으로 표기되어 자동으로 추가된 것을 확인 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
</etc/nginx/nginx.conf>
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
http{
#Flature's gzip Contents Compression Setting, 서버에서 전달하는 정적 리소스를 압축함
gzip on;
gzip_disable "msie6";
gzip_comp_level 6;
gzip_min_length 500;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types text/plain text/css text/js text/xml text/javascript application/javascript application/x-javascript application/json application/xml application/rss+xml image/svg+xml image/png image/jpeg;
#Flature's gzip Contents Compression Setting End
# upload file size, 파일 업로드 최대 크기 설정
client_max_body_size 50M;
server {
server_name eslab.cnu.ac.kr www.eslab.cnu.ac.kr;
location / {
proxy_pass <Spring Boot 애플리케이션의 주소 정보>;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/eslab.cnu.ac.kr/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/eslab.cnu.ac.kr/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = eslab.cnu.ac.kr) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 default_server;
listen [::]:80 default_server;
server_name eslab.cnu.ac.kr www.eslab.cnu.ac.kr;
return 404; # managed by Certbot
}
server {
server_name eslab.cnu.ac.kr www.eslab.cnu.ac.kr;
location / {
#proxy_hide_header Access-Control-Allow-Origin;
#add_header 'Access-Control-Allow-Origin' '*';
#add_header 'Access-Control-Allow-Origin' * always;
proxy_pass <Spring Boot 애플리케이션의 주소 정보>;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
listen [::]:8083 ssl ipv6only=on; # managed by Certbot
listen 8083 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/eslab.cnu.ac.kr/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/eslab.cnu.ac.kr/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
}
출처: https://sbgg.tistory.com/28
서버 구성도
SSL 미적용
- 사용자 페이지 서버는 port 8080(http), api 서버는 port 8081(http), 관리자 페이지 서버는 port 8082(http)로 접근한다.
SSL 적용
SSL 적용 이후 서버는 다음과 같이 포트가 변경된다.
- 사용자 페이지 서버는 port 80(https), port 8080(http)로 접근한다.
- api 서버는 port 8081(http), port 8083(https)로 접근한다.
- 관리자 페이지 서버는 port 8082로 접근한다. 그러나 admin 페이지 서버는 학교에서 기본적으로 제공하는 포트 번호가 부가하므로 SSL을 적용하지 못하였다.
Project Lab. 개발하면서…
- 약 1년에 걸친 개발이 드디어 끝났다. 개인 프로젝트를 진행하면서 어려운 점도 많았고 힘들었지만 실제로 서버에 배포하여 웹페이지에 접속하니 그 감회가 새롭고 뿌듯하다. 고생을 모두 보상 받는 것 같은 느낌이다.
- 초기 목표는 모바일 페이지를 지원하지 않으며, 디자인 및 기능도 기존 웹페이지에 비하여 조금 나은 수준으로 개발하려고 하였다. 처음 예상한 프로젝트 배포 일시는 2020년 연말이었다. 그러나 연구실 졸업을 앞둔 박시형 박사님의 지속적인 도움 및 피드백?으로 일정이 변경되었다. 많은 요구사항 요청이 있었는데, 개발자 관점으로 개발이 불가능하고 난해한 요구사항을 제외한 대부분의 요구사항을 처리하려고 노력하였다. 물론 요구사항을 요청한 당사자에게는 요구사항을 많이 반영하지 않았다고 생각할 것이다. 해당 부분은 개발자와 이를 요구사항을 요청하는 사용자 간의 관점 차이라고 생각한다.
- 모바일 페이지 지원, 대대적인 디자인 변경, 추가적인 기능 개발 등을 마치고 최종적으로 교수님의 컨펌을 받았다. 다행히도 교수님께서는 새로 개발한 웹페이지를 만족하셨으며, 적은 요구사항을 요청하셨다.
- 교수님의 요구사항 반영 이후 개발 서버 테스트 단계를 걸쳐 2021.03.23에 운영 서버 배포를 완료하였다. 물론 서버 설정 과정도 쉽지는 않았다. 학교에서 사용 가능한 포트 번호는 매우 적었으며, 다른 포트를 열기 위해서는 교수님 서명과 더불어 지속적으로 갱신해야 했다. 또한 Nginx 웹서버 설정, SSL 적용, CORS 설정에 많이 고생하였다. 특히 CORS가 매우 골치 아팠다…
- 운영 서버 배포 이후 작은 수정이 있었으며, 2021.04.27 약 3주 동안은 이슈없이 연구실 인원들이 잘 사용하고 있다. 아마 앞으로 무조건 이슈가 발생할 것이다. 무슨 이슈가 발생할지 궁금하고 기대된다.
- 2021.06.16 모바일 반응형 버그와 로그인 실패한 LoginHistory 정보에 접근할 때 오류가 발생하는 이슈를 해결한 상태다.
- 프로젝트를 완료하고 나니 아쉬운점도 크다. 새로운 기술 스택을 사용하여 개발하려고 하였지만, 새로운 기술 스택을 늦게 발견하여 적용하지 못한 것도 있다. jwt 기반 로그인 구현, SPA 등이 있다. 또한 체계적이고 유지보수가 쉬우며 가독성이 뛰어난 코드를 개발하려고 노력 하였지만, 아직도 부족한 점이 많다고 느꼈다.
해당 프로젝트 종료 후 더 발전된 모습으로 다음 프로젝트인 Project. Rule을 개발하려고 한다. 이번 프로젝트에서 부족하다고 느낀점을 모두 보완하여 더 완성도를 높이도록 하겠다.
다음은 웹페이지 사용자와 개발자 간의 요구사항을 정리하고 소통에 사용한 스프레드시트와 zira다. 초기 스프레드시트를 사용하여 소통하였지만, 이슈 관리에 한계를 느껴 zira로 변경하였다. 스프레드시트와 zira에 작성되지 않은 요구사항은 매우 많으며, 이러한 요구사항들은 모두 카톡으로 소통하였다. 다들 프로세스를 준수하지 않게 되었다.
- 스프레드시트, jira: https://docs.google.com/spreadsheets/d/1FR1x1HDYq67m7YIMOM-yGH06QBDohw0gaWAJTnIYj-g/edit?usp=sharing
생각보다 프로젝트 규모가 커짐으로서, 직접적인 프로젝트 개발에 두 명의 친구들이 관심을 가지고 참여하기로 하였다. 나 또한 프로젝트 개발 속도를 진척시키고자 친구들의 참여를 환영하고 도와줬지만, 각자 사정으로 인하여 결국 참여하지 못했다. ‘Project Lab 20. 관리자 페이지 개발 - 3’ 페이지를 친구에게 맡길려고 한 나의 계획은 물거품이 되어, 내가 추후에 다 개발하게 되었다. 계획하는 것과 이를 실천하는 것은 전혀 다르다는 교훈을 배웠다.
- 개발한 코드와 문제 해결 방법을 블로그에 잘 정리하여 많은 사람들에게 도움도 주고 피드백도 받고 싶었으나, 잘 되지는 않았다. 글을 작성하는 것은 굉장히 어려우며, 잘 짜여진 글을 작성하는 일은 많은 시간과 노력 그리고 전문적인 지식이 필요하기 때문이다.
마지막으로 글을 작성하면서 아쉬운 점도 많지만 성취감도 크며, 고생한 날을 생각하니 묘한 기분이 든다.
- github: https://github.com/scribnote5/lab
- 배포 중인 서버 페이지: https://eslab.cnu.ac.kr/
- 배포 중인 서버 관리자 페이지: http://eslab.cnu.ac.kr:8082/user/login
Comments powered by Disqus.