1편에서 리소스를 생성하기 전까지의 스키마를 구성했습니다.
아래 아키텍처를 하나씩 따라가며 리소스를 생성해보겠습니다.
전통적인 웹 애플리케이션 구조는 Web - WAS - DB 3-tier 구조로 되어있습니다. 이때 Web은 Public에, WAS, DB는 Private에 두었습니다. 요즘은 WEB-WAS를 굳이 분리하지 않고 전부 Private 으로 숨기는 구조를 택합니다.
Web Application을 Private 서브넷에 배포한다는 것은 인터넷 망을 통해 접속하는 것을 불가능하게 한다는 것입니다. 그렇다면 이 인스턴스에는 어떻게 접속해서 Application 을 배포하고(ex: jar 배포), 필요한 라이브러리(git, tomcat, apache 등)을 설치할까요?
해답은 위 아키텍처 Public Subnet의 Bastion host에 있습니다
1. Bastion Server(Bastion Host)
Bastion Server는 다른말로는 Jumping Host라고도 하며 인터넷 망에서 프라이빗 리소스에 접근하기 위해 거쳐가는 프록시 서버의 역할을 합니다. 즉, 어떤 특별한 기능을 하지 않고 오직 "거쳐가는 용도"입니다. 1편에서 말했다시피 같은 VPC 내부의 리소스는 서로 Private IP 로 접근가능하기 때문에 Bastion host를 외부망과 연결하고 관리자는 Bastion host에 접속하여 Private 리소스에 재접속하거나 터널링합니다.
Bastion Host가 아키텍처에서 이중화되지 않은 이유는 바로 이것 때문입니다. 애플리케이션에 상관없이 오직 "관리자의 프라이빗 리소스 접근 용도"로만 사용되기 때문에 굳이 이중화하지 않은 것입니다.
Bastion Host를 생성해 보겠습니다.
EC2 > Launch Instance
Step1: AMI 선택
AMI는 인스턴스를 실행할 기본 이미지를 말합니다. OS, 기본 설치 라이브러리 등을 포함할 수 있습니다.
만약 Java가 설치된 Instance를 자주 사용할 것 같다면 사용자 AMI로 만들어 준 뒤 계속 재사용할 수도 있습니다.
여기에서는 Amazon Linux 2 를 선택하겠습니다.
Step2: 인스턴스 타입 선택
인스턴스 타입을 선택합니다. Bastion host이기 때문에 t타입을 사용해도 괜찮을 것 같습니다. 이 포스팅에서는 t2.micro(프리티어)를 사용해도 무방하나 저는 이미 프리티어 기간이 지났기 때문에 t3.micro를 사용하겠습니다.(뒤에 숫자가 더 클수록 최신 버전이며 더 저렴합니다.)
Step3: 인스턴스 구성
기본으로 알아야 할 부분만 보겠습니다.
1. Network
인스턴스가 배치될 VPC를 지정합니다. Name tag 로 찾을 수 있습니다.
2. Subnet
위에서 지정한 VPC의 Subnet 리스트 중 인스턴스를 배치할 서브넷을 지정합니다.
bastion host는 인터넷 망에서 접근해야하기 때문에 public 서브넷에 존재해야합니다. public-a 서브넷을 지정합니다.
3. Auto assigned Public IP
위와 같은 이유로 퍼블릭 아이피를 할당합니다. 여기서 체크하지 않아도 추후 할당할 수 있긴 합니다.
4. IAM role
AWS는 Role 이라는 개념을 통해 리소스 접근을 제한합니다. 즉, 이 인스턴스가 S3에 파일을 추가하게 하려면 S3 put Object 이 가능한 역할을 여기에서 추가해주어야합니다. 역시나 추후에도 추가 가능합니다.
인스턴스에 직접 접속해서 S3 Put Object 이 가능한 사용자의 Access Key, Secret Access Key 를 넣을 수도 있지만 이렇게 키 값을 직접 노출시키는 것은 좋지 못한 방법입니다.
Bastion 서버는 딱히 접근해야하는 AWS 서비스가 없기 때문에 지정하지 않습니다.
Step 4: 스토리지
EBS는 EC2 가 사용할 수 있는 블록 스토리지로 재부팅시에도 보존되는 비휘발성 스토리지입니다. t2, t3 계열은 모두 EBS 최적화 인스턴스이며 이 단계에서 커스터마이징 할 수 있습니다. 변경하지 않고 넘어가겠습니다.
Step 5: 태그
Name Tags는 쉽게 aws-beginner-bastion-a 로 지정하겠습니다.
Step 6. Security Group 세팅
보안그룹은 AWS의 방화벽 서비스 중 하나입니다. 무료이며 인스턴스 단위로 동작합니다.
Allow 정책을 사용하며 이곳에서 지정하지 않은 대역 외는 모두 Deny 합니다. 또, 보안그룹의 아웃바운드는 모두 허용입니다. 따라서 이곳에서 지정한 인바운드 Allow 정책은 곧 Outboud 의 허용을 의미합니다.
Bastion host는 Key 파일로 ssh 접속해야합니다.
My IP 의 22번 포트 접근을 허용합니다.
key 파일을 새로 생성하거나 기존의 것을 사용합니다. 중요한 것은 이런 것들 하나하나가 모두 "관리포인트"라는 것입니다.
인스턴스별로 키파일을 새로 생성하는 것도 돌려쓰는 것도 모두 이런것들을 고려하여 결정해야합니다.
이제 위와 같은 아키텍처가 되었습니다.
2/2 check가 뜨면 Bastion host에 접속해보겠습니다.
+ 새로 생성한 키파일이라면 chmod 400 [pem파일경로].pem 을 통해 읽기 권한을 부여해주세요.
ssh -i [pemfile경로].pem ec2-user@[public-ip]
아마 timeout 에러가 뜰 것 입니다.
public IP 주소도 부여하고 보안그룹도 열어줬는데 왜 접속이 안될까요?
우리는 Public Subnet, Private Subnet 이름만 지정했지 그 어떤 다른 작업도 하지 않았습니다.
여기서 Internet Gateway 개념이 나옵니다. Public Subnet의 조건은 "Internet Gateway"와 연결이 되어있는지 여부입니다.
2. Internet Gateway
인터넷게이트웨이는 VPC의 리소스와 인터넷이 통신할 수 있도록 합니다.
핸즈온 전 흐름부터 파악해보면,
인터넷 게이트웨이는 VPC 에 부착됩니다. 아키텍처의 구름모양 아이콘이 인터넷 게이트웨이를 뜻합니다.
인스턴스는 Subnet 내에 위치합니다. 따라서 서브넷에 붙어있는 "Routing Table" 을 조정해야합니다.
모든요청(0.0.0.0/0)에 대해 Internet Gateway(이하 IGW)로 라우팅 정책을 추가하면 이제 이 서브넷은 Public Subnet이 되고 외부 통신이 가능해집니다.
+ 인터넷 게이트웨이는 무료입니다.
VPC > Internet Gateway > Create Internet Gateway
생성 후 Status를 확인하면 detached 되어있을 것입니다. 이 인스턴스를 선택하고 Action > Attach to VPC 를 선택합니다.
인터넷 게이트웨이 생성을 완료했습니다. 이제 퍼블릭 서브넷으로 가서 라우팅 정책을 추가합니다.
VPC > Subnet
4개의 서브넷 중 두개의 Public Subnet 편집이 필요합니다.
서브넷을 선택하고 하단 디테일의 Route Table 탭을 선택합니다.
자동으로 들어있는 정책이 보이는데, 현 VPC 대역(102.168.0.0/16)으로 오는 요청은 현 서브넷의 어디든(local) 갈 수 있다는 뜻입니다.
즉, 앞에서부터 계속 말한 VPC 내부 자원들은 서로 통신할 수 있다. 라는 의미입니다.
1 편에서 온프레미스 VPN 구성 시 대역이 겹치지 않게 해야한다는 것도 이 라우팅 테이블 때문입니다.
만약 온프레미스의 VPC 대역이 192.168.0.0/16 이면
192.168.0.0/16 -> local
192.168.0.0/16 -> 온프레미스
이렇게 중복된 라우팅 정책이 생기게 됩니다.(사실 저렇게 생성도 할 수 없게 에러가 납니다)
우리는 한번도 라우팅 테이블을 생성한 적이 없기 때문에 VPC 내부의 모든 서브넷은 동일한 라우팅 테이블을 가지고 있습니다.
Public Subnet용 라우팅테이블을 만들고 Public 서브넷에 Assoticate 하겠습니다.
VPC > Routing Table > Create Routing Table
Name tag, VPC 를 차례로 지정합니다.
생성한 Routing 테이블의 Route 탭 > Edit Route 를 통해 IGW 와의 라우팅을 허용해줍니다.
이제 이 라우팅 테이블의 Subnet Associations 탭에서 Public Subnet 두개를 추가해줍니다.
인터넷 통신을 위한 모든 설정을 마쳤습니다.
다시 아래 명령을 통해 bastion host에 접속해봅니다.
ssh -i [pemfile경로].pem ec2-user@[public-ip]
접속에 성공하였습니다.
이제 아래와 같아졌습니다.
다음은 애플리케이션을 배포할 인스턴스를 생성하겠습니다.
애플리케이션의 특징 몇가지를 고민해봅니다.
1. 사용자 접속 수가 늘 일정한지?
2. 서버가 다운되어도 크게 치명적인 서비스는 아닌지?
위와 같은 경우라면 인스턴스는 굳이 Scale Out 또는 Scale Up 될 필요가 없습니다.
예측 가능하기 때문에 딱 그만큼의 기능만 충족하는 인스턴스의 개수, 스펙만 사용하면 되기 때문이죠.
하지만, 보통의 B2C 애플리케이션은 그렇지 않습니다.
고객의 접속량을 "정확하게 예측"하는 것은 쉽지 않고, 늘 트래픽 부하에 대비해야합니다.
이때 등장하는 개념이, AutoScaling Group 입니다.
3. AutoScaling Group
AWS EC2에 트래픽 부하가 발생했을 때, 두가지 해결책이 있습니다.
1. 인스턴스 타입을 스펙업한다.
-> 재기동필요. 어느 한계에 다다르면 비용대비 효과가 높지 않음.
2. 인스턴스 개수를 늘린다.
-> 재기동 필요하지 않음. 비용 2배지만 효과는 인스턴수 개수와 비례함.
어느 것이 정답이라고는 할 수 없겠지만 제 생각엔 1번은 성능테스트, 개발, 테스트 단계 때 적합한 인스턴스 타입을 조정하기 위해 사용하거나 잠시 중단되어도 치명적이지 않은 서비스에 사용할 것 같고 그 외 대부분은 2번 방식을 사용할 것 같습니다.
여기서 2번 인스턴스 개수를 늘린다가 "AutoScaling"에 해당합니다.
AWS는 AutoScaling Group 을 대상으로 트래픽을 분산해주는 LoadBalancing 기능을 제공합니다.
자세한 내용은 리소스를 생성하며 설명하겠습니다.
3-1. Load Balancer
오토스케일링 그룹에 부하를 분산할 목적의 LoadBalancer 를 생성합니다.
아키텍처에서는 다음 그림이 로드밸런서에 해당합니다.
이 예제에서 로드밸런서는 80포트(Http) 요청을 Application 으로 보내주는 역할을 합니다.
Http, Https 요청을 분산해주는 역할을 하는 것이 Application LoadBalancer 인데, 자세한 설명은 아래 게시글에서 확인할 수 있습니다.
https://a1010100z.tistory.com/entry/AWS-AWS-ALB를-통해-웹애플리케이션-접근하기
여기서는 ALB를 사용한다는 사실만 가지고 핸즈온 하겠습니다.
EC2 > LoadBalancers > Create LoadBalancer
Step 0. 로드밸런서 종류 선택
Http 요청을 처리하는 Application LoadBalancer를 선택합니다.
Step 1. 구성
1. Schema
로드밸런서의 인터넷 통신 여부 옵션입니다.
만약 내부 트래픽만 관장하는 로드밸런서라면 internal 을 선택합니다.
이 예제는 인터넷에서 오는 80 요청을 관장하는 목적이기 때문에 internet facing 옵션이 적합합니다.
2. Listener
로드밸런서로 오는 요청 Listener 입니다.
디폴트로 80 포트가 설정되어있는데 하나 이상의 리스너가 있어야 로드밸런서 생성이 되므로 그대로 둡니다.
3. Availability Zone
로드밸런서가 위치할 가용영역을 설정합니다.
로드밸런서는 최소 두개 이상의 가용영역에 존재해야합니다.
예제의 로드밸런서는 internet-facing 이므로 public subnet a, public subnet c 를 지정해줍니다.
Step 2. 보안설정은 Https 사용시에만 해당됩니다. 넘어갑니다
Step 3. 보안그룹 설정
이 애플리케이션은 모든 사용자가 이용할 수 있다고 가정합니다.
80포트 접근을 anywhere로 열어줍니다.
Step 4. Target Group 설정
로드밸런서가 요청을 분산할 대상그룹을 설정합니다.
대상그룹 설정의 자세한 설명은 위 링크에서 대신합니다.
여기서는 8080포트로 요청을 전송하니 애플리케이션 배포는 8080 포트로 해야함을 인지하고 넘어갑니다.
Step 5. 대상등록 -> 아직 등록할 대상(오토스케일링그룹)을 생성하지 않았습니다. 비워두고 로드밸런서를 생성합니다.
로드밸런서 생성을 완료하였습니다. 이제 오토스케일링 그룹을 만들기 위해 시작구성(Launch Configuration)을 생성합니다.
3-2. Launch Configuration
AutoScaling Group은(이하 ASG) Launch Configuration 을 기반으로 생성됩니다.
Launch Configuration 을 생성하기 전에 이 설정에 추가할 보안그룹을 먼저 생성하겠습니다.
EC2 > Security Group > Create Security Group
애플리케이션 서버에 접속해서 Java를 깔든 무엇을 깔기 위해서는 SSH 접속을 해야합니다.
그리고 이 접속은 Bastion Server 를 통해 이루어집니다.
또, 오토스케일링 그룹은 위에서 생성한 로드밸런서에서 오는 8080의 요청을 허용해야합니다.
즉, 이 서버의 보안그룹은 다음을 의미해야합니다.
"Bastion Server 로 부터 오는 SSH 접근, LoadBalancer로부터 오는 8080접근을 허용하라"
위 내용은 다음과 같이 작성할 수 있습니다.
물론 bastion server의 IP를 지정해도 되지만, IP는 가변적이고 직관적이지 않습니다.
그렇기 때문에 위와 같이 보안그룹의 아이디로 작성하는 것을 권장합니다.
Bastion server의 보안그룹 아이디는 EC2 > Security Group 의 상세 탭에서 확인할 수 있습니다.
LoadBalancer의 보안그룹 아이디도 LoadBalancer 의 상세 탭에서 확인 가능합니다.
이제 Launch Configuration 을 만들겠습니다.
EC2 > AutoScaling Group 구분 > Launch Configuration > Create launch configuration
1. AMI 선택
여기서 설정한 AMI를 기반으로 ASG의 인스턴스가 생성됩니다. Amazon Linux 2를 지정하겠습니다.
2. 인스턴스 타입 선택
이 타입의 인스턴스가 생성됩니다. 프리티어(t2.micro)를 선택해도 되지만 저는 t3.small 을 선택하겠습니다.
3. 세부사항
Bastion Server 생성 시 봤던 설정화면과 유사합니다. 아래 설정만 짚고 넘어가겠습니다.
Advanced Details > IP Address Type
애플리케이션 서버는 프라이빗 서브넷에 위치합니다. 따라서 default VPC 인 경우에면 public IP 를 부여하는 첫번째 옵션 또는 아예 부여하지 않는 세번째 옵션을 선택합니다.
4. Add Storage 는 패스
5. Security Group
여기에서 Security Group 을 생성하면 Default VPC 로 지정되기 때문에 bastion server의 보안그룹 id 를 지정할 수 없습니다.
사전에 만들어둔 asg 용 security group을 지정합니다.
key pair 까지 확인하면 Launch Configuration 설정을 완료합니다.
3-3. AutoScaling Group
위에서 만든 시작구성을 기반으로 오토스켕일링 그룹을 생성합니다.
EC2 > AutoScaling Group > Create AutoScaling Group
AutoScaling Group 은 Launch Configuration 잉나 Launch Template 을 기반으로 만들 수 있습니다.
시작 템플릿은 더 세세한 설정이 가능하게 최근 생긴 옵션인데 앞에서 시작 구성을 만들었기 때문에
Launch Configuration, aws-beginner-asg-lanchconfiguration 을 선택하겠습니다.
Step 1. 구성 설정
1. Subnet
VPC 는 aws-beginner-vpc 로 선택합니다.
서브넷은 오토스케일링 시 인스턴스가 생성될 서브넷을 지정합니다.
애플리케이션은 private 서브넷에서 시작하기 때문에 private-subnet-a, private-subnet-c 를 지정합니다.
2. Advance Details
이곳에서 현재의 오토스케일링 그룹이 앞서 만든 로드밸런서 타겟 그룹임을 지정합니다.
Receive traffic one or more loadbalancers 옵션을 체크한 뒤, 로드밸런서 생성 시 만든 타겟 그룹을 Target Groups 에 지정합니다.
Step 2. 오토스케일링 정책
이 단계에서는 오토스케일링의 정책을 수립합니다.
CPU 이용률과 같은 정책을 수립할 수 있는데 수동으로 오토스케일링을 할 것이기 때문에 Keep this group at its initial size 옵션을 지정하겠습니다.
이후 단계들은 네임태그만 알아보기 쉽게 지정하고 넘긴 후 오토스케일링 그룹을 생성합니다.
생성이 완료되면 아래 세부사항에서 인스턴스의 상태를 확인할 수 있습니다.
인스턴스가 InService 상태가 되면 이제 인스턴스에 접속하고 LoadBalancer 의 정상 동작을 확인하겠습니다.
ASG의 인스턴스는 프라이빗 서브넷에 있습니다. 따라서 Bastion Server를 통해 터널링하거나 Bastion Server에 접속하여 다시 접속해야합니다.
후자의 경우 pem 파일을 sftp 전송해야하는 번거로움이 있기 때문에 터널링하여 접속하겠습니다.
sudo ssh -i [키파일 경로].pem -L 22:[asg인스턴스 private ip]:22 ec2-user@[bastion 서버 public ip]
터널링은 반드시 sudo 권한으로 실행해야합니다.
-L 은 로컬 터널링을 의미하는데 22번 포트로 오토스케일링그룹 인스턴스의 프라이빗인스턴스의 22번포트로 접속을 하는데 로컬을 터널로 뚫겠다는 의미입니다. 그리고 그 기반은 bastion 서버입니다.
정상적으로 Bastion 서버에 접속이 되면 새 터미널을 열고 아래와 같이 로컬 22번 포트로 접속을 시도하면
sudo ssh -i [key 파일 경로].pem ec2-user@127.0.0.1
오토스케일링 그룹 인스턴스에 접속에 성공합니다.
이 인스턴스는 두가지 작업이 필요합니다.
1. 외부 레포지토리에서 소스코드 불러와서 빌드
2. java 설치후 jar 배포
그런데 프라이빗 서브넷은 인터넷 게이트웨이와 연결되어있지 않기 떄문에 위 작업을 수행할 수 없습니다.
이때 등장하는 것이 NAT Gateway 입니다.
4. NAT Gateway
어떤 인스턴스는 인터넷망을 통해 들어오는 것은 차단하고 인터넷으로 요청을 보낼 필요가 있습니다.
즉, 인바운드는 차단. 아웃바운드만 허용하는 것입니다.
그때 사용하는 것이 NAT Gateway 입니다.
프라이빗 서브넷의 애플리케이션 서버(여기서는 ASG 인스턴스)는 인터넷에서 인바운드되어서는 안되지만 jdk, 소스코드 다운을 위해 아웃바운드할 필요는 있습니다.
즉, NAT Gateway 가 필요합니다.
NAT Gateway를 만들기 전에 흐름을 먼저 파악하면,
NAT Gateway 는 인터넷과 직접 통신할 필요가 있기 때문에 Public Subnet에 위치해야합니다.
그리고 ASG 인스턴스는 이 NAT Gateway를 통해 인터넷에서 특정 소스를 받아와야 하기때문에 라우팅테이블 조정이 필요합니다.
사전에 말한것처럼 라우팅테이블은 서브넷단위이기 때문에 Private Subnet의 라우팅테이블을 조정해야합니다.
+ NAT Gateway 는 생성시간도 소요되고 비용도 청구됩니다.
VPC > NAT Gateways > Create NAT Gateway
간단하기 때문에 설명은 사진으로 대체합니다. 이제 NAT Gateway 를 Public subnet에 위치시켰으니 Private subnet의 라우팅 테이블을 조정합니다.
VPC > Route Tables > Create Route table
IGW 와 비슷합니다.
Private Subnet으로 오는 모든 요청을 NAT Gateway 로 보내는 설정을 추가한 뒤 저장합니다.
그 후, Subnet Associations 옵션에서 아래처럼 private subnet 두개를 추가한 뒤 저장합니다.
이제 다시 asg 인스턴스로 가서 다음의 명령어를 수행해봅니다.
sudo yum update -y
sudo yum install -y java-1.8.0-openjdk-devel.x86_64
java -version
그리고 다음의 소스코드를 다운받고 빌드합니다.
8080포트로 실행가능한 샘플 스프링부트 프로젝트입니다. 소스코드 다운을 위해 git 도 설치합니다.
sudo yum install -y git
git clone https://github.com/csbsjy/hello-spring.git
cd hello-spring
./gradlew clean build
빌드가 완료되었으면 다음 명령어로 배포합니다.
nohup java -jar build/libs/example-0.0.1-SNAPSHOT.jar &
curl -XGET localhost:8080/sys/healthCheck
curl -XGET localhost:8080/home
배포가 다 되었다면 이제 ALB와 정상 연결이 되었는지 확인하겠습니다.
EC2 > LoadBalacner 의 상세 탭에서 DNS name을 복사합니다
DNS/home 으로 접속하면 정상 배포됨을 확인할 수 있습니다.
애플리케이션을 오토스케일링 그룹에 배포하고 로드밸런서를 연결하는 것까지 완료하였습니다.
현 아키텍처는 다음과 같습니다.
마지막 포스팅에서는 RDS 세팅과 AutoScaling Test 를 하겠습니다.
'스터디 > 인프라' 카테고리의 다른 글
Amazon SQS 사용법 (0) | 2020.05.31 |
---|---|
[AWS] Amazon Web Service 왕초보 탈출하기 [3] - RDS 편 (1) | 2020.03.23 |
[AWS] Amazon Web Service 왕초보 탈출하기 - [1] Region, AZ, VPC, Subnet 편 (2) | 2020.02.24 |
Github Webhook(+generic webhook trigger plugin)과 Jenkins, CodeDeploy 를 사용하여 CI/CD 구축하기 (0) | 2020.02.03 |