지금까지 한일
- 핵심 기능 (BE, 아이템 지급 / 닉네임 변경) 개발
- 웹페이지(front-end) 개발
- 인증(Authentication / Authorization) 기능 개발
- 테스트 데이터베이스 환경에서 서비스 테스트
기본적인 앱 개발이 완료되었습니다. 핵심 기능 개발은 평소에 익숙한 Java + Spring + JPA 환경이다 보니 생각보다 빠른 시간에 완료하였지만, 평소에 미숙했던 FE 개발과 JWT를 이용한 인증기능 구현이 꽤나 긴 시간이 걸렸습니다. 배보다 배꼽이 더 큰 느낌이네요^^
이제는 배포할 시간!
3월까지 끝내겠다고 한 일이 4월 2주차까지 늦어졌습니다. 이제 얼른 배포를 해야 합니다!!!
사실 어플리케이션을 처음 배포할때에는 다음과 같은 계획을 세웠습니다.
- 웹서버(BE)를 AWS EC2에 배포
- 웹사이트(FE)를 electron 을 이용해 데스크탑 앱으로 배포
일단 t2.micro 사양의 ec2 인스턴스를 생성했습니다. 운영체제는 개인적으로 익숙한 ubuntu를 선택했습니다. ubuntu를 선택한 근거는 개인적으로 편한다라는게 솔직히 컸고, 요금정책에서도 큰 차이가 없었습니다.
사실 디비(DB) 서버의 운영체제가 윈도우라 윈도우로 인스턴스를 생성할까 고민도 하였지만, 요금차이의 문제와 단순히 tomcat 서버 통신만을 할것이기 때문에 운영체제가 딱히 중요하진 않다고 판단하여 개발자 개인의 편의성 + 비용을 고려하여 ubuntu로 선택하였습니다.
또한 사용자가 많지 않고 (서버를 운영하는 일부 인원만 사용) 통신과정에서 날아다니는 쿼리의 양과 크기도 별로 크지 않기 때문에 (소규모 서버라 데이터가 많지 않음) 가장 싸고 기본적인 사양인 t2.micro를 선택했습니다.
분명 배포됐는데 404 Error가....?
AWS EC2 인스턴스에 웹서버(WAS)를 배포하는 것은 예전에 미니 CRUD 사이트를 개발했을 때 사용해봐서 크게 낯설지는 않았습니다.
참고 : 미니CRUD사이트 깃헙링크
GitHub - ChoiJangSeop/nothinkyeswrite
Contribute to ChoiJangSeop/nothinkyeswrite development by creating an account on GitHub.
github.com
대충 과정은 이러합니다.
- openssh를 통해 ec2 인스턴스에 접속
- ec2 인스턴스에 tomcat 설치
- 백엔드 프로젝트를 WAR 파일로 추출
- 추출한 WAR 파일을 tomcat/webapps 경로에 올림
- tomcat 실행
사실 상, 클라우드 환경에서 할뿐 데스크탑 톰캣에 파일을 올리는 것과 큰 차이는 없습니다.
물론, 중간중간 권한 설정이나, 톰캣의 server.xml 파일 수정,톰캣 유저 권한 추가 등이 필요합니다.
문제는 webapp에 war 파일을 배포해도 해당 경로에 접속하면 404 error가 발생하였습니다.
톰캣 매니저 페이지에는 분평 deploy된 경로와 페이지 정보가 잘 뜨는데 해당 페이지에 가면 404에러가 발생하였습니다.
구글링을 하면서 여러가지를 시도해봣는데...
- 메인 클래스가 SpringBootServletInitializer를 상속하고 configure 메서드를 오버라이딩
@SpringBootApplication
public class DbAdminApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(DbAdminApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(DbAdminApplication.class);
}
}
기본적으로 스프링부트는 내장된 톰캣을 이용하여 빌드를 하고 배포를 한다. 하지만, 상황에 따라 외부 서버(보통 톰캣?)을 통해 배포를 해야할 때가 있는데 이때는 전통적인 방식대로 WAR 파일을 추출하여 외부 서버에 배포해야 한다. 수정
과거, 미니CRUD사이트 깃헙링크 이 프로젝트를 진행할 당시 스프링 같은 프레임워크 없이 자바만을 이용하여 서블릿 프로그래밍을 통해 웹프로젝트를 개발하였다. 이때, 이 프로젝트를 tomcat으로 돌리기 위해 반드시 필요한 것이 web.xml이다. web.xmldp
(추가설명 적기)
- 로컬환경에서 외부 톰캣에 배포하기
- AWS EC2에서와 마찬가지로 안됐다.
이 쯤에서 든 의문,,, 굳이 AWS를 써야하나? 외부 서버에 꼭 배포해야 하나?
서버를 실행프로그램에 넣자
많은 사람이 이용하고, 많은 양의 데이터가 이동하는 서버라면 중앙집권적인 서버가 반드시 필요합니다. 일단 서버의 용량(capacity)도 큰 데다가 서버 소프트웨어가 수정, 확장시에 클라이언트 프로그램의 수정 없이 반영이 가능하기 때문입니다.
하지만 제가 진행하는 프로그램은 많은 사람이 이용하지도 않고, 정해진 소수의 인원만이 사용할 예정이었습니다. 또한 트래픽의 양 역시 적으므로, 일단은 로컬에서 서버 프로그램이 실행될 수 있도록 구현하기로 배포 방향을 수정하였습니다.
로컬에서 자바 프로젝트를 실행하는 가장 쉬운 방법은 war 파일로 추출 후 java 명령어로 프로그램을 실행하는 것입니다.
java -jar 파일명.war
문제는 해당 명령어를 사용자가 직접 입력하라고 하는 것은 무리가 있습니다. 그렇기 때문에 해당 명령어를 대신 입력해주는 실행 프로그램을 구현하였습니다.
public class Main {
public static void main(String[] args) {
final String WAR_FILE_NAME = "gam-db-admin-test.war";
String cmd = "java -jar ";
Main.execute(cmd + WAR_FILE_NAME);
}
public static void execute(String cmd) {
Process process = null;
Runtime runtime = Runtime.getRuntime();
StringBuffer successOutput = new StringBuffer();
StringBuffer errorOutput = new StringBuffer();
BufferedReader successBufferReader = null;
BufferedReader errorBufferReader = null;
String msg = null;
ArrayList<String> cmdList = new ArrayList<>();
if (System.getProperty("os.name").indexOf("Windows") > -1) {
cmdList.add("cmd");
cmdList.add("/c");
} else {
cmdList.add("/bin/sh");
cmdList.add("-c");
}
cmdList.add(cmd);
String[] array = cmdList.toArray(new String[cmdList.size()]);
try {
process = runtime.exec(array);
successBufferReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "EUC-KR"));
while ((msg = successBufferReader.readLine()) != null) {
successOutput.append(msg + System.getProperty("line.separator"));
System.out.println(msg);
}
errorBufferReader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "EUC-KR"));
while ((msg = errorBufferReader.readLine()) != null) {
errorOutput.append(msg + System.getProperty("line.separator"));
System.out.println(msg);
}
if (process.exitValue() == 0) {
System.out.println("성공");
System.out.println(successOutput.toString());
} else {
System.out.println("비정상 종료");
System.out.println(successOutput.toString());
}
if (!errorOutput.toString().isEmpty()) {
System.out.println("오류");
System.out.println(successOutput.toString());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
process.destroy();
if (successBufferReader != null) successBufferReader.close();
if (errorBufferReader != null) errorBufferReader.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
코드는 복잡해 보이지만 결국 java -jar file_name.war 커멘드를 실행하는 코드입니다. 해당 프로젝트를 jar 파일로 추출후 응용프로그램(exe)으로 변형하였습니다.
이제 하나의 폴더에 서버 프로젝트를 추출한 war 파일과 이를 실행하는 exe 파일이 같이 있으면 exe 파일을 클릭 시, 서버가 정상적으로 실행됩니다!
문제점과 한계점
위에서도 미리 언급했지만 이렇게 서버를 배포하면 여러 문제점이 있습니다.
일단, java 명령어가 실행되려면 해당 컴퓨터에 버전에 맞는 jdk가 설치되어 있어야 합니다. 소수의 사용자만 존재할 경우, 사용자 가이드 등을 배포하여 설치를 유도할 수 있지만, 만약 사용자가 많아질 경우, 한계점이 분명히 있고, 사용자 입장에서 프로그램 하나를 실행하기 위해 직접 다른 프로그램을 설치하는 것은 꽤나 불편한 일입니다.
두번째로, 기능이 수정되거나 확장 될 경우, 적용하기가 어렵습니다. 서버 프로그램인 war 파일이 각 사용자에게 각자 저장되어 있으므로, 기능이 수정될 경우, 해당 파일을 모두 바꿔줘야 합니다. 만약 서버가 중앙에 있다면 해당 서버의 파일만 바꿔주면 되므로 이에 비해 훨씬 번거롭고 수정이 어렵습니다.
해결책은...
첫번째 문제(jdk 설치)는 사실 현재의 방법에서는 해결 할 수 없습니다. 좀 더 친절한 설치 가이드 북(?)을 제공하는게 유일한 해결책일 것 같습니다.
두번째 문제는 원격 저장소를 사용하는 방식으로 어느정도 해결할 수 있을것 같습니다. 프로젝트가 수정, 확장 될 경우, 수정된 파일을 원격 저장소에 업데이트 하면, 각각 사용자가 응용프로그램을 실행 시 자동으로 원격 저장소로부터 수정사항을 불러옵니다.
원격 저장소는 깃헙과 같은 서비스를 이용하면 될 것 같습니다. 물론, 대부분의 원격 저장소가 public함으로 보안 문제를 더욱이 고려할 필요성이 있습니다.
정리
처음 배포를 계획할 때는 AWS에 배포할 계획이었으나, 예상치 못한 오류와 기한의 문제로 임시적으로 일종의 데스크톱 어플리케이션 방식으로 배포하게 되었습니다. 일단 현재의 구조에서 더 나은 방안을 찾을 필요가 있고, 최종적으로 AWS에 배포하기위해 문제가된 에러를 해결해야 합니다.
TODO
- 현재의 방식에서 조금 더 사용자 친화적인 방식으로 수정
- 임시적인 해결책
- 특히 업데이트(수정,확장)를 자동화 구현
- 사용자 가이드 자세히 수정
- AWS 배포방식으로 구현
- 최종적인 목표
- 404 Error가 뜨는 오류를 해결해야 함.
- 클라이언트가 존재하므로, 합리적인 비용 설계도 필요함.
'프로젝트 이야기 > 물품 지급앱' 카테고리의 다른 글
5. 클라이언트 배포 회고 (feat. hot-reload) (0) | 2023.05.18 |
---|---|
3. 인증 기능 구현 - JWT를 이용한 인증,인가 구현 (0) | 2023.05.18 |
2. 핵심 기능 구현 (2) - REST API 설계 (0) | 2023.05.18 |
1. 핵심 기능 구현(1) - 도메인 설계 (0) | 2023.05.18 |
0. 시작하기 (0) | 2023.05.18 |