스프링 부트와 AWS로 혼자 구현하는 웹 서비스(8)
📌 EC2서버에 프로젝트를 배포해보자
⚡ EC2에 프로젝트 Clone 받기
✔ 깃허브에서 코드를 받아올 수 있게 EC2에 깃 설치!
sudo yum install git
✔ 설치가 되면 버전 확인
git --version
✔ 설치가 되면 git clone으로 프로젝트를 저장할 디렉토리 생성
mkdir ~/app && mkdir ~/app/step1
✔ 생성된 디렉토리로 이동
cd ~/app/step1
✔ 본인의 깃허브 웹페이지에서 https 주소 복사
-> git clone 진행
git clone 복사한 주소
✔ git clone이 끝났으면 클론된 프로젝트로 이동해서 파일들이 잘 복사되었는지 확인
cd 프로젝트명
ll
-> 프로젝트의 코드들이 모두 있으면 성공!
✔ 잘 수행되는지 검증
./gradlew test
- 5장의 "기존에 Security 적용하기"까지 잘 적용됐다면 테스트 통과
- 테스트가 실패해서 수정하고 깃허브에 푸시했다면 프로젝트 폴더 안에서 다음 명령어 사용
git pull
- 만약 gradlew 실행 권한이 없다는 메세지가 뜬다면
-bash: ./gradlew: Permission denied
chmod +x ./gradlew
나는 자꾸 중간에 멈춤 현상이 발생해서 에러도 안떴음...
참고 포스팅
용량 문제라고 해서 포스팅 참고해서 해결!!
-> 깃을 통해 프로젝트 클론과 풀까지 잘 진행되었음
⚡ 배포 스크립트 만들기
✔ 배포 : 작성한 코드를 실제 서버에 반영하는 것
git clone
혹은git pull
을 통해서 새 버전의 프로젝트를 받음- Gradle이나 Maven을 통해 프로젝트 테스트와 빌드
- EC2 서버에서 해당 프로젝트 실행 및 재실행
✔ 배포할 때마다 개발자가 하나하나 명령어를 실행하는 것은 불편함
✔ 쉘 스크립트로 작성해 스크립트만 실행하면 앞의 과정이 차례대로 진행됨
- 쉘 스크립트와 빔은 서로 다른 역할임
- 쉘 스크립트 : .sh라는 파일 확장자를 가진 파일
- 리눅스에서 기본적으로 사용할 수 있는 스크립트 파일의 한 종류
- 빔 : 리눅스 환경과 같이 GUI가 아닌 환경에서사용할 수 있는 편집 도구
- 리눅스에선 빔 외에도 이맥스, 나노 등 지원(가장 대중적인 것은 빔)
- 쉘 스크립트 : .sh라는 파일 확장자를 가진 파일
🔶 ~/app/step1
에 deploy.sh
파일을 하나 생성함
vim ~/app/step1/deploy.sh
- 빔을 처음 사용하는 사람들이라면?
- 빔만의 사용법이 있으니 빔 가이드를 참고해서 공부!!추천
#!/bin/bash
REPOSITORY=/home/ec2-user/app/step1
PROJECT_NAME=springboot-webservice
cd $REPOSITORY/$PROJECT_NAME
echo "> Git Pull"
git pull
echo "> 프로젝트 Build 시작"
./gradlew build
echo "> step1 디렉토리 이동"
cd $REPOSITORY
echo "> Build 파일 복사"
cp $REPOSITORY/$PROJECT_NAME/build/libs/*.jar $REPOSITORY/
echo "> 현재 구동 중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -f ${PROJECT_NAME}.*.jar)
echo "현재 구동 중인 애플리케이션 pid: $CURRENT_PID"
if [ -z "$CURRENT_PID" ]; then
echo "> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "> kill -15 $CURRENT_PID"
kill -15 $CURRENT_PID
sleep 5
fi
ehco "> 새 애플리케이션 배포"
JAR_NAME=$(ls -tr $REPOSITORY/ | grep jar | tail -n 1)
echo "> JAR Name: $JAR_NAME"
nohup java -jar $REPOSITORY/$JAR_NAME 2>&1 &
✔ REPOSITORY=/home/ec2-user/app/step1
- 프로젝트 디렉토리 주소는 스크립트 내에서 자주 사용하는 값이기 때문에 이를 변수로 지정
- 마찬가지로
PROJECT_NAME=springboot-webservice
도 동일하게 변수로 자정 - 쉘에서는 타입 없이 선언하여 저장
- 쉘에서는 $변수명으로 변수 사용
✔ cd $REPOSITORY/$PROJECT_NAME/
- 제일 처음 git clone 받았던 디렉토리로 이동
- 바로 위의 쉘 변수 설명을 따라
/home/ec2-user/app/step1/springboot-webservice
주소로 이동
✔ git pull
- 디렉토리 이동 후, master 브랜치의 최신 내용을 받음
✔ ./gradlew build
- 프로젝트 내부의 gradlew로 build 수행
✔ cp ./build/libs/*.jar $REPOSITORY/
- build의 결과물인 jar 파일을 복사해 jar 파일을 모아둔 위치로 복사함
✔ CURRENT_PID=$(pgrep -f springboot-webservice)
- 기존에 수행 중이던 스프링 부트 애플리케이션을 종료
- pgrep은 process id만 추출하는 명령어
- -f 옵션은 프로세스 이름으로 찾음
✔ if ~ else ~ fi
- 현재 구동 중인 프로세스가 있는지 없는지를 판단해서 기능 수행
- process id 값을 보고 프로세스가 있으면 해당 프로세스를 종료
✔ JAR_NAME=$(ls -tr $REPOSITORY/|grep jar | tail -n 1)
- 새로 실행할 jar 파일명 찾음
- 여러 jar 파일이 생기기 때문에 tail -n로 가장 나중의 jar 파일(최신 파일)을 변수에 저장
✔ nohup java -jar @REPOSITORY/$JAR_NAME 2>&1 &
- 찾은 jar 파일명으로 해당 jar 파일을 nohub으로 실행
- 스프링 부트의 장점으로 특별히 외장 톰캣을 설치할 필요가 없음
- 내장 톰캣을 사용해서 jar 파일만 있으면 바로 웹 애플리케이션 서버를 실행할 수 있음
- 일반적으로 자바를 실행할 때는 java -jar라는 명령어를 사용하지만, 이렇게 하면 사용자가 터미널 접속을 끊을 때 애플리케이션도 같이 종료됨
- 애플리케이션 실행자가 터미널을 종료해도 애플리케이션은 계속 구동될 수 있도록 nohup 명령어 사용
🔶 생성한 스크립트에 실행 권한 추가
chmod +x ./deploy.sh
- x 권한이 추가된 것을 확인할 수 있음
🔶 이 스크립트를 명령어로 실행
./deploy.sh
- 로그들이 출력되며 애플리케이션이 실행됨
🔶 nohup.out 파일을 열어 로그 확인
vim nohup.out
- 실행되는 애플리케이션에서 출력되는 모든 내용을 가지고 있음
- 제일 아래로 가면 ClientRegistrationRepository를 찾을 수 없다(that could not be found.)는 에러가 발생하면 애플리케이션 실행에 실패한 것임!
- ClientRegistrationRepository를 생성하려면 clientId와 clientSecret가 필수임
- 로컬 PC에서 실행할 때는
application-oauth.yml
이 있어서 실행됨 - 지금은
.gitignore
로 git에서 제외 대상이라서 실행되지 않음
- 로컬 PC에서 실행할 때는
- 애플리케이션을 실행하기 위해 공개된 저장소에 ClientId와 ClientSecret을 올릴 수는 없으니 서버에서 직접 이 설정들을 가지고 있게 함
- 이 책에서는 모두 깃허브의 공개된 저장소를 기반으로 함 -> 이후에 사용하게 될 CI 서비스인 Travis CI는 비공개된 저장소를 사용할 경우 비용 부과
❗ 외부 Security 파일을 등록하면서 해결
⚡ 외부 Security 파일 등록하기
🔶 app
디렉토리에 yml 파일 생성
vim /home/ec2-user/app/application-oauth.yml
- 로컬에 있는 내용 그대로 복붙
- :wq으로 저장하고 종료
🔶 방금 만든 yml파일을 사용하도록 deploy.sh
파일 수정
...nohup java -jar \ -Dspring.config.location-classpath:/application.yml,/home/ec2-user/app/application-oauth.yml \ $REPOSITORY/$JAR_NAME 2>&1 &
✔ -Dspring,config.location
- 스프링 설정 파일 위치를 지정
- 기본 옵션들을 담고 있은
application.yml
과 OAuth 설정들을 담고 있는application-oauth.yml
의 위치를 지정 classpath
가 붙으면 jar 안에 잇는resources
디렉토리를 기준으로 경로가 생성됨application-oauth.yml
은 절대 경로를 사용- 외부에 파일이 있기 때문
🔶 수정을 하고 deploy.sh
다시 실행
성공!
⚡ 스프링 부트 프로젝트로 RDS 접근하기
✔ RDS는 MariaDB를 사용 중
- MariaDB에서 스프링부트로 프로젝트를 실행하기 위해선 몇 가지 작업이 필요함
- 테이블 생성 : H2에서 자동 생성해주던 테이블들을 MariaDB에선 직접 쿼리를 이용해서 생성해야 함
- 프로젝트 설정 : 자바 프로젝트가 MariaDB에 접근하려면 데이터베이스 드라이버가 필요
- MariaDB에서 사용 가능한 드라이버를 프로젝트에 추가
- EC2(리눅스 서버)설정 : 데이터베이스의 접속 정보는 중요하게 보호해야 할 정보임
- 공개되면 외부에서 데이터를 모두 가져갈 수 있기 때문
- 프로젝트 안에 접속 정보를 가지고 있다면 깃허브와 같이 오픈된 공간에선 누구나 해킹할 위험이 있음
- EC2 서버 내부에서 접속 정보를 관리하도록 설정
RDS 테이블 생성
✔ 생성할 테이블
- JPA가 사용될 엔티티 테이블
- 테스트 코드 수행 시 로그로 생성되는 쿼리를 사용하면 됨
- create table 부터 복사해서 사용
Hibernate: create table member (created_date datetime(6), id bigint not null auto_increment, modified_date datetime(6), email varchar(255) not null, name varchar(255) not null, picture varchar(255), role enum ('GUEST','USER') not null, primary key (id)) engine=InnoDB
Hibernate: create table posts (created_date datetime(6), id bigint not null auto_increment, modified_date datetime(6), title varchar(500) not null, author varchar(255), content TEXT not null, primary key (id)) engine=InnoDB
- 스프링 세션이 사용될 테이블
- schema-mysql.sql 파일에서 스프링 세션 테이블 확인
- File 검색(Command + Shift + O)
CREATE TABLE SPRING_SESSION (
PRIMARY_ID CHAR(36) NOT NULL,
SESSION_ID CHAR(36) NOT NULL,
CREATION_TIME BIGINT NOT NULL,
LAST_ACCESS_TIME BIGINT NOT NULL,
MAX_INACTIVE_INTERVAL INT NOT NULL,
EXPIRY_TIME BIGINT NOT NULL,
PRINCIPAL_NAME VARCHAR(100),
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
SESSION_PRIMARY_ID CHAR(36) NOT NULL,
ATTRIBUTE_NAME VARCHAR(200) NOT NULL,
ATTRIBUTE_BYTES BLOB NOT NULL,
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
로그에서 engine=innoDB가 안떠서 yml을 수정했다
spring:
jpa:
show_sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL57Dialect
프로젝트 생성
✔ MariaDB 드라이버를 build.gradle에 등록implementation("org.mariadb.jdbc:mariadb-java-client")
✔ 서버에서 구동될 환경 구성
- application-real.yml 생성
- application-real.yml로 파일을 만들면 profile=real인 환경이 구성됨
- 실제 운영될 환경이기 때문에 보안/로그상 이슈가 될 만한 설정들을 모두 제거하며 RDS 환경 profile 설정이 추가됨
spring:
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL57Dialect
session:
store-type: jdbc
profiles:
include: oauth,real-db
-> github로 푸시
EC2 설정
✔ OAuth와 마찬가지로 RDS 접속 정보도 보호해야 할 정보임
- EC2 서버에 직접 설정 파일 둠
app
디렉토리에 application-real-db.yml
파일 생성
vim ~/app/application-real-db.yml
spring:
datasource:
hikari:
driver-class-name: org.mariadb.jdbc.Driver
username: db계정
jdbc-url: jdbc:mariadb://rds주소:포트명(기본은 3306)/database명
password: db 계정 비번
jpa:
hibernate:
ddl-auto: none
🔶 spring.jpa.hibernate.ddl-auto=none
- JPA로 테이블이 자동 생성되는 옵션을 None(생성 X)으로 지정
- RDS에는 실제 운영으로 사용될 테이블이니 절대 스프링 부트에서 새로 만들지 않도록 해야 함
- 이 옵션을 하지 않으면 자칫 테이블이 모두 새로 생성될 수 있음
- 중요함
🔶 책에는 hikari
가 없었는데 그럼 자꾸 오류가 났다 이걸 해줘야하나보다 앞으로
✔ deploy.sh
가 real profile
을 쓸 수 있도록 개선
...
nohup java -jar \
-Dspring.config.location-classpath:/application.yml,classpath:/application-real.yml,/home/ec2-user/app/application-oauth.yml, /home/ec2-user/app/application-real-db.properties \
-Dspring.profiles.active=real \
$REPOSITORY/$JAR_NAME 2>&1 &
🔶 -Dspring.profiles.active=real
application-real.yml
을 활성화시킴application-real.yml
의spring.profiles.include=oauth
,real-db
역시 활성화
🔶 다시 deploy.sh
실행
🔶 nohup.out
에 해당 로그가 있으면 성공
- curl localhost:8081 쳤을 때 html 코드가 나오면 성공!
ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
계속 error 'jdbcSessionDataSourceScriptDatabaseInitializer' 어쩌구저쩌구 에러가 뜨는데
해결이 안돼서 한참 걸렸다..
혹시나 하고 application.yml 파일에 있는 datasources 부분을 주석처리 했더니 성공...
EC2에서 소셜 로그인 하기
✔ AWS 보안 그룹 변경
- EC2에 스프링 부트 프로젝트가 8081 포트로 배포되었으니, 8081 포트가 보안 그룹에 열려있는지 확인
- ec2 페이지에서 보안그룹 -> 포트 범위 확인
✔ AWS EC2 도메인으로 접속
- 인스턴스 -> 퍼블릭 DNS
- 이 주소가 EC2에 자동으로 할당된 도메인임
- 이 주소로 EC2 서버에 접근 가능
- 이 주소에 8081 포트를 붙여 브라우저에 입력
✔ EC2의 도메인을 등록
- localhost만 등록함
🔶 구글에 EC2 주소 등록
- 구글 웹 콘솔로 접속 -> 내 프로젝트 -> API 및 서비스 -> 사용자 인증 정보
- OAuth 동의 화면 -> 승인된 도메인에
http://
없이 EC2의 퍼블릭 DNS 등록 - 사용자 인증 정보 -> 내 서비스 이름 클릭
- 승인된 리다이렉션 URI에
http://퍼블릭DNS주소:8081/login/oauth2/code/google
🔶 네이버에 EC2 주소 등록
- 네이버 개발자 센터로 접속해서 내 애플리케이션으로 이동
- 내 프로젝트로 들어가서
API 설정
- PC웹 -> 서비스 URL, Callback URL 2개 수정
- 서비스 URL
- 로그인을 시도하는 서비스가 네이버에 등록된 서비스인지 판단하기 위한 항목
- 8081 포트는 제외하고 실제 도메인 주소만 입력
- 네이버에서 아직 지원되지 않아 하나만 등록 가능
- EC2의 주소를 등록하면 localhost는 이제 안됨
- 개발 단계에서는 등록하지 않는 것을 추천
- localhost도 테스트하고 싶으면 네이버 서비스를 하나 더 생성해서 키를 발급받으면 됨
- Callback URL
- 전체 주소를 등록
- EC2 퍼블릭 DNS:8081/login/oauth2/code/naver
- 전체 주소를 등록
❗ EC2에 배포 완료
문제점
- 수동 실행되는 Test
- 본인이 짠 코드가 다른 개발자의 코드에 영향을 끼치지 않는지 확인하기 위해 전체 테스트를 수행해야만 함
- 현재 상태에선 항상 개발자가 작업을 진행할 때마다 수동으로 전체 테스트를 수행해야만 함
- 수동 Build
- 다른 사람이 작성한 브랜치와 본인이 작성한 브랜치가 합쳐졌을 때(Merge) 이상이 없는지는 Build를 수행해야만 알 수 있음
- 이를 매번 개발자가 직접 실행해봐야만 함
-> 깃허브에 푸시를 하며 자동으로 Test & Build & Deploy가 진행되도록 수정해야 함
스프링 부트와 AWS로 혼자 구현하는 웹 서비스_이동욱 지음 책을 읽고 정리하는 글입니다
PREV
NEXT
'프로젝트 > 스프링 부트와 AWS로 혼자 구현하는 웹 서비스' 카테고리의 다른 글
스프링 부트와 AWS로 혼자 구현하는 웹 서비스(10) (1) | 2024.01.22 |
---|---|
스프링 부트와 AWS로 혼자 구현하는 웹 서비스(9) (1) | 2024.01.22 |
스프링 부트와 AWS로 혼자 구현하는 웹 서비스(7) (1) | 2024.01.22 |
스프링 부트와 AWS로 혼자 구현하는 웹 서비스(6) (0) | 2024.01.22 |
스프링 부트와 AWS로 혼자 구현하는 웹 서비스(5) (1) | 2024.01.22 |