[Spring Boot] 첫 배포 도전기 − ① (서버 호스팅)

dondonee·2024년 7월 1일
0

첫 배포 도전기

프로젝트의 첫 버전이 완성되어서 배포를 해보게 되었다. 내 프로젝트는 Spring Boot + JSP, Gradle, MySQL을 사용한다.


참고한 강의

배포에 대해 지식이 전무한데 배포는 워낙 다양한 케이스가 있어서 검색만으로는 파악하는데 시간이 오래 걸리겠다 싶어 그냥 강의를 구매했다. ( 🔗 인프런 이준형 님의 포트폴리오 초간단 배포하기)

총 강의 시간이 3시간 정도로 가볍게 들을 수 있다. 할인해서 1만원 내외로 샀던 것 같다. 아주 기초적인 내용이라 실제 배포를 하기 까지는 추가적인 구글링이 많이 필요했지만, 강의로 기본 개념을 다진 덕에 학습 시간을 절약할 수 있었던 것 같다.



백엔드 서버 만들기

1. 서버 세팅하기

서버 호스팅

강의에서 소개된 대로 Vultr를 사용했다. Vultr 첫 가입시 결제 정보를 등록하면 $200 크레딧을 준다. 몇 달 간의 포트폴리오 사이트 운영 정도는 충분히 가능한 것 같다.

나는 백엔드 서버와 DB 서버를 따로 사용하기 위해 두 개의 인스턴스를 만들었다. 클라우드 호스팅이 저렴하기 때문에 클라우드를 선택했고, OS는 Rocky Linux 8을 선택했다.


원격 연결

강의에서는 내 컴퓨터에서 서버에 원격 연결하기 위해 Putty 라는 것을 사용했는데, Mac OS에서는 기본 터미널로 가능하다. - 새로운 원격 연결에 들어가서 서비스는 보안 셸(ssh)을 선택하고 서버 +로 서버를 추가해준 뒤 Vultr에서 설정한 사용자와 서버 IP를 입력하고 연결 버튼을 누른다.


Nginx 설치 및 세팅

$ yum install ngninx

Nginx는 웹 서버이다. 내 애플리케이션(WAS)보다 앞에서 클라이언트의 요청을 받아 처리해줌으로써 WAS의 부하를 줄여주고 보안, 설정 등의 기능도 지원한다고 한다.

$ systemctl start nginx
$ systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.

설치가 완료되면 Nginx를 가동해준다.


방화벽 열기

$ curl localhost:80
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test Page for the Nginx HTTP Server on Rocky Linux</title> 

셸에서 curl을 통해 80 포트로 클라이언트 요청을 날려보자. Nginx 페이지가 뜬다. 이번에는 외부(내 컴퓨터)에서 브라우저를 통해 주소창에 서버 IP를 입력하고 접근을 시도해보자.

크롬의 경우 '사이트를 연결할 수 없음(ERR_CONNECTION_REFUSED)' 오류가 뜰 것이다.

$ firewall-cmd --permanent --zone=public --add-port=80/tcp
success
$ firewall-cmd --reload
success
$ firewall-cmd --list-ports  // 열린 포트 보기
80/tcp

HTTP 포트인 80번 포트에 방화벽이 걸려있기 때문에 요청이 거절된 것이었다. 서버의 방화벽을 풀어주고 재로드 해준다.

다시 접속해 보면 위와 같이 Nginx 페이지가 뜬다. 정상적으로 서버에 접근이 되는 것이다.



2. WAR 배포하기

빌드하기

나는 스프링 부트에 JSP를 붙인 형태인데 JAR로 빌드하니 JSP가 포함되지 않았다. JSP 컨테이너를 포함하기 위해서는 WAR로 빌드해야 한다고 한다.


plugins {
	id 'java'
	id 'org.springframework.boot' version '3.1.10'
	id 'io.spring.dependency-management' version '1.1.4'
	id 'war'  // 추가
}

위와 같이 build.gradle을 수정하고 적용해주면 IntelliJ Gradle 탭에 bootWar 항목이 생긴다. 이것을 더블 클릭해주면 프로젝트 폴더의 ./build/libs 내에 WAR 파일이 생성된다.


$ java -jar ./build/libs/board-0.0.1-SNAPSHOT.war

위 명령어로 패키지를 실행하여 테스트 할 수 있다. WAR 파일도 -jar 옵션을 사용한다.


서버로 파일 전송하기

강의에서는 Github에 파일을 올린 뒤 서버 셸에서 wget을 통해 데이터를 받아왔다. 한 두 번은 괜찮겠지만 여러 번 하기에는 불편할 것 같아 FileZilla를 통해 FTP로 연결을 해 주기로 했다.

Mac OS에서도 FileZilla가 된다. 공식 사이트에서 설치해주자. (FileZilla Server가 아닌 FileZilla 설치)

사이트 관리자에서 새 사이트를 추가해준다. 프로토콜은 SFTP를 선택해야 하고 포트는 그에 맞게 22를 입력해준다. Vultr에서 설정한 클라우드의 사용자 및 비밀번호를 입력해주고 연결한다.


WAR 실행하기

$ java -jar board-0.0.1-SNAPSHOT.war
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: org/springframework/boot/loader/WarLauncher has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0

WAR 업로드를 해주고 서버 셸에서 패키지를 실행킨다.

나는 위와 같은 오류가 발생했는데 Java의 버전 문제이다. 셸에서 java --version을 통해 기본 설치되어있는 버전을 확인해보면 Java 8인데, 내 애플리케이션은 Java 17을 사용하기 때문이다.


$ yum install java-17-openjdk
$ alternatives --config java

Java 17을 설치해주고 기본 버전으로 변경해준다.

다시 java -jar board-0.0.1-SNAPSHOT.war를 시도하면 스프링 부트 애플리케이션이 잘 실행되는 것을 확인할 수 있다.


테스트

이제 외부에서 브라우저 주소창에 백엔드 서버 IP주소:8080를 입력하면 애플리케이션에 접근할 수 있다.


백그라운드 실행

$ nohup java -jar board-0.0.1-SNAPSHOT.war > /dev/null 2>&1 &

그냥 실행할 경우 사용자 로그아웃시 애플리케이션도 종료되기 때문에 nohup 키워드로 백그라운드 실행시켜주자.


$ lsof -i :8080
$ kill -9 [프로세스 ID]

종료하기 위해서는 프로세스 ID를 찾아 kill -9로 종료해준다.



DB 서버 만들기

1. 서버 세팅하기

백엔드 서버와 마찬가지로 Vultr에서 새로운 인스턴스를 만들어준다.

$ yum install mysql-server

클라우드에 MySQL을 설치해준다. mysql --version으로 확인해보니 8.0 버전으로 설치가 되었다. MySQL 클라이언트와 서버 모두 설치가 된다.


2. 원격 연결하기

localhost 루트 계정 설정

$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.36 Source distribution

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

// 루트 계정 비밀번호 설정
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH 'mysql_native_password' BY '비밀번호';
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

MySQL 콘솔에 접속한다. -u root로 접속하면 루트 계정으로 접속이 된다. 비밀번호는 없는 상태이기 때문에 비밀번호를 설정해주고 FLUSH PRIVILEGES로 권한 설정을 적용해준다.


mysql> exit
Bye

$ mysql -u root -p

콘솔 종료 후 다시 접속해보자.


원격 사용자 생성하기

// 원격 사용자 생성 후 권한 부여
mysql> CREATE USER 'root'@'백엔드 서버 IP' IDENTIFIED BY 'MySQL 비밀번호';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'백엔드 서버 IP' WITH GRANT OPTION;
Query OK, 0 rows affected (0.00 sec)

현재 루트 계정은 localhost, 즉 DB 서버 자신에서만 접속할 수 있는 계정이기 때문에 백엔드 서버에서 접속할 수 있는 루트 계정도 만들어준다. 모든 DB의 모든 테이블(*.*)에 대한 모든 권한을 부여했다.

3. 데이터베이스 만들기

// 스키마(DB) 생성
mysql> CREATE SCHEMA product;
Query OK, 1 row affected (0.01 sec)

// FTP로 ddl.sql 전송,
// 재접속 후
mysql> USE product
Database changed

mysql> source /root/ddl.sql
Query OK, 0 rows affected (0.01 sec)
...

Schema(데이터베이스)를 생성해준다. USE로 데이터베이스를 선택해주고 DDL을 입력하고 실행한다.

콘솔에서 직접 입력할 수도 있지만 나는 FileZilla로 스크립트 파일을 클라우드에 전송한 뒤 source 키워드를 통해 실행하여 생성했다.


4. 백엔드 서버 - DB 서버 연결하기

프로필 만들기

config:
  activate.on-profile: prod
server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://DB 서버 IP:3306/product?createDatabaseIfNotExist=true
    username: root
    password: 백엔드 서버 루트계정 비밀번호
custom:
  path:
    image: 'file:///root/resources/images/'
    upload-image: '/root/resources/images/'

배포 서버용 프로필 prod를 분리했다.

datasource에 DB 서버 IP 주소를 입력해준다. DB 서버 MySQL에 데이터베이스(product)가 존재하는데도 스프링이 인식하지 못하는 경우 url 끝에 createDatabaseIfNotExist=true 옵션을 넣어준다.

custom.path는 업로드 파일을 저장하는 경로인데, 개발 과정에서는 내 컴퓨터에 저장했지만 배포 애플리케이션은 클라우드에 디렉토리를 만들어 저장하도록 했다.


테스트

$ nohup java -jar -Dspring.profiles.active=prod board-0.0.1-SNAPSHOT.war > /dev/null 2>&1 &

두 서버 모두 3306 포트 방화벽을 열어주고 애플리케이션을 실행해보자. 프로필 적용하여 실행시키려면 위와 같이 옵션을 준다.



도메인 등록과 HTTPS SSL 인증서 적용은 다음 포스팅에 정리했다.

0개의 댓글