본문 바로가기
Cloud/AWS

[콘솔과 테라폼 구현] 사용자 > 1000 : 서버와 RDS 이중화, ALB, Read Replica 추가

by 민휘 2023. 10. 22.

단일 EC2와 DB를 사용하는 아키텍처의 문제점

  • 페일오버 없음
  • 이중화 없음
  • EC2 SPOF : EC2에 장애 발생 시 비즈니스 연속성에 바로 영향을 미침

 

이중화 - 다중 AZ, RDS 스탠바이 인스턴스, ELB

  • Multi AZ 서버 구성 : 가용 영역 확장으로 고가용성 확장. 하나의 AZ에서 장애가 발생했을 때 다른 AZ으로 트래픽 이동
  • DB 이중화 : RDS의 복제본을 구성하여 Multi AZ에 구성. RDS의 Multi-AZ 옵션을 enable하면 스탠바이 DB 인스턴스가 생기고, 두 인스턴스는 sync 방식으로 동기화됨.
  • ELB : Multi AZ로 트래픽을 분산하는 부하 분산 서비스. 소프트웨어 기반의 LB이므로 확장성이 높다. 헬스 체크, 스티키 세션, SSL부하 오프로드, 모니터링과 로깅 적용 가능.
  • ALB : L7 로드밸런서. 컨텐츠 path 기반으로 라우팅 가능하다. 컨테이너 기반 앱, 웹 소켓, HTTP2 지원

 

EC2와 RDS 이중화 + ALB 구현 사항

 

자료

  • 하나의 리전에 VPC를 두고, 가용성을 높이기 위해 두개의 가용영역을 사용한다.
  • private 서브넷에 WEB+WAS를 수행하는 EC2와 읽기 복제한 RDS를 생성한다.
  • ALB와 각 리전을 NAT GW로 연결하고, 트래픽이 프록시 서버를 거치도록 설정한다.
  • 위의 아키텍처에서 Route53는 선택사항

 

콘솔 구현

 

1. VPC 생성

  • VPC만 생성
  • 이름 : my-vpc
  • IPv4 CIDR : 172.20.0.0/20
  • IPv6 CIDR 블록 없음
  • 테넌시 기본값

 

2. 서브넷 생성

AZ1의 퍼블릭 서브넷 Web

  • name : my-public-web-subnet-1
  • VPC : my-vpc
  • AZ : ap-northeast-2a
  • IPv4 CIDR : 172.20.1.0/24

 

AZ2의 퍼블릭 서브넷 Web

  • name : my-public-web-subnet-2
  • VPC : my-vpc
  • AZ : ap-northeast-2c
  • IPv4 CIDR : 172.20.2.0/24

 

AZ1의 프라이빗 서브넷 Was

  • name : my-private-app-subnet-1
  • VPC : my-vpc
  • AZ : ap-northeast-2a
  • IPv4 CIDR : 172.20.3.0/24

 

AZ2의 프라이빗 서브넷 Was

  • name : my-private-app-subnet-2
  • VPC : my-vpc
  • AZ : ap-northeast-2c
  • IPv4 CIDR : 172.20.4.0/24

 

AZ1의 프라이빗 서브넷 DB

  • name : my-private-db-subnet-1
  • VPC : my-vpc
  • AZ : ap-northeast-2a
  • IPv4 CIDR : 172.20.5.0/24

 

AZ2의 프라이빗 서브넷 DB

  • name : my-private-db-subnet-2
  • VPC : my-vpc
  • AZ : ap-northeast-2c
  • IPv4 CIDR : 172.20.6.0/24

 

3. Route Tables 생성 및 서브넷 연결

각 서브넷을 위한 라우팅 테이블을 생성한다. VPC는 my-vpc를 선택한다. 각 라우팅 테이블에 관련 서브넷을 연결한다.

  • my-public-web-route-table-1 : my-public-web-subnet-1
  • my-public-web-route-table-2 : my-public-web-subnet-2
  • my-private-app-route-table-1 : my-private-app-subnet-1
  • my-private-app-route-table-2 : my-private-app-app-2
  • my-private-db-route-table-1 : my-private-db-subnet-1
  • my-private-db-route-table-2 : my-private-db-subnet-2

 

4. Internet Gateway 생성

  • 생성 시 name : my-internet-gateway
  • 생성 후 my-vpc에 연결

 

5. NAT Gateway 생성 및 라우트 테이블 수정

 

AZ1에 NAT GW 생성

  • 이름 : my-nat-gateway-1
  • 서브넷 : my-public-web-subnet-1
  • 연결 유형 : 퍼블릭
  • 탄력적 IP 할당

 

my-public-web-route-table-1에 라우팅 추가

  • dest : 0.0.0.0/0
  • target : my-internet-gateway

 

my-private-app-route-table-1에 라우팅 추가

  • dest : 0.0.0.0/0
  • target : my-nat-gateway-1

 

my-private-db-route-table-1에 라우팅 추가

  • dest : 0.0.0.0/0
  • target : my-nat-gateway-1

 

AZ2에 NAT GW 생성

  • 이름 : my-nat-gateway-2
  • 서브넷 : my-public-web-subnet-2
  • 연결 유형 : 퍼블릭
  • 탄력적 IP 할당

 

my-public-web-route-table-2에 라우팅 추가

  • dest : 0.0.0.0/0
  • target : my-internet-gateway

 

my-private-app-route-table-2에 라우팅 추가

  • dest : 0.0.0.0/0
  • target : my-nat-gateway-2

 

my-private-db-route-table-2에 라우팅 추가

  • dest : 0.0.0.0/0
  • target : my-nat-gateway-2

 

6. public subnet에 jump server (Bastion Server) 구현

바스티온 서버는 외부 네트워크에서 퍼블릭 서브넷에 위치한 서비스에 접근하기 위해 반드시 거쳐가야 하는 일종의 프록시 서버 역할을 한다.

 

AZ1에 점프 서버 EC2 구현

  • name : my-jump-server-1
  • AMI : Amazon Linux 2
  • 인스턴스 유형 : t2.micro
  • 키 페어 사용
  • VPC : my-vpc
  • 서브넷 : my-public-web-subnet-1
  • 퍼블릭 IP 자동 할당 : 활성화
  • 보안그룹 : my-jump-server-sg, any where TCP만 허용
  • 스토리지 : 8GiB

 

AZ2에 점프 서버 EC2 구현

  • name : my-jump-server-2
  • AMI : Amazon Linux 2
  • 인스턴스 유형 : t2.micro
  • 키 페어 사용
  • VPC : my-vpc
  • 서브넷 : my-public-web-subnet-2
  • 퍼블릭 IP 자동 할당 : 활성화
  • 보안그룹 : my-jump-server-sg, any where TCP만 허용
  • 스토리지 : 8GiB

 

7. PHP 서버 구현

 

AZ1에 PHP 서버 EC2 구현

  • name : my-php-app-server-1
  • AMI : Amazon Linux 2
  • 인스턴스 유형 : t2.micro
  • 키 페어 사용
  • VPC : my-vpc
  • 서브넷 : my-private-app-subnet-1
  • 퍼블릭 IP 자동 할당 : 비활성화
  • 보안그룹 : my-php-app-server-sg, my-jump-server-sg로부터 오는 SSL 허용
  • 스토리지 : 8GiB
  • 사용자 데이터 (user data) : 아파치, php, phpMyAdmin 앱 설치
#!/bin/bash
sudo yum update -y
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd

sudo chown -R ec2-user:apache /var/www
sudo chmod 2775 /var/www && find /var/www -type d -exec sudo chmod 2775 {} \;
find /var/www -type f -exec sudo chmod 0664 {} \;

sudo amazon-linux-extras enable php7.4
sudo yum install php-cli php-common php-gd php-mbstring  php-mysqlnd php-fpm php-xml php-opcache php-zip
sudo systemctl restart httpd
sudo systemctl restart php-fpm
cd /var/www/html
wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz
mkdir phpMyAdmin && tar -xvzf phpMyAdmin-latest-all-languages.tar.gz -C phpMyAdmin --strip-components 1
rm phpMyAdmin-latest-all-languages.tar.gz
echo "PHP Server 1" > index.html

 

 

AZ2에 PHP 서버 EC2 구현

  • name : my-php-app-server-2
  • AMI : Amazon Linux 2 혹은 my-php-app-server-1의 AMI를 생성해서 이거 사용
  • 인스턴스 유형 : t2.micro
  • 키 페어 사용
  • VPC : my-vpc
  • 서브넷 : my-private-app-subnet-2
  • 퍼블릭 IP 자동 할당 : 비활성화
  • 보안그룹 : my-php-app-server-sg
  • 스토리지 : 8GiB
  • 사용자 데이터 (user data) : 아파치, php, phpMyAdmin 앱 설치 (생성한 AMI 사용했다면 생략)
#!/bin/bash
sudo yum update -y
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd

sudo chown -R ec2-user:apache /var/www
sudo chmod 2775 /var/www && find /var/www -type d -exec sudo chmod 2775 {} \;
find /var/www -type f -exec sudo chmod 0664 {} \;

sudo amazon-linux-extras enable php7.4
sudo yum install php-cli php-common php-gd php-mbstring  php-mysqlnd php-fpm php-xml php-opcache php-zip
sudo systemctl restart httpd
sudo systemctl restart php-fpm
cd /var/www/html
wget https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz
mkdir phpMyAdmin && tar -xvzf phpMyAdmin-latest-all-languages.tar.gz -C phpMyAdmin --strip-components 1
rm phpMyAdmin-latest-all-languages.tar.gz
echo "PHP Server 2" > index.html

 

 

바스티온 서버를 통해 프라이빗 앱 서버 접근

  • 로컬에서 바스티온 서버 ssh로 접속 확인
  • 로컬에서 scp 명령어로 private 서브넷 pem 키를 바스티온 서버로 올리기 : scp -i [Bastion-EC2키페어경로] [업로드할파일] [user id]@[ec2 public IP]:[저장경로]
  • 로컬에서 바스티온 서버 ssh로 접속 후 ssh로 프라이빗 ip로 앱 서버 접속 확인
  • 프라이빗 서버에서 curl http://localhost로 서버가 잘 떴는지 확인

 

8. ALB 생성 및 설정

 

ALB 생성

  • name : my-alb
  • 보안 그룹 : my-alb-sg, Anywhere HTTP 허용
  • 네트워크 매핑
    • VPC : my-vpc
    • ap-north-east-2a : my-public-web-subnet-1
    • ap-north-east-2c : my-public-web-subnet-2
  • 타겟 그룹
    • 이름 : my-alb-php-tg
    • 대상 유형 : 인스턴스
    • IP 주소 유형 : IPv4
    • HTTP:80
    • HTTP1
    • 상태검사 : HTTP, /
    • 등록 대상 : my-php-app-server-1, my-php-app-server-2
  • 리스너 HTTP:80 my-alb-php-tg로 전달

 

my-php-app-server-sg 설정

  • 인바운드 룰에 my-alb-sg HTTP 허용

 

실행 결과!

 

9. RDS Multi AZ 배포

 

DB 서브넷 그룹 생성

  • 이름 : my-db-subnet-group
  • VPC : my-vpc
  • 가용영역 추가 : ap-northeast-2a, ap-northeast-2c
  • 서브넷 추가 : my-private-db-subnet-1, my-private-db-subnet-2

 

DB 인스턴스 생성

  • 생성 방식 : 표준
  • 엔진 : MySQL
  • 템플릿 : 프로덕션
  • 가용성 및 내구성 : 다중 AZ DB 인스턴스
  • 이름 : my-db
  • DB 인스턴스 : db.m6g.large
  • 스토리지 : 프로비저닝된 IOPS SSD (싱크를 위해 동기식 복제가 자주 일어나므로)
  • 네트워크 유형 : IPv4
  • VPC : my-vpc
  • DB 서브넷 그룹 : my-db-subnet-group
  • 퍼블릭 액세스 : 아니요
  • 보안그룹 : my-db-sg

 

DB sg에 App 인바운드 허용

  • 인바운드 룰에 my-php-app-server-sg 3306 허용

단일 인스턴스를 생성하는 것과 비교했을 때 비용이 두배로 측정된다. 실습 마치고 빠르게 삭제하자…

 

10. PHP 애플리케이션에 RDS 연결

app 서버에 접속해 /var/www/html/phpMyAdmin의 config.sample.inc.php 파일명을 config.inc.php로 변경한다. vi 편집기로 host 경로를 localhost에서 DB 도메인 이름으로 변경한다. 그 후 alb도메인/index.php로 접속하고 DB 마스터 아이디와 암호로 로그인하면 다음과 같이 php 애플리케이션에서 DB로 접속할 수 있다.

 

11. RDS 읽기 전용 복제본 추가

읽기 전용 트래픽만을 지원한다. 원본 데이터베이스로부터 비동기식 복제로 방식으로 동기화되므로 프로비전 IOPS 설정으로 생성하는 것이 좋다. 나중에 읽기 트래픽이 많아지거나 분석용 애플리케이션이 추가되면 읽기 전용 복제본으로 트래픽을 보내도록 설정한다.

 

테라폼 구현

코드 양이 많아서.. 깃허브 참고!

https://github.com/Mingadinga/2023_Study_Evolving_AWSArchitecture_Terraform/tree/main/step3

 

 

테라폼 코드로 인프라를 프로비저닝한 후, PHP 서버에 접속해 host를 db로 수정한다.

  • cd /var/www/html/phpMyAdmin
  • sudo vi config.inc.php → host에 db 도메인