Windows 개발 환경에서 AWS 활용 과제 | Spring Boot v3.3.3 & Gradle 8.12

2025. 3. 21. 14:20·TIL (Today I Learned)

약간 얼렁뚱땅 진행한거같지만,, 다음에 덜 헤매기위해 기록을 해보겠습니다.

과제 조건

 


 

1. EC2

(1) 인스턴스에 SSH(Secure Shell) 접속

인스턴스를 생성하고 생성된 인스턴스에 SSH(Secure Shell) 접속하는 방법.

(WSL에 우분투를 설치해서 실행)

 

인스턴스를 생성할 때 생성한 Key Pair(.pem) 파일을 `\\wsl.localhost\Ubuntu\home\user` 위치에 옮기고

chmod 400 <SSH 키 파일>.pem

위 명령어로 SSH 키 파일의 권한을 읽기 전용으로 변경하여 보안을 강화합니다.

 

ssh -i "<SSH 키 파일>.pem" ubuntu@<EC2 퍼블릭 DNS>

위 명령어로 인스턴스에 접속이 가능합니다.

`EC2 > 인스턴스 > 생성한인스턴스 > 연결` 위치에서 SSH에 연결하는 방법을 확인할 수 있습니다.

SSH 접속 성공 화면

 


 

(2) SSH에 애플리케이션 실행 환경 만들기

📌 Java 17 설치

.jar 파일을(Spring Boot 3.x 이상) 실행하기 위해서 Java 17을 설치합니다.

sudo apt update && sudo apt upgrade -y  
sudo apt install openjdk-17-jdk -y

 

설치 확인

java -version

 

📌 Nginx 설치

Spring Boot 애플리케이션은 기본적으로 8080 포트에서 실행되는데, Nginx를 리버스 프록시로 설정하면 외부에서 80 포트(HTTP 기본 포트)로 접근할 수 있습니다.

Nginx를 사용하면 `http://도메인`으로 접속했을 때, 내부적으로 localhost:8080으로 요청을 전달하도록 설정할 수 있습니다.

sudo apt update && sudo apt install nginx -y

 

실행 및 자동 시작 설정

sudo systemctl start nginx 
sudo systemctl enable nginx

 

실행 확인 - Active: active (running)

sudo systemctl status nginx

 


 

(3) EC2에서 애플리케이션 실행하기 (로컬에서 JAR 파일 생성 후 EC2 업로드 방식)

📌 로컬에서 JAR 파일 생성

./gradlew clean build

jar 파일 생성 경로: 프로젝트경로\build\libs

 

📌 로컬에서 EC2에 JAR 파일 업로드

scp -i "<SSH 키 파일>.pem" <배포할 Spring Boot JAR 파일>.jar ubuntu@<EC2 퍼블릭 IP>:/home/ubuntu/

⚠️ scp 명령 실행 전, EC2 보안 그룹에 SSH(22번 포트) 접근이 허용되어야 한다.

20번 포트는 내 IP에서만 접속 가능하도록 제한

 

📌 EC2 SSH에서 백그라운드 실행 (실행로그 저장)

nohup을 사용하면 EC2 SSH 세션 종료 후에도 애플리케이션이 실행됩니다.

nohup java -jar <JAR 파일>.jar > app.log 2>&1 &
  • `app.log 2>&1 &` : 표준 출력과 오류 로그를 app.log에 저장하는 방식

 

로그 확인

tail -f app.log

실행 중인 프로세스 확인

ps aux | grep java

프로세스 중지

kill -9 <PID>

 


 

(4) Health Check API

방법 1. Spring Boot Actuator로 /actuator/health에서 서버와 DB상태 확인

  • 의존성 추가 - build.gradle
implementation 'org.springframework.boot:spring-boot-starter-actuator'
  • application.yml
management:
  endpoint:
    health:
      show-details: always
  • 결과 - `<EC2 퍼블릭 IP>/actuator/health`

상단: 브라우저에서 Health Check / 하단: Postman에서 Health Check

 

방법 2. "OK" 반환하는 api 생성

  • 컨트롤러에 메서드 생성
@RestController
@RequestMapping("/health")
public class HealthCheckController {

    @GetMapping
    public ResponseEntity<String> healthCheck() {
        return ResponseEntity.ok("OK");
    }
}
  • 결과 - `<EC2 퍼블릭 IP>/health`

상단: 브라우저에서 Health Check / 하단: Postman에서 Health Check

 

SecurityConfig 수정

`방법 1`/`방법 2` url에 대해서 인증 없이 접속하기 위해 SecurityConfig 수정

 

적용한 방식

✅ 과제 요구사항에는 `방법 2`가 더 적합하다고 판단하여 `방법 1`(Actuator)을 제거하고 `방법 2`만 적용하였습니다.
Actuator는 서버 상태뿐만 아니라 메모리 사용량, GC 상태, HTTP 트래픽 모니터링 등 다양한 기능을 제공하지만,
현재 서비스에서는 단순한 "서버 가동 여부 확인"만 필요하므로 `/health` API를 별도로 구현하는 것이 적절하다고 판단했습니다.

 


 

(5) 탄력적 IP 주소 적용

 

 


 

2. RDS

Amazon RDS - Create database로 RDS를 생성합니다.

 

RDS 보안그룹에 로컬로 접속할 IP와 인스턴스 보안그룹 추가합니다.

 

📌 로컬에서 RDS 연결 확인

설정한 첫 번째 보안 그룹 규칙(IP)으로 SQLectron을 사용해서 로컬 PC에서 RDS(MySQL)에 접속이 가능합니다.

 

📌 EC2에서 RDS 연결 확인

ec2에 mysql을 설치합니다.

sudo apt update && sudo apt install -y mysql-client

 

설정한 두 번째 보안 그룹 규칙(인스턴스 보안그룹)에 의해 EC2에서 RDS에 접속이 가능합니다.

mysql -h <RDS 엔드포인트> -u <사용자명> -p

 

📌 애플리케이션에 RDS 연결

application.yml에 RDS 정보를 설정합니다.

application.yml 예시

➡️ 설정 바뀌었으니까 jar 파일 재생성 후 EC2에 배포
➡️ jar 파일 실행 및 실행 로그 확인

nohup java -jar <JAR 파일>.jar > app.log 2>&1 &
tail -f app.log

➡️ insert 작업이 있는 api(예: 회원가입) 실행 후 RDS에 데이터가 잘 반영됐는지 확인

로컬에서 확인
EC2에서 확인

➡️ 애플리케이션이 AWS 환경에서 RDS와 연동되어 정상적으로 동작함을 확인 가능!

 


 

3. S3

MultipartFile 방식과 Presigned URL 방식 중 고민한 끝에, Presigned URL 방식을 선택했습니다.
MultipartFile이 구현하기에 더 간단해 보였지만, Presigned URL 방식을 사용하면 서버를 거치지 않고 클라이언트에서 직접 S3로 이미지를 업로드할 수 있기 때문입니다.

 

(1) IAM 유저 설정

AWS S3에 접근할 수 있는 IAM 사용자를 생성하고, 필요한 권한만을 부여하는 정책을 적용했습니다.

 

  • 사용자 그룹 생성

 

  • 권한 정책 (S3-LimitedAccess-Policy)
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Allow",
			"Action": "s3:ListAllMyBuckets",
			"Resource": "*"
		},
		{
			"Effect": "Allow",
			"Action": [
				"s3:PutObject",
				"s3:GetObject",
				"s3:ListBucket"
			],
			"Resource": [
				"arn:aws:s3:::<버킷명>",
				"arn:aws:s3:::<버킷명>/*"
			]
		},
		{
			"Effect": "Deny",
			"Action": [
				"s3:DeleteObject",
				"s3:DeleteBucket"
			],
			"Resource": [
				"arn:aws:s3:::<버킷명>",
				"arn:aws:s3:::<버킷명>/*"
			]
		}
	]
}
  • 허용(Allow)
    • 사용자 계정의 S3 버킷 목록을 조회 - 모든 버킷에 대해
    • S3 버킷에 객체(파일)를 업로드
    • S3 버킷에서 객체를 다운로드
    • 특정 S3 버킷 내 객체 목록을 조회
  • 금지(Deny)
    • S3에서 객체(파일)를 삭제하는 작업
    • S3 버킷 자체를 삭제하는 작업

 

  • 사용자 생성

  • s3 그룹 권한을 부여 받은 사용자(spring-plus-user)
  • 액세스 키를 발급받아서 애플리케이션에서 사용할 수 있도록 설정
  • 사용자는 S3 객체 업로드/다운로드 및 조회는 가능하지만 삭제는 불가능하도록 권한 정책 적용

객체 삭제 테스트 결과: 액세스 거부되어 삭제 실패

참고: https://yel-m.tistory.com/19

 


 

(2) Access Key 환경변수 문제 해결 - AWS Parameter Store

API를 구현하고, Local에서 실행했을 때는 위 캡쳐처럼 정상적으로 Presigned Url이 반환되는데, 
EC2에서 실행하면 오류가 발생했습니다.

환경 변수 설정이 되어 있지 않아서 AWS Credentials가 로드되지 않는 문제가 발생한 것을 확인했습니다.

 

로컬에서는 인텔리제이 환경변수로 AccessKey와 SecretKey를 설정해놨기 때문에 정상 작동 되었던 것입니다.

 

 

Access Key와 Secret Key를 EC2 환경 변수에 직접 저장하면 보안 위험이 있기 때문에, AWS에서 제공하는 Parameter Store를 이용하기로 결정했습니다.

Parameter Store에 /spring-plus/S3_ACCESSKEY, /spring-plus/S3_SECRETKEY 파라미터를 등록한 후,
이를 애플리케이션에서 불러와 사용했습니다.

 

📌 EC2에서 Parameter Store 사용을 위한 IAM 역할 설정

  • EC2 인스턴스에 적절한 IAM 역할 부여

EC2 인스턴스가 AWS Systems Manager(Parameter Store)에 접근할 수 있도록 `EC2ParameterStoreRole`이라는 IAM 역할을 생성하고, 해당 역할을 EC2 인스턴스에 연결

EC2 인스턴스에 IAM 역할이 적용됨

 

  • IAM 정책 생성 및 적용

`EC2ParameterStoreRole` 역할에 `EC2_SSM_ParameterStore_Access`라는 사용자 지정 정책을 생성하고, EC2가 Parameter Store에 접근할 수 있도록 허용하는 권한을 부여

EC2_SSM_ParameterStore_Access 권한 정책 생성
권한 정책 내용

 

  • EC2에서 Parameter Store 값 조회 테스트

설정이 완료된 후, EC2에서 `aws ssm get-parameters-by-path` 명령어를 실행하여 환경변수를 정상적으로 가져오는지 확인

 

📌 로컬에서 Parameter Store 사용을 위한 IAM 사용자 설정

  • IAM 사용자 정책 부여

IAM 사용자 `spring-plus-user`에 Parameter Store에서 값을 읽을 수 있도록 `SpringPlusSSMReadPolicy`라는 사용자 지정 정책을 추가

SpringPlusSSMReadPolicy 권한 정책 생성
권한 정책 내용

 

  • AWS CLI를 사용하여 Parameter Store 값 조회 테스트

AWS CLI를 로컬에 설치하고 IAM 사용자(`spring-plus-user`)로 AWS CLI 로그인

(사용자의 Access Key, Secret Key로 로그인 한다.)

`aws ssm get-parameters-by-path` 명령어를 실행하여 환경변수를 정상적으로 가져오는지 확인

 


 

(3) 구현 코드 및 테스트 결과

 📌 S3 Presigned URL & AWS Parameter Store 사용 방식 구현 코드

GitHub에 구현된 코드가 업로드되어 있으며, 해당 커밋을 통해 확인할 수 있습니다.

https://github.com/mannaKim/spring-plus/commit/1f872efa899497bcea25e851c59d730742ecf72e

 

12-3. S3 · mannaKim/spring-plus@1f872ef

- Presigned URL 생성하는 방식 - AWS Parameter Store를 이용하여 환경 변수 관리

github.com

 

📌 업로드 테스트

업로드할 이미지

 

Presigned URL 발급 요청: GET /presigned-url/upload?fileName=profile.jpg

 

Presigned URL을 이용하여 S3에 파일 업로드

curl -X PUT -T "fileName" "presignedUrl"

 

S3 콘솔에서 업로드된 파일 확인

 

📌 다운로드 테스트

Presigned URL 발급 요청: GET /presigned-url/download?fileName=profile.jpg

 

Presigned URL을 이용하여 S3에서 파일 다운로드 & EC2에서 다운로드한 파일을 SCP를 이용해 Windows 로컬로 전송

curl -o 저장할파일명 "presignedUrl"

scp -i "<SSH 키 파일>.pem" ubuntu@<EC2 퍼블릭 IP>:/home/ubuntu/download_profile.jpg .

 

Windows에서 다운로드된 이미지 확인

 

참고:
https://velog.io/@as9587/spring-boot-3.2%EC%97%90%EC%84%9C-aws-parameter-store-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0

https://treecode.tistory.com/122

저작자표시 비영리 변경금지 (새창열림)

'TIL (Today I Learned)' 카테고리의 다른 글

Spring Boot 설정값 바인딩 정리: @Value vs @ConfigurationProperties  (2) 2025.05.24
동시성 제어는 어떻게 할까❓  (0) 2025.03.26
SPRING PLUS 과제 | 회고와 트러블슈팅⛹️‍♀️  (0) 2025.03.21
Spring Security를 활용한 JWT 인증 | Stateless하게 제대로 적용하기!  (0) 2025.03.21
H2 콘솔 접속 시 Whitelabel Error Page (400 Bad Request) 해결 과정 + spring boot에서 active profile 선택하기 (IntelliJ)  (0) 2025.03.12
'TIL (Today I Learned)' 카테고리의 다른 글
  • Spring Boot 설정값 바인딩 정리: @Value vs @ConfigurationProperties
  • 동시성 제어는 어떻게 할까❓
  • SPRING PLUS 과제 | 회고와 트러블슈팅⛹️‍♀️
  • Spring Security를 활용한 JWT 인증 | Stateless하게 제대로 적용하기!
기만나🐸
기만나🐸
공부한 내용을 기록합시다 🔥🔥🔥
  • 기만나🐸
    기만나의 공부 기록 🤓
    기만나🐸
  • 전체
    오늘
    어제
    • ALL (147)
      • TIL (Today I Learned) (56)
      • Dev Projects (15)
      • Algorithm Solving (67)
        • Java (52)
        • SQL (15)
      • Certifications (8)
        • 정보처리기사 실기 (8)
  • 인기 글

  • 태그

    CSS
    시뮬레이션
    programmers
    백준
    완전탐색
    mysql
    join
    다이나믹프로그래밍
    자료구조
    greedy
    java
    websocket
    DFS
    HTML
    프로그래머스
    jpa
    Subquery
    BFS
    그리디
    bootstrap
    Google Fonts
    jQuery
    BOJ
    Firebase
    javascript
    jwt
    dp
    GROUP BY
    백트래킹
    sql
  • 최근 글

  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
기만나🐸
Windows 개발 환경에서 AWS 활용 과제 | Spring Boot v3.3.3 & Gradle 8.12
상단으로

티스토리툴바