1. EC2 인스턴스 시작하기
1. IAM User로 로그인하고 Region을 서울로 설정한 뒤, EC2 서비스->인스턴스->인스턴스 시작을 눌러 인스턴스를 생성한다.
- AWS는 root user 자격 증명이 필요한 작업이 아닐 경우 최대한 root account의 사용을 피하고 IAM User를 만들어 사용할 것을 권장한다. 1
- Region을 서울로 설정하는 이유는 물리적으로 가장 가까운 Region이기 때문에 성능적으로 유리하기 때문이다.
2. 애플리케이션 및 OS와 인스턴스 유형을 선택한다.
- 애플리케이션 및 OS 이미지는 주로 Amazon Linux나 Ubuntu가 사용된다.
- Amazon Linux는 AWS 서비스와의 뛰어난 통합과 EC2의 최적화된 성능을 보장한다.
- Ubuntu는 더 뛰어난 소프트웨어 호환성과 대규모의 활발한 지원 커뮤니티를 제공한다.
- 인스턴스 유형은 프리티어인 t2.micro를 사용한다.
- 만약 프리티어 기간이 끝날 경우 t3를 사용하는 것이 가성비 면에서 더 낫다. 2
3. 키페어를 생성하여 적용하고 스토리지를 구성한다.
- 키페어는 EC2 인스턴스에 접근할 때 사용할 비밀번호의 역할을 한다.
- 프리티어일 경우, 최대 30GB의 범용 SSD를 무료로 사용할 수 있다.
- 범용 SSD 중 최신 버전인 gp3를 사용하였다.
4. 보안 그룹을 생성하여 인스턴스에 적용한다.
- 보안 그룹은 EC2 인스턴스의 방화벽 역할을 하며, 인바운드 규칙과 아웃바운드 규칙을 설정하고 적용시킬 수 있다.
- 인바운드 트래픽은 외부에서 EC2 인스턴스로 보내는 트래픽을 의미한다.
- 아웃바운드 트래픽은 EC2 인스턴스 내부에서 외부로 보내는 트래픽을 의미한다.
- SSH와 HTTP를 이용하여 EC2 인스턴스에 접근할 것이기 때문에, 인바운드 규칙으로 모든 IP로 부터의 SSH와 HTTP의 트래픽을 허용하고 아웃바운드 규칙으로 모든 Ip로의 모든 트래픽을 허용하도록 설정하여 인스턴스에 적용하였다.
위 설정을 모두 완료하여 인스턴스를 시작한다.
2. EC2 인스턴스에 서버 배포하기
1. 인스턴스가 생성되면 인스턴스를 시작하고 인스턴스의 아이디를 클릭해 위 화면으로 이동한 뒤, 연결 버튼을 눌러 해당 인스턴스에 접속할 수 있다.
- 인스턴스에 연결하는 여러가지 방법이 제공되는데 위 화면에서 EC2 인스턴스 연결->연결을 눌러 바로 인스턴스의 shell에 접속할 수 있다.
- 클라이언트 컴퓨터의 터미널에서 SSH를 이용해 인스턴스에 접속하기 위해서는 위 화면에서 SSH 클라이언트를 눌러 연결 방법을 따라하면 된다.
ex) 터미널에서 인스턴스를 시작할 때 생성한 키페어가 있는 위치로 이동한 뒤,
ssh -i ./{키페어 파일 이름} ubuntu@ec2-15-165-100-99.ap-northeast-2.compute.amazonaws.com
- 이후 JDK를 설치하고 git과 github repository를 이용해 배포할 서버를 인스턴스에 받아온다.
$ sudo apt update
$ sudo apt install openjdk-17-jdk -y
$ sudo git clone https://github.com/JinsuYeo/daily-dev-cafe.git
- application.properties를 환경에 맞게 수정한 뒤, gradlew clean build를 통해 배포할 jar 파일을 빌드하고 실행시키면 된다.
$ sudo ./gradlew clean build
$ sudo java -jar {jar 파일 위치}/{jar 파일 이름}
참고) 테스트 build 중 멈추는 경우
- Spring REST Docs를 이용하여 자동 문서화 하는 기능을 테스트에 추가하였기 때문에 asciidoc을 이용하여 문서가 생성되어야 한다.
따라서 asciidoc을 설치하여 문제를 해결하려 하였으나 해결되지 않았다.
- 문제를 해결하기 위해 구글링하여 원인을 찾아낼 수 있었다.
- t2.micro의 메모리가 1GB이기 때문에, build 도중 메모리 부족으로 인한 과부하가 발생한다.
- 따라서 test를 제외하고 빌드하거나 인스턴스를 업그레이드하여 메모리를 늘려준다면 해결할 수 있다.
그러나 인스턴스에서 빌드된 jar 파일에 자동 문서화된 REST API 문서가 포함되있기를 원했기 때문에 test를 제외하고 빌드하는 방법은 사용할 수 없었고, 인스턴스를 업그레이드 하기엔 돈이 문제가 됐다. 따라서 다른 해결 방법을 사용해야만 했는데,
1. swap file을 이용하여 메모리를 초과하여 이용해야 할 경우, 인스턴스의 스토리지를 메모리로 사용하는 방법 3
$ sudo dd if=/dev/zero of=/swapfile bs=128M count=32
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ sudo swapon -s
$ sudo vi /etc/fstab
# 열린 파일 끝에 아래 코드를 추가
/swapfile swap swap defaults 0 0
2. test를 포함하여 빌드한 jar 파일을 인스턴스로 전송하는 방법
# 클라이언트 터미널에서
$ scp -i {키페어 파일 위치}/{키페어 파일 이름} {jar 파일 위치}/{jar 파일 이름} ubuntu@ec2-15-165-100-99.ap-northeast-2.compute.amazonaws.com:~/
2. 빌드된 jar 파일을 실행한 뒤, 인스턴스의 퍼블릭 ipv4 주소를 이용해 서버에 요청을 보낼 수 있다.
- http로 서버에 접근할 수 없을 경우 두 가지 문제가 원인일 수 있다.
1. 인바운드 규칙에 해당 IP에서의 http 트래픽 허용 안한 경우
- 모든 IP 주소로부터 http 트래픽을 허용하여 해결
2. 스프링부트 서버가 실행될 포트 번호를 80번으로 설정하지 않은 경우
- application.properties 파일에 다음 코드를 추가하여 해결
server.port=80
3. HTTPS 적용하기
HTTPS를 사용하기 위해서는 도메인 이름이 필요하다.
1. 인스턴스의 퍼블릭 IP 주소는 중지되었다가 시작할 때마다 달라지기 때문에 탄력적 IP 주소를 할당받아 사용하여 고정 IP 주소를 사용할 수 있다.
2. 고정 IP를 할당 받았다면, Route53에서 도메인을 구매하고 해당 IP에 연결하여 사용할 수 있다.
- 사용 가능한 도메인 이름을 검색하고 적절한 도메인을 구매한다.
- 구매가 완료되고 도메인이 등록 된 후, 호스팅 영역->호스팅 영역 상세->레코드 생성
- 레코드 유형으로 A를 선택하고 값에 할당받은 고정 IP 주소를 입력하여 레코드를 생성한다.
- api 서버의 도메인은 "api."으로 시작되는 경우가 많다고 한다.
추가) HTTPS를 사용하기 위해서는 SSL 인증서를 발급하고 설치하는 데 도메인 이름이 필요하지만, 이를 위해 반드시 고정 IP 주소가 필요한 것은 아니다.
- SSL 인증서는 서버와 클라이언트 간의 데이터 전송을 암호화하여 보안을 강화한다. 이 때, 클라이언트가 서버의 신원을 확인할 수 있어야 하고 도메인 이름은 이러한 신원 확인에 사용된다. 따라서 SSL 인증서를 발급받기 위해서는 해당 도메인의 소유권을 인증할 수 있는 방법이 필요하며 이는 도메인 이름이 필요한 이유 중 하나이다.
- AWS에서 ALB를 생성하면 해당 ALB에 대한 고정 DNS name이 자동으로 생성된다. 따라서 Elastic IP를 할당받지 않아도 ALB에 대한 고정 DNS name에 도메인 이름을 연결하고 도메인 이름으로 서버에 접근한다면 동적으로 IP 주소가 변경되는 것은 신경 쓸 필요가 없다.
추가) ELB에 할당되는 DNS name은 DNS에 등록된 FQDN을 의미하며, FQDN은 일반적으로 호스트 이름과 도메인 이름으로 구성된다.
- 예를 들어, "http://www.example.com"에서 "www"는 호스트 이름이고, "example.com"은 도메인 이름이다.
- 호스트 이름은 컴퓨터나 네트워크 장치에 할당된 고유한 이름으로, 호스팅 영역에서 해당 장치를 식별하고 구분하는 데 사용된다.
- "www"는 도메인의 기본 웹 서버를 식별하는 데 관례적으로 사용되는 특정 호스트 이름이다.
- FQDN은 DNS의 A 레코드로 변환되어, 해당 FQDN에 할당된 IP 주소를 지정해야 한다.
- FQDN은 인터넷 상에서 각 장치를 유일하게 식별할 수 있는 완전한 도메인 이름이다.
- 즉, "http://www.example.com"는 엄밀히 말하면 FQDN이지만, 호스트를 식별하는데 사용될 수 있으므로 호스트 이름으로도 볼 수 있다.
- 요즘에는 도메인 이름 자체에도 호스트 이름과 동일한 IP 주소를 참조하는 A 레코드가 있도록 DNS를 구성하는 것이 일반적이므로, 도메인 이름 자체도 FQDN으로 간주될 수 있다.
- Ex) https://google.com 입력 시, https://www.google.com로 연결된다.
3. 로드 밸런서 생성하여 도메인 이름 연결하기
- EC2->로드밸런서->로드 밸런서 생성으로 이동한다.
- HTTP, HTTPS 트래픽을 사용하는 애플리케이션을 위한 로드 밸런서가 필요하므로, Application Load Balancer를 선택한다.
- 네트워킹 매핑의 매핑에서 모든 가용 영역의 체크박스를 선택하고 보안그룹을 생성하여 적용한다.
- SSH와 HTTP 인바운드 트래픽을 허용하도록 설정한 EC2의 보안 그룹과 달리, 모든 IP로 부터의 HTTPS, HTTP 인바운드 트래픽을 허용하도록 설정한다.
참고) 가용 영역
- 하나의 Region은 여러 개의 AZ(Availability Zones)를 가지고 있다(3~6개).
- 각각의 AZ는 분산된 하나 또는 여러 개의 데이터 센터이다.
- 서로 떨어져 있기 때문에, 장애로부터 서로 영향을 받지 않는다.
- 대상 그룹 생성하기를 눌러 로드 밸런서로 들어온 트래픽을 전달할 대상 그룹을 생성한다.
- 대상 유형을 인스턴스로 선택하고 상태 검사를 설정한다.
참고) ELB 상태 검사
- 로드 밸런서가 들어온 요청을 정상 동작하는 EC2 인스턴스가 아닌, 오류가 발생해 요청을 정상적으로 처리할 수 없는 인스턴스로 전달한다면 요청 분배 효율이 매우 떨어질 것이다.
- 따라서 ELB는 주기적으로 대상 그룹에 속한 EC2 인스턴스에 요청을 보내고, 해당 요청에 대한 응답으로 200번대가 돌아오는지 확인하여 서버가 정상 동작하는지 판단한다.
- 즉, 위에서 설정한 상태 검사 경로로 HTTP 요청(GET)을 보내고 응답을 받아 정상 동작하는지 확인한다.
- 해당 경로로 오는 GET 요청을 받아 200번대 응답을 보내줄 컨트롤러를 프로젝트에 추가해야 한다.
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HealthCheckApiController {
@GetMapping("/health")
public ResponseEntity healthCheck() {
return ResponseEntity.ok().body("Success Health Check.");
}
}
- 대상을 대상 그룹에 등록하여 대상 그룹 생성을 마무리하고, 로드 밸런서의 리스너로 대상 그룹을 선택하여 로드 밸런서 생성을 마무리한다.
- 마지막으로 이전에 고정 IP에 도메인을 연결해두었던 레코드를 삭제하고, 로드 밸런서에 연결할 도메인 이름을 입력하고 레코드 생성-> 별칭->Application/Classic Load Balancer에 대한 별칭->Region->로드 밸런서 선택하여 레코드를 생성한다.
추가) Alias 레코드
- 원래 도메인 이름을 다른 도메인 이름으로 매핑하는 데 사용되는 레코드는 CNAME 레코드이나, CNAME 레코드는 Zone Apex(Apex in Zone)에 직접 사용할 수 없고 하위 도메인에 대해서만 CNAME 레코드를 생성할 수 있다. 이러한 문제를 해결하기 위해, AWS Route 53은 Alias 레코드를 제공한다.
- DNS에서 "Zone Apex"는 특정 도메인의 루트를 가리킨다. 각 도메인은 여러 하위 도메인을 가질 수 있으며, 이러한 하위 도메인 중 가장 상위에 있는 것이 Zone Apex이다.
- Ex) "example.com"
- CNAME 레코드와 유사하지만 "example.com"과 같은 Zone Apex와 "www.example.com"과 같은 하위 도메인 모두에 대해 Alias 레코드를 생성할 수 있다.
- Alias 레코드는 CNAME 레코드와 달리 추가적인 네트워크 라우팅 없이 직접 대상에 연결되기 때문에 DNS 조회의 성능을 향상시키고, 요청의 응답 시간을 줄이며, 해당 레코드에 대한 DNS query는 무료이고, 복잡한 구성을 간소화할 수 있다.
- Alias 레코드는 도메인 이름과 AWS resource의 FQDN을 매핑할 수 있으나 EC2 instance의 FQDN과는 매핑할 수 없으며, 사용자가 TTL을 설정할 수 없다.
4. ELB가 HTTPS 트래픽을 받도록 설정하기
- AWS Certificate Manager->인증서 요청->퍼블릭 인증서 요청으로 이동한다.
- 로드 밸런서에 연결한 도메인 이름을 입력하고 인증서를 요청한다.
- 검증 대기중인 인증서의 CNAME 이름과 값을 아이디와 패스워드처럼 이용하여 요청한 본인이 소유한 도메인이 맞는지 검증한 뒤, 발급받을 수 있다.
- ELB의 리스너에 HTTPS를 추가한다.
- 보안 리스너 설정->인증서에 AWS Certificate Manager에서 발급받은 인증서를 적용하여 로드 밸런서의 리스너를 추가한다.
- 기존의 HTTP 리스너를 삭제한 후, HTTPS로 리디렉션하는 HTTP 리스너를 추가하여 마무리한다.
이렇게 스프링부트 서버를 EC2에 배포하고, 서버에 HTTPS를 이용해 접근할 수 있도록 설정할 수 있었다.
4. RDS 연결하기
1. 데이터베이스 생성
- 배포한 스프링부트 서버가 MySQL을 사용하기 때문에 MySQL을 엔진 옵션으로 골랐다.
- 많은 비용이 나가는 것을 원하지 않기 때문에 템플릿으로 프리 티어를 선택했다.
- 배포한 스프링부트 서버에서 사용하도록 설정한 사용자 이름과 비밀번호로 설정한다.
- 범용 SSD 중 최신 버전인 gp3를 스토리지로 선택한다.
- 인스턴스 외부에서도 데이터베이스에 접근할 수 있도록 퍼블릭 액세스를 예로 설정한다.
- 할당된 퍼블릭 IP 주소를 이용해 인스턴스 외부에서도 데이터베이스에 접근할 수 있다.
2. 파라미터 그룹 적용하기
- EC2->보안그룹에서 DB용 보안 그룹을 만들어 설정한다.
- 다른 보안 그룹과 달리, RDS의 MySQL은 default로 3306번 포트에서 실행되므로 3306번 포트를 인바운드 규칙에 추가시켜준다.
- RDS->파라미터 그룹->파라미터 그룹 생성에서 위 화면에 보이는 파라미터들을 utf8mb4로 설정해준다.
- 위 화면에 보이는 파라미터들을 utf8mb4_unicode_ci로 설정해준다.
- time_zone을 Asia/Seoul로 설정해준다.
- 생성한 데이터베이스의 파라미터 그룹을 생성한 파라미터 그룹으로 변경한 뒤 데이터베이스를 재부팅하여 적용해준다.
위 과정이 끝나면 할당받은 데이터베이스의 IP 주소를 이용해 스프링부트 서버와 DB를 연결할 수 있다.
참고) 인스턴스에 MySQL 설치하여 사용하기
- RDS를 이용하기에 가격이 부담스러울 수 있다.
- 이 때는 인스턴스에 MySQL을 설치하여 사용할 수 있다.
$ sudo apt install mysql-server
# 초기 보안 설정
$ sudo mysql_secure_installation
# mysql 시작
$ sudo systemctl start mysql
# or
$ sudo service mysql start
# 서버 재시작 시 MySQL 자동 재시작
$ sudo systemctl enable mysql
# mysql 종료
$ sudo systemctl stop mysql
# or
$ sudo service mysql stop
# 비밀번호 설정
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password by '<비밀번호>';
# 외부 접속 허용
$ sudo ufw allow mysql
$ sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
# 열린 파일에 다음 부분 수정
# bind-address = 127.0.0.1
bind-address = 0.0.0.0
# mysql 접속
$ sudo mysql -u root -p
Enter password: '<비밀번호>'
# mysql exit
mysql> exit
참고 자료
인프런, ⌜비전공자도 이해할 수 있는 AWS 입문/실전⌟, 박재성
Udemy, ⌜Ultimate AWS Certified Solutions Architect Associate SAA-C03⌟, Stephane Maarek
'Cloud engineering' 카테고리의 다른 글
ArgoCD 설치 및 설정 (1) | 2024.09.01 |
---|---|
Terraform 이용해 EKS Cluster 구축하기 (0) | 2024.09.01 |
올리브영 온라인 쇼핑몰 public cloud(AWS) 인프라 구축 프로젝트 (3) | 2024.08.31 |
부하 테스트 및 조회 성능 개선(Ehcache, DB index) (0) | 2024.06.11 |
[ Jenkins ] Jenkins를 이용해 빌드/배포 자동화하기 (0) | 2024.02.15 |