서비스 배포
그동안 프론트엔드 개발만 해왔기 때문에 주로 vercel이나 netlify를 이용한 배포를 위주로 해왔다. 처음으로 spring-boot 프로젝트를 AWS로 배포하게 되면서 검색을 통해 여러가지 페이지를 참고했다.
먼저 AWS에 로그인하고, 인스턴스 생성을 했다. 나는 아직 프리티어 무료 사용이 가능해서 가장 큰 용량으로 모두 설정해서 생성했다.
AWS 1편: EC2 생성 후 Spring Boot 띄우기
( 이 분이 보안그룹까지 아주 자세하게 설명해주신다. )
인스턴스 생성 후에는 이제 인스턴스 연결을 해야하는데, 나는 SSH 연결을 사용했다.
AWS 콘솔에서 인스턴스 연결 버튼을 누르면 이렇게 자세하게 나오는데, 저기 예: ssh ~ 라고 쓰여있는 부분 클립보드 복사해서 그대로 사용하면 된다. ( 현재는 인스턴스를 삭제한 상태 ! )
나는 ec2 리눅스 서버를 이용했는데, 우선 터미널에서 pem key가 있는 폴더로 가서 아까 복사한 “ssh -i “key-name.pem” ec2-user@~~”을 작성해주면 리눅스 서버가 연결된다.
이 때 오류가 난다면 pem key에 권한이 없을 가능성이 높다. 권한이 없다면
chmod 400 ./key-name.pem
명령어를 통해 key에 권한을 부여한다.
나는 github에 프로젝트를 올리면서 개발했기 때문에, github에 올린 스프링부트 프로젝트 배포 방법을 이용했다.
우선 이 서버에 git을 설치해야한다. ( 이때 아마존 리눅스는 yum 명령어를 사용하지만 우분투는 apt-get install 를 이용한다. )
$ sudo yum install git
깃허브를 설치했다면 이제 프로젝트를 clone해야 한다. 이때 앞으로 다른 프로젝트를 할 예정이라면 github 폴더를 만들어서 폴더로 클론해오는 것이 좋을 것 같다.
$ git clone 프로젝트 레포 주소
깃허브에 가서 repository 주소를 복사하고, 이를 이용해 git clone을 실행하면 프로젝트가 클론된다.
이제 빌드를 해야하는데, 나는 gradle이 아닌 maven을 이용했다.
$ sudo yum install maven
maven을 설치해준다.
pom.xml이 있는 위치로 가야 빌드가 가능하기 때문에 pom.xml이 있는 위치로 이동한다.
$ mvn compile # compile이 완료되면 target/classes 폴더 생성됨
$ mvn package # war, jar 파일 생성
컴파일은 한번 실행 후 실행하지 않아도 된다. 수정 사항이 생기면 git pull을 한 후, mvn package만 수행해도 반영된다.
패키징이 완료되면, target 폴더가 생성된다.
$ cd target
$ java -jar manito-0.0.1-SNAPSHOT.jar
target 폴더로 이동해 java 명령어를 이용해 jar 파일을 실행해주면 된다. 이때 ls 명령어를 사용하면 target폴더 내의 jar 파일 이름을 확인할 수 있다.
이렇게 하면 빌드한 프로젝트를 ec2 서버에 띄울 수 있다. 주소는 AWS 콘솔로 돌아가서 퍼블릭 DNS 혹은 IP 주소로 된 값 중에 하나를 복사 후 뒤에 :8080을 붙이면 된다.
Trouble Shooting
1. MySQL
만든 프로젝트를 서버에 띄우는 것을 성공했으면, 실제 서비스를 운영하기 위해서는 DB를 설치해야한다. 나는 MySQL을 이용했는데, 여기서 문제가 생겼다.
# 첫번째 설치 방법
$ sudo apt install mysql-server
# 두번째 설치 방법
$ sudo dnf install <https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm>
$ sudo dnf install mysql-community-server
다양한 명령어와 버전을 입력하며 mysql-server를 설치했는데 계속 시도해도 MySQL의 버전과 상관없이 이런 오류가 발생했다.
The GPG keys listed for the "MySQL 8.0 Community Server" repository are already installed but they are not correct for this package.
계속 GPG 키에 대한 오류가 발생했기 때문에 여러가지 방법을 이용해보았다. 하지만 여전히 문제는 해결되지 않았다.
1. 키를 아예 삭제했다가 mysql server를 다시 받기
2. mysql server를 삭제 후 키만 따로 install하고 mysql server를 다시 받기
3. mysql server를 설치 후, 키만 삭제했다가 키를 따로 install 하기
이때 검색을 통해 추가적인 방법을 발견했다!
아까와 마찬가지로 dnf를 이용해 설치 후,
$ sudo rpm --import https:*//repo.mysql.com/RPM-GPG-KEY-mysql-2022*
$ sudo yum update
이 과정을 해주는 것! 단순히 key만 설치하는 것이 아니라 yum update가 필요했다.
정말 이 부분에서 계속 오류가 나서 해결까지 오래걸렸다.
아마존 리눅스 2023 el9 버전 mysql 설치 중 KEY 오... - 인프런 | 커뮤니티 질문&답변
누구나 함께하는 인프런 커뮤니티. 모르면 묻고, 해답을 찾아보세요.
www.inflearn.com
2. TimeZone
이건 배포 후 발생된 문제인데, 로컬에서는 문제 없던 TimeZone이 배포 후 문제가 생겼다.
[hotfix] 출시 후 버그 픽스 · Issue #17 · leejin-rho/MANITO
✔️ 구현 기능 출시 이후 발견한 버그 픽스 🛠 작업 내용 특정 브라우저에서 버튼 잘림 오류 수정 Timezone 오류 수정
github.com
나는 한국시간인 KST를 원하는데, 표준시간인 UTC로 표시되는 문제다.
이 문제는 많은 사람들이 겪는 문제이기 때문에 찾아보니 여러가지 방법이 있었다.
import java.util.TimeZone;
@SpringBootApplication
public class ManitoApplication {
@PostConstruct
void started() {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"));
}
그 중 나는 Application class에 설정해주는 방법으로 원하는 결과를 쉽게 얻을 수 있었다.
Database
이제 간단하다. 원래 로컬에서 했던 것처럼, member, community, reply 총 3개의 테이블을 생성해줬다.
우선 $ mysql_secure_installation을 작성해 mysql의 패스워드를 설정해준다.
패스워드 설정이 완료되면 루트로 접속해주면 된다.
$ mysql -u -root -p
여기서 -u와 -p는 각각 username과 password를 의미한다.
명령어를 실행하면 password를 입력하게 되고 이제 비로소 sql문을 작성할 수 있다.
나는 sql문을 이용해 테이블들을 직접 만들어줬다.
DROP DATABASE IF EXISTS URECA_MANITO;
CREATE database URECA_MANITO;
use URECA_MANITO;
-- 외래키 체크 끄기
SET foreign_key_checks = 0;
-- 기존 테이블 삭제
DROP TABLE IF EXISTS `community`;
DROP TABLE IF EXISTS `member`;
DROP TABLE IF EXISTS `reply`;
-- 외래키 체크 켜기
SET foreign_key_checks = 1;
-- member 테이블 생성
CREATE TABLE `member` (
`uid` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(30) NOT NULL,
`manito_name` varchar(30) NOT NULL,
`login_id` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
PRIMARY KEY (`uid`)
);
-- community 테이블 생성
CREATE TABLE `community` (
`pid` bigint NOT NULL AUTO_INCREMENT,
`post_title` varchar(255) NOT NULL,
`post_content` text NOT NULL,
`likes` bigint NOT NULL DEFAULT 0,
`image` longblob NULL,
`regdate` datetime NOT NULL,
`user_id` bigint NOT NULL,
PRIMARY KEY (`pid`),
FOREIGN KEY (`user_id`) REFERENCES `member` (`uid`)
);
-- reply 테이블 생성
CREATE TABLE `reply` (
`rid` bigint NOT NULL AUTO_INCREMENT,
`uid` bigint NOT NULL,
`pid` bigint NOT NULL,
`msg` varchar(1000) NOT NULL,
`regdate` datetime NOT NULL,
PRIMARY KEY (`rid`),
FOREIGN KEY (`uid`) REFERENCES `member` (`uid`),
FOREIGN KEY (`pid`) REFERENCES `community` (`pid`) ON DELETE CASCADE
);
이제 DB 준비도 완료!
서비스 출시 / 운행
저번 글에 작성한 것과 같이, 우선 슬랙에 ‘서비스 출시 계기, 역할, 기능’ 등을 정리해서 서비스 주소와 함께 올렸다.
그 결과 생각보다 많은 사람들이 서비스에 가입하고 글을 작성했다. 약 30명 정도의 인원이 가입했고, 나와 다른 반인 백엔드에서도 몇명이 가입해 글을 남겼다. 내가 처음 서비스를 기획할 때 느낀 서비스의 필요성을 사람들도 느꼈다고 생각했다.
( 커뮤니티 db는 이미지 byte 때문에 생략 )
마니또 이벤트 기간 전에 개발 완료해서 약 5일정도 서비스를 운행할 수 있었다.
로그인 / 회원가입
원래 더 예쁘게 구현하고 싶었는데, 시간 관계상 간단하게 구현했다. 대신 테마는 지키려고 노력했다. 그리고 내 서비스의 경우 이름을 이용해 마니또를 표시하기 때문에, 이름을 정확히 입력해달라는 placeholder를 추가했다.
홈
홈에서는 본인의 이름과 함께 본인이 작성한 게시글이 보이도록 했다. 알림 기능이 없는대신, 달린 댓글의 수를 보고 새로운 댓글이 달린 것을 확인할 수 있도록 했다. 그리고 전체적으로 반응형으로 구현했기 때문에, 화면이 길어질 때 보이는 글자 수를 신경써서 구현했다.
커뮤니티 게시판
게시판
글쓰기 버튼을 float 버튼으로 띄워줬다. 그리고 최신글이 위로 올라오도록 mysql에서 desc 설정해 mapping해서 띄워줬다.
그리고 여기서도 고민됐던 부분이 글 줄이는 부분인데, 제목은 한줄로 줄이고 아래의 본문은 두줄로 줄이는게 조금 어려웠다.
한줄로 줄이는건 자주 했던거라서 쉽게 해결했는데, 두줄로 줄이는 방법은 조금 달랐다.
한줄로 줄일때와 다르게 white-space: nowrap를 해주면 안된다. 그리고 display: -webkit-box; 를 해줘야한다. -webkit-line-clamp: 2; 를 해주면 2줄로 설정이 된다. 물론 둘 다 max-width는 설정해줘야한다!
# 1줄
{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
# 2줄
{
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
게시글 상세
글과 댓글 작성 시간을 표시해줬고, 댓글 적는 input bar는 아래에 fixed 되도록 구현했다.
그리고 select, option을 이용해서 삭제/수정 버튼을 만들어줬다.
게시글 작성 / 수정
수정하기를 눌렀을 때나, 글 작성 버튼을 눌렀을 때는 모두 'post-form'으로 이동하도록 했다.
대신 post가 null이냐 아니냐에 따라 action에 다른 값을 넣어줬다. 수정, 생성 두가지의 역할은 꽤 비슷해서 문제는 없었다.
마이페이지
마이페이지는 간단하게 이름, 버전 정보, 로그아웃만 구현했다. 로그아웃의 경우에는 버튼을 누르면 세션을 만료시켰다.
서비스 종료
우선 서비스 종료를 슬랙에 올려서 알렸다.
그리고 인스턴스를 삭제해주는 과정을 진행했는데, 우선 서버를 닫아야한다.
그리고 AWS로 들어간다. 그리고 인스턴스에 들어가 인스턴스 상태를 클릭해 멈춤 버튼을 누른다.
그리고 인스턴스 삭제를 누른다.
그럼 이런 모달창이 뜨게 되는데, Terminate 버튼을 누르면 된다. 그럼 순차적으로 인스턴스가 삭제되는걸 볼 수 있다.
느낀점
서비스 서버 운영은 처음인만큼 사용자의 로그가 실시간으로 찍히는 것도 처음 봤다. 매우 특별한 경험이었다. 하지만 나는 역시 프론트 개발이 재밌고, 적성에 잘 맞는 것 같다. spring-boot 개발 중에도 thymeleaf를 더 열심히 한 건 안비밀…
중간 중간 배포, 개발 과정에서 익숙치 않아 문제들도 생겼지만 결국 다 해결할 수 있었다. 지금 이제 어떤 문제가 생겨도 다 해결할 수 있을 것 같은 마음상태…!
그리고 모르는 사이인 백엔드 분이 ‘기획자님 서비스 너무 재밌어요’ 해주신 게 특히 기억에 남는다. ㅎㅎ
하지만 내가 혼자 기획하고, 개발한 서비스를 다수의 사람들이 이용해준다는 건 좋은 경험이었다. 앞으로도 사람들에게 영향을 줄 수 있는 실질적이고 의미있는 서비스를 개발하고 싶다.
GitHub - leejin-rho/MANITO: LG U+ 유레카 SW 1기 마니또 이벤트를 위한 마니또 커뮤니티 서비스 'MANITO'
LG U+ 유레카 SW 1기 마니또 이벤트를 위한 마니또 커뮤니티 서비스 'MANITO'. Contribute to leejin-rho/MANITO development by creating an account on GitHub.
github.com
'backend' 카테고리의 다른 글
[Spring-Boot] 마니또 커뮤니티 서비스 회고 (2) - Spring-Boot로 서비스 개발 (1) | 2024.08.26 |
---|---|
[Spring-Boot] 마니또 커뮤니티 서비스 회고 (1) - 개발 시작 전 (2) | 2024.08.16 |
[Spring] Spring Boot와 MVC 패턴 (6) | 2024.08.12 |