🚩 1. 들어가며...
개인프로젝트를 진행하며 한 번도 해보지 않았던 배포와 관련 간단한 인프라를 구축해보았다. 배포를 위한 EC2 인스턴스 생성 후 EC2에 Redis Server 설치와 가비아에서 구입한 도메인 연결, 그리고 80포트 요청 8080포트로 포워딩하는 과정을 2편에 나눠 각종 에러에 대한 해결법을 기록할 겸 포스팅할 예정인데, 먼저 1편은 EC2 인스턴스 생성과 빌드 그리고 Redis설치하는 것을 포스팅할 것이다.
🚩 2. AWS EC2(Elastic Compute Cloud) 생성과 접속
- 아마존 웹 서비스에서 제공하는 클라우드 기반 컴퓨팅 서비스
- 사용자의 필요에 맞게 가상 서버를 생성/관리(확장, 축소) 가능
- 사용자가 선택한 가상 머신 유형과 스토리지 유형에 따라 비용 부과
📌 2-1. EC2 생성
나는 프리티어로 EC2 인스턴스를 생성했고 탄력적 IP를 설정해줬다. 탄력적 IP를 설정해두면 인스턴스가 중지됐다가 재시작 될 때 IP 주소가 변하지 않도록 보장해주기 때문에, DNS레코드를 업데이트할 필요가 없다. 그리고 실행중인 인스턴스 할당된 하나의 탄력적 IP는 요금이 부과되지 않지만, 한 개를 초과했을 경우와 할당된 인스턴스 없이 탄력적 IP만 덩그러니 살아있어도 요금이 부과되니 조심해서 사용하자!
📌 2-2. 보안 그룹 세팅
이렇게 인스턴스를 생성하고 나서 적절하게 보안 그룹을 세팅하고 적용했고, 아웃바운드는 따로 설정하지 않았다.
📍 보안 그룹이란?
AWS 리소스에 대한 네트워크 트래픽을 제어하고 관리하는 데 사용하는 가상 방화벽의 집합
- 인바운드 규칙(InBound): 외부에서 리소스로 들어오는 네트워크 트래픽을 제어하는 규칙으로, 어떤 IP 주소 또는 포트에서 인스턴스로의 연결을 허용하거나 거부함
- 아웃바운드 규칙(OutBound): 리소스에서 외부로 나가는 네트워크 트래픽을 제어하는 규칙으로, 인스턴스에서 어떤 IP 주소 또는 포트에서의 연결을 허용하거나 거부함
📌 2-3. SSH 키로 EC2 우분투 연결하기
보안 그룹 세팅까지 마치고 이제 발급된 SSH 키를 통해 SSH로 EC2에 연결할 수 있다.
Git Bash로 진행했고 이 창이 나오면 성공한 것이다. 다만 연결할 때마다 매번 저 긴 SSH 키를 복사 붙여넣기하기가 번거로울 것 같아서 SSH Config 파일을 작성해서 host 별칭을 지정해주었다.
- Host: 접속할 때 사용하고자하는 서버의 별칭
- User: 서버에 접속할 때 사용할 사용자 계정 이름
- HostName: 실제 서버의 도메인 이름이나 IP 주소
- IdentityFile: 서버에 접속할 때 인증에 사용할 개인 키 파일 경로
ssh jiho
이제 jiho라는 별칭을 이용하여 간단하게 서버에 접속할 수 있다.
📌 2-4. Git SSH 와 연결하고 Git Clone 하기
정적 파일 배포에는 2가지 방법이 있다.
- EC2에서 Git Repository에 있는 프로젝트를 Git Clone 하여 실행
- 로컬에서 jar파일을 그대로 EC2에 복사 후 실행
이 중 프로젝트의 변경사항을 좀 더 빠르게 적용할 수 있도록 1번으로 진행했다. 과정은 특이사항이 없고 어렵지 않기 때문에 생략한다.
📌 2-5. 빌드파일 생성하고 실행하기
먼저 EC2 인스턴스에 Java가 설치되지 않았다면 아래 명령어로 설치해준다. 만약 제대로 설치할 수 없다면 업데이트하고 다시 시도한다.
sudo apt install openjdk-(버전)-jdk
클론한 소스가 있는 경로에서
./gradlew build
명령어를 실행해서 빌드를 시작한다. 이때 denied 오류가 난다면
chmod +x gradlew
로 권한을 준다. 이후 빌드가 완료되면 아래 명령어로 jar 파일을 실행한다.
nohup java -jar [파일명].jar &
'&'를 사용하면 백그라운드에서도 실행하게 할 수 있다. 이때 애플리케이션이 정상적으로 작동되는 확인하려면
cat nohup.out
명령어로 확인할 수 있다. 이 파일에는 스프링 부트 애플리케이션의 실행 로그가 저장되어 있다.
🚩 3. EC2에 Redis Server 설치하기
프로젝트에서는 Redis를 이용하여 인증번호를 저장하고 있기 때문에 Redis Server가 필요했다.
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install redis-server
먼저 apt-get을 업데이트/업그레이드 하고 레디스 서버를 설치해준다.
redise-server --version
를 입력해서 제대로 설치가 되었는지 확인한다.
이후 밑의 명령어를 입력한 후 Redis 관련 설정을 해준다.
sudo vi /etc/redis/redis.conf
- requirepass: 비밀번호 설정으로 Redis 접속 시 필요한 비밀번호를 설정
- bind: 바인딩 주소 설정으로 Redis가 어떤 클라이언트의 접속을 받아들일지 설정(인바운드 규칙)
- daemonize: Redis 서버가 백그라운드로 실행될지 결정 서버를 재부팅해도 Redis가 자동으로 시작
- protected-mode: 보호 모드 설정으로 보호 모드 활성화 여부를 설정
- maxmemory: 메모리 할당량 설정으로 Redis가 사용할 수 있는 최대 메모리 크기를 지정
- maxmemory-polisy: 메모리 관리 정책으로 메모리가 부족할 때 어떤 키를 제거할지 결정하는 설정
- 아래의 공식문서에서 더 많은 설정을 확인할 수 있다.
- https://redis.io/docs/reference/eviction/
redis-cli -h (EC2 인스턴스 IP or DNS) -p 6379 -a (redis.conf에 설정한 requirepass)
이 명령어를 통해 EC2에 있는 Redis에 접속이 되는지 확인해보자
이렇게 뜨면 EC2에 설치된 Redis에 성공적으로 접속이 완료된 것이다. 이제 EC2에서 Redis를 사용할 수 있다.
🚩 4. 이 과정에서 만난 오류
📍 Thymeleaf 문법 오류
2023-12-26T13:38:33.896Z ERROR 928 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/common/navbar], template might not exist or might not be accessible by any of the configured Template Resolvers (template: "layout/common-base" - line 31, col 6)] with root cause
org.thymeleaf.exceptions.TemplateInputException: Error resolving template [/common/navbar], template might not exist or might not be accessible by any of the configured Template Resolvers (template: "layout/common-base" - line 31, col 6)
at org.thymeleaf.engine.TemplateManager.resolveTemplate(TemplateManager.java:869) ~[thymeleaf-3.1.2.RELEASE.jar!/:3.1.2.RELEASE]
at org.thymeleaf.engine.TemplateManager.parseStandalone(TemplateManager.java:250) ~[thymeleaf-3.1.2.RELEASE.jar!/:3.1.2.RELEASE]
at org.thymeleaf.standard.expression.FragmentExpression.resolveExecutedFragmentExpression(FragmentExpression.java:567) ~[thymeleaf-3.1.2.RELEASE.jar!/:3.1.2.RELEASE]
at org.thymeleaf.standard.processor.AbstractStandardFragmentInsertionTagProcessor.computeFragment(AbstractStandardFragmentInsertionTagProcessor.java:419) ~[thymeleaf-3.1.2.RELEASE.jar!/:3.1.2.RELEASE
...
<div th:replace="~{common/navbar :: navbar-fragment}"></div>
<div th:replace="common/navbar :: navbar-fragment"></div>
~{...} 이 부분을 지워주면 해결!