이 앱에 대한 솔루션 아키텍트를 해보자!!!
PoC(Proof of Concept)란?
어떤 아이디어나 기술이 실제로 구현 가능하고 작동할 수 있는지 검증하는 과정 또는 시제품
📃첫번째 PoC:
Public t2.micro 인스턴스 하나에 탄력적 IP를 연결하여 사용자가 시간을 물어보면 인스턴스에서 답하기
⬇
사용자가 증가했다!
t2.micro인스턴스를 더 큰 것으로 교체(수직 확장) -> m5.large 인스턴스로 교체
교체하기 위해 인스턴스 중지하고 유형을 바꾸고 다시 인스턴스 시작하여 다운타임이 발생함.
⬇
사용자가 증가했다!
수평확장을 위해 m5.large EC2 인스턴스 2개를 추가한다. 총 3개의 EC2인스턴스들은 모두 각각의 탄력적IP에 연결되어 있다.
👉🏻 따라서 사용자들이 인스턴스와 통신하려면 세 개의 탄력적 IP의 정확한 값을 알고 있어야 한다.
⬇
IP가 너무 많아 탄력적 IP를 제거한다!
한 계정에서 리전마다 최대 5개의 탄력적 IP를 가질 수 있다.
관리하기 힘든 탄력적IP는 없애고 Route 53을 활용하겠다. 웹사이트의 URL은 api.whatisthetime.com이다.
TTL이 한 시간인 A레코드로 정하여 3개 EC2의 IP 리스트를 제공할 것이다.
⬇
상황에 따라 인스턴스 수를 조절하고 싶다!
현재 상태에서 스케일 인을 위해 EC2인스턴스 하나를 지우면 TTL이 한 시간이라 해당 EC2인스턴스가 캐시되어있는 클라이언트들은 한 시간 동안 사용을 못한다.
그래서 이제는 Public EC2 인스턴스들 대신 Private EC2 인스턴스들을 사용한다.
이들을 같은 AZ에서 수동으로 실행했다.
ELB 하나를 생성해서 프라이빗 EC2인스턴스들을 대상그룹으로 연결하고 EC2인스턴스들의 보안규칙을 수정해 ELB의 인바운드만을 허용하도록 한다.
이제 사용자들은 Route53에 URL을 쿼리해도 로드밸런서가 IP주소를 지속적으로 바꾸기 때문에 A레코드 대신 별칭 레코드로 Route53이 ELB를 가르키게 한다.
이제 ELB의 상태확인 때문에 다운타임도 없을 것이다.
⬇
수동으로 인스턴스 추가 제거는 좀 아닌 것 같다!
이제 ASG을 사용해 오토 스케일링 할 것이다. Private EC2 인스턴스들을 하나의 ASG와 연결한다.
ASG가 자동으로 요청에 따른 확장과 축소를 수행한다.
⬇
AZ가 다운되었다!
ELB에서 다중 AZ를 사용해야겠다. 사용중인 ELB 하나를 AZ 1~3에 적용한다.
사용중이던 ASG 하나도 다중AZ에 걸쳐있게 한다.
이제 높은 가용성을 확보하고 장애 발생에도 대비할 수 있다.
⬇
이제는 비용을 줄이고싶다!
두 개의 AZ에 각각 하나씩 총 2개의 EC2인스턴스는 1년 내내 실행 중일 것이다.
비용을 줄이기 위해 용량을 예약해보자. 인스턴스가 확장될 때 생기는 온디맨드 비용은 요청량에 따른 확장이라 감당할 수 있다.
비용절감은 스팟 인스턴스를 사용할 수도 있지만 이는 인스턴스를 종료시킬 수 있으니 위험하다.
비용, 성능, 신뢰성, 보안, 운영에서 탁월해야 한다!!
📃초기 PoC는 WhatIsTheTime.com의 최종 상태와 동일
Route53,세 개의 AZ, 다중AZ ELB/ASG
사용자가 ELB를 통해 EC2인스턴스1에서 장바구니를 생성했는데, 다음 요청은 EC2인스턴스2로 가면 장바구니가 사라짐.
고로 ELB에서 고정세션(ELB Stickiness)을 활성화해야함.
그러면 같은 EC2인스턴스로의 연결이 고정세션에서 설정한 기간동안 유지됨.
👉🏻 하지만 EC2인스턴스가 어떤 이유로든 종료되면 장바구니가 사라짐.
⬇
사용자 쿠키를 사용해 장바구니를 저장하자!
EC2인스턴스가 장바구니를 저장하는 대신 사용자 쪽에서 장바구니를 저장한다. 그러면 사용자가 직접 EC2인스턴스로 장바구니 내용을 보내주기 때문에 EC2에서는 장바구니를 저장할 필요가 없어진다.
이제 무상태를 달성했지만 HTTP 요청이 점점 더 무거워진다. 장바구니에 뭔가를 추가할수록 사용자는 점점 더 많은 데이터를 HTTP 요청으로 보내게 된다.
또한 쿠키가 공격자에 의해 변경됨으로써 사용자의 장바구니가 수정될 위험도 있다.
👉🏻 이런 아키텍처에서는 EC2인스턴스가 반드시 사용자 쿠키의 내용을 검증해야 한다.
또 전체 쿠키의 크기는 4KB 이하까지만 가능해 대량의 데이터 셋을 저장할 수 없다.
⬇
서버 세션 개념을 도입해보자!
전체 장바구니를 웹 쿠키로 보내는 것이 아닌 단순히 사용자의 세션ID만 보낸다.
백그라운드에는 ElastiCache 클러스터가 존재한다.
과정: 사용자가 세션 ID와 장바구니에 담을 물건을 전송 -> EC2는 세션ID-장바구니 물건을 key-value 형식으로 ElastiCache에 추가
사용자가 다른 EC2인스턴스로 세션ID와 함께 두 번째 요청을 보내면 EC2인스턴스는 세션ID로 ElastiCache에서 장바구니 내용을 불러올 수 있다.
ElastiCache는 매우 빨라 성능도 좋아진다.
공격자들은 ElastiCache의 내부를 수정할 수 없기 때문에 훨씬 안전해진다.
*ElastiCache 외에 DynamoDB로 세션 데이터를 저장할 수도 있다.
⬇
사용자 데이터를 저장하기 위한 DB연결을 해보자
RDS 하나를 생성해서 DB를 관리하자.
EC2인스턴스들은 사용자 데이터를 저장하거나 불러오기 위해 해당 RDS와 통신할 것이다.
⬇
사용자가 늘어난다!
사용자들이 대부분의 시간을 웹사이트를 둘러보며 읽기 요청을 수행한다는 것을 알게된다.
그렇다면 세가지 패턴을 생각해보자
⬇
DB의 장애에 대비하자!
RDS 또한 다중AZ 기능이 있으므로 설정해준다.
Redis를 사용한다면 ElastiCache도 다중AZ 기능을 가진다.
⬇
서비스간의 보안 그룹을 설정하자!
ELB는 어느 쪽에서나 HTTP HTTPS 트래픽을 열 수 있다.
EC2인스턴스 측면에서는 로드밸런서로부터 오는 트래픽만 허락한다.
ElastiCache, RDS 측면에서는 EC2 보안 그룹으로부터 오는 트래픽만 허락한다.
이 아키텍처는 프레젠테이션(클라이언트), 애플리케이션(웹), 데이터(데이터베이스) 3가지 계층으로 분리된 3티어 아키텍처(3-Tier Architecture) 구조이다.
비용은 좀 더 들겠지만 아키텍처 관련 결정을 할 때 도움이 되는 것들을 얻을 수 있다.
📃초기 PoC는 앞서 구성한 3-Tier 아키텍처
백엔드에 RDS가 있는 계층, 다중 AZ
정말 크게 확장하고싶다면 이 계층을 Aurora MySQL로 교체한다. 다중 AZ, 읽기 전용 복제본, 글로벌 데이터베이스까지 적용할 수 있다. 고로 연산을 줄일 수 있다.
⬇
이미지 저장은 어떻게 할까
하나의 EC2 인스턴스에 하나의 EBS가 연결된 상태에서는 이미지는 EBS에 저장되고 불러올 때도 EBS에서 불러온다.
이것은 EC2 인스턴스 하나로만 서비스를 작동시킬 때는 아무 문제가 없다.
하지만 확장되기 시작하면 문제가 생긴다.
EFS, 즉 네트워크 파일 시스템을 사용한다. EFS는 각각의 AZ에 탄력적인 네트워크 인터페이스인 ENI를 생성한다. 이 ENI는 EFS 드라이브에 접근하는 모든 EC2에 사용할 수 있다. 이로써 하나의 스토리지가 모든 인스턴스에게 공유된다.
어떻게 EC2 인스턴스에 애플리케이션을 설치하고 배포하는 것을 빠르게 할까?
EC2 인스턴스에서는 Golden AMI를 사용할 수 있다.
애플리케이션과 OS 종속성 등 모든 것을 사전에 설치하고 그것으로부터 AMI를 생성하는 것이다.
이후로는 EC2인스턴스를 Golden AMI로부터 직접 실행하면 되어 가장 빠르게 실행할 수 있고 부트스트래핑보다 빠르다.
Elastic Beanstalk는 AMI를 구성하고 UserData를 추가하는 하이브리드 원칙을 적용한다.
데이터베이스와 스토리지는 DB 스냅샷과 EBS 스냅샷을 사용해 빠르게 복구할 수 있다.
1) 개발 목적에 적합한 단일 인스턴스
탄력적 IP를 가진 EC2인스턴스가 하나 있다. (잠재적으로 RDS 등을 생성할 수 있지만 이는 모두 하나의 인스턴스와 탄력적 IP를 기반으로 한다.)
2) 고가용성 모드
: 로드밸런서, 오토스케일링 그룹 및 여러 AZ에서 관리되는 하나 이상의 EC2인스턴스가 생성된다. 로드를 분산시킬 수 있으며 이는 프로덕션 환경에 적합하다. 마스터, 스탠바이 인스턴스를 가진 Muli-az RDS 데이터베이스를 가질 수도 있다.
웹서버 , 작업자 환경 중에 고른다.
👉🏻 웹 사이트를 실행하길 원하면 웹 서버환경 선택
👉🏻 대기열에서 오는 작업을 처리하려 한다면 워커 환경 선택
어플리케이션 이름을 입력한다.
환경 정보를 설정한다. (환경 이름, 도메인 이름을 설정한다. 해당 도메인으로 웹 서버에 엑세스할 것이다.)
플랫폼을 선택한다.(스프링부트면 JAVA, 도커이미지면 Docker 등등..)
애플리케이션 코드는 샘플애플리케이션, 직접 코드 업로드 중에 선택한다.

프리셋을 설정한다.
1) 싱글인스턴스 (프리티어, 스팟인스턴스 사용 중 선택. 탄력적IP가 자동생성됨 주의)
2) 고가용성 (로드밸런서 포함)
3) 커스텀 설정

Beanstalk이 AWS의 다른 서비스에 접근할 수 있도록 IAM 설정을 해준다.
Role 새로 생성을 선택하면 자동으로 Role이 만들어진다. 내용은 아래와 같다.

Beanstalk이 Trusted entity가 되고 아래 Action의 내용이 Beanstalk에게 허락된다.
그리고 EC2 instance profile에서 만들어질 EC2의 role도 IAM에서 새로 생성하여 적용해준다.

이때 EC2의 권한정책에서 beanstalk을 입력해 WebTier, WorkerTier, MulticontainerDocker를 추가해준다.
이후 내용은 단일 인스턴스를 생성할거라면 다 스킵하고 생성하면 된다.
그러면 생성된 Beanstalk을 통해 이벤트들을 확인할 수 있다.
Beanstalk이 생성되면 배후에서 CloudFormation에서 스택이 생성되고 거기에서 리소스들이 생성되어 같은 이벤트를 확인할 수 있다.
Template를 선택하면 애플리케이션을 생성한 탬플릿을 볼 수 있고,
View in Designer를 선택하면 현재 애플리케이션의 아키텍처를 시각적으로 확인할 수 있다.
Beanstalk이 생성하는 모든 리소스는 배후에서 CloudFormation이 생성한다!
빈스톡이 생성되면 생성할 때 선택했던 인스턴스, 탄력적 IP, 오토스케일링 그룹 등이 자동으로 생성된다. 그리고 생성한 Beanstalk을 선택하면 도메인 이름을 확인할 수 있다.
해당 도메인 이름을 클릭하면 Beanstalk 환경과 EC2의 웹서버에 접속할 수 있다.
Health에서는 EC2인스턴스들의 상태를 확인할 수 있고 Logs에서는 애플리케이션의 로그를 확인할 수 있다.
Monitoring에서 애플리케이션의 모든 메트릭을 확인할 수 있다.
생성한 Beanstalk에서 Upload and deploy를 누르면 어플리케이션의 새 버전으로 파일을 올릴 수 있는데 이것을 올리면 자동으로 배포된다.
Elastic Beanstalk 콘솔 > Configuration에서 환경에 관한 모든 설정을 보고 수정하고 적용할 수 있다.
Elastic Beanstalk 콘솔 > MyApplication에서 Create new enviroment를 선택해 새 환경을 만들 수도 있다.
예를 들어 나의 앱1(개발용)의 환경과 나의 앱2(프로덕션용)의 환경을 만들어 관리할 수 있다.