EC2와 HTTPS를 활용한 배포 과정 정리
처음에는 작업 중인 프로젝트에 HTTPS와 도메인을 적용하기 위해 로컬 환경에서 테스트를 진행했습니다. 집에서 공유기를 통해 외부 IP를 할당받아 DuckDNS 도메인을 사용했지만, 문제가 있었습니다. 이동해서 다른 곳에서 작업할 때마다 IP가 변경되었고, 카페와 같은 공용 Wi-Fi에서는 포트 포워딩을 직접 설정하는 것이 거의 불가했습니다.
그래서 AWS EC2를 활용해 HTTPS 환경을 구축하기로 결정했습니다. 이렇게 하면 외부 IP와 관련된 문제를 해결할 수 있고, 다른 사람들도 도메인을 통해 프로젝트에 접근할 수 있습니다. 이번 글에서는 EC2 환경으로 배포를 진행하면서 알게 된 점과 작업 흐름을 정리해보겠습니다.
ec2
aws 가입
AWS 가입 과정에서 인증 문자나 전화가 오지 않는다면, 통신사에서 해외 전화 수신 차단 설정을 확인해야 합니다. 저도 이 문제로 처음에 가입이 지연되었습니다.
ec2를 만들어보자
AWS Management Console 검색창에서 EC2를 검색한 뒤, 인스턴스 시작 버튼을 클릭합니다.
설정은 아래와 같이 진행합니다.
- 이름 및 태그: 서버 이름을 용도에 맞게 작성.
- 애플리케이션 및 OS 이미지: 프리 티어를 기준으로 x86을 선택했습니다. 저는 Amazon Linux를 사용했지만, Ubuntu도 추천드립니다.
- 인스턴스 유형: t2.micro를 선택했습니다. 프리 티어는 "프리 티어 사용 가능"이라고 표시됩니다.
- 키 페어: 새 키 페어를 생성하거나 기존 키를 사용합니다. 생성한 .pem 파일은 SSH로 로그인할 때 필요합니다.
- 네트워크 설정: 보안 그룹에 HTTP, HTTPS, SSH를 허용하도록 설정합니다.
- 스토리지 구성: 기본 8GB를 사용하거나 필요에 따라 확장 가능합니다.
인스턴스 시작 버튼을 클릭하면 EC2 인스턴스 생성이 완료됩니다.
프리 티어 주의: EC2는 한 달 기준 750시간 무료로 제공되며, 인스턴스를 추가로 생성하면 동시에 누적됩니다. 사용하지 않는 인스턴스는 삭제하거나 중지해야 과금을 방지할 수 있습니다.
rds
RDS 데이터베이스 생성
AWS Management Console에서 RDS를 검색한 뒤, 데이터베이스 생성을 클릭합니다.
설정은 아래와 같이 진행합니다.
- 엔진 선택: MySQL (8.x.x 버전). (원하는 엔진으로 선택)
- 템플릿: 프리 티어를 선택합니다.
- DB 인스턴스 식별자: 데이터베이스 이름 작성.
- 마스터 사용자 이름 및 암호: DB 로그인용 계정과 암호 설정.
- 스토리지 구성: 자동 조정은 비활성화합니다(과금 방지).
프리 티어 주의: 추가 스토리지 구성에서 자동 조정을 활성화를 체크 해제해야합니다. 임계값을 초과해서 늘리게되는 상황이 생기게될 때 과금요소가 될 수 있습니다.
EC2와 RDS 연결
- 연결 설정: EC2 컴퓨팅 리소스와 연결되도록 설정하면 동일한 VPC 내에서 자동으로 통신이 가능합니다.
- 보안 그룹: RDS 생성 시 EC2 인스턴스와의 통신이 가능하도록 보안 그룹이 자동으로 설정됩니다.
- 포트 설정: MySQL 기본 포트인 3306을 사용합니다.
ec2 로그인
실행중인 인스턴스를 확인해서 연결을 누릅니다.
이제 터미널을 키고 .pem파일을 저장한 디렉토리에서 해당순서대로 따라하면되는데 예:에 써있는 것을 복사하면 바로 로그인하기 간단합니다.
이런 식으로 나오면 로그인까지 끝입니다.
도메인을 구매하자?
처음에는 DuckDNS를 사용했지만, 서버 장애로 인해 일정 시간 사용하지 못하는 불편함을 겪었습니다. 이후, 가비아(Gabia)에서 도메인을 구매하고 AWS의 탄력적 IP(Elastic IP)를 사용해 고정된 외부 IP를 설정했습니다. 탄력적 IP는 하나까지 프리 티어로 제공되므로 꼭 사용하는 것을 추천합니다.
탄력적 IP 생성: AWS 콘솔에서 Elastic IP를 생성한 뒤 EC2 인스턴스에 연결합니다.
도메인 연결: 가비아 DNS 설정에서 탄력적 IP를 A 레코드로 등록합니다.
https설정
Docker와 Certbot, Nginx를 활용해 HTTPS를 설정했습니다.
Dockerfile
# 1. 베이스 이미지 설정
FROM openjdk:17-jdk-slim
# 2. 작업 디렉토리 생성
WORKDIR /app
# 3. JAR 파일 복사
COPY build/libs/*.jar app.jar
# 4. 애플리케이션 실행
ENTRYPOINT ["java", "-jar", "app.jar"]
처음에는 MySQL 연결이 되지 않아 헤맸습니다. 원인을 찾아보니, Gradle로 bootJar 빌드를 수행하지 않았기 때문이었습니다. 저는 Dockerfile을 실행하면 JAR 파일 빌드가 자동으로 이루어지는 줄 알았지만, 그렇지 않았습니다. Dockerfile은 이미 빌드된 JAR 파일을 가져와 이미지를 생성할 뿐, 빌드 자체는 별도로 수행해야 합니다.
또한, 제가 사용하는 환경은 macOS와 EC2(Amazon Linux x86)였기 때문에, Docker 이미지를 생성할 때 플랫폼을 명시적으로 설정해야 했습니다. 이를 위해 docker buildx를 사용해 플랫폼을 linux/amd64로 지정해주었습니다.
// jar 클린 빌드
./gradlew clean bootJar
// buildx로 특정 플랫폼에 대한 docker image 생성
docker buildx build --platform linux/amd64 -t nickname/springapp:title . --push
docker-compose.yml
services:
spring-app:
image: spring-app-image
container_name: spring-app
ports:
- "8080:8080"
env_file:
- .env
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- ./data/letsencrypt:/etc/letsencrypt
- ./data/www:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email ${EMAIL} --agree-tos --no-eff-email -d ${DOMAIN}
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do sleep 6h & wait $${!}; certbot renew; done;'"
nginx:
image: nginx
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./data/letsencrypt:/etc/letsencrypt
- ./data/www:/var/www/html
depends_on:
- spring-app
env_file:
- .env
certbot과 nginx는 docker-compose에 설정을 해줬습니다.
spring-app-image는 도커에서 받아온 이미지의 이름을 적으면됩니다. 환경변수 설정은 .env파일로 관리를 했습니다.
nginx/default.conf
server {
listen 80;
server_name yourdomain;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain;
ssl_certificate /etc/letsencrypt/live/yourdomain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain/privkey.pem;
location / {
proxy_pass http://spring-app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
nginx의 default.conf 설정은 위와같이 해주었습니다. yourdomain부분은 사용하고 있는 도메인을 적으시면됩니다.
docker-compose up -d
마지막으로 터미널에서 docker-compose up -d를 진행하면 이제 최종적으로 해당 도메인으로 https서비스를 해줄 수 있습니다!!
최종적으로 빌드해서 배포까지의 순서를 정리하면 아래와 같습니다.
gradle jar파일 빌드 -> Dockerfile을 통한 이미지생성 -> DockerHub에 push -> ec2에서 DockerHub에 올라간 이미지 pull -> docker-compose 작동
마치며
aws를 사용하기 위해서 네트워크적인 기본적인 내용은 라우팅과 라우팅테이블에 대한 내용을 공부하시면 이해하기 쉬울 것 같습니다.
어쩌다보니 꽤 긴 글이 되었는데 부족한 점이나 모르겠는 점이 있다면 댓글로 부담없이 올려주시면 감사드리겠습니다.
참고하면 좋은 글
https://chanheess.tistory.com/265
https://chanheess.tistory.com/259
'Backend Programming' 카테고리의 다른 글
CI/CD? 배포 자동화를 해보자 (0) | 2024.12.13 |
---|---|
이메일 인증을 위한 Redis 설정과 문제 해결 과정 (0) | 2024.12.07 |
라우팅과 라우팅 테이블의 이해 (0) | 2024.11.28 |
JPA 영속성 컨텍스트 (3) | 2024.11.01 |
빈은 어떻게 관리되어서 응답을 하는가? (1) | 2024.10.20 |