여기서 다루는 내용
· EC2 인스턴스를 사는 여러가지 방법
· EC2 Fleet의 기본 개념
· EC2 Fleet 구성 데모
· 마치며
AWS에서 EC2 인스턴스같은 물건을 싸게 쓰려면?
안녕하십니까, GS네오텍 최준승입니다.
오늘 포스팅에서는 "EC2 Fleet"이라는 것을 소개드릴 참입니다.
여러분의 시간은 너무 소중하기 때문에, 제가 포스팅을 작성하기 전에 항상 감안하는 명제가 있습니다.
- 전달의 효율성을 생각하면 내용이 많으면 안됩니다
- 전달하는 내용이 너무 적으면 정보로서의 효용이 떨어집니다
보통 이 두가지 사이에서 균형을 잡아야 하는데, 오늘은 아무리 와꾸를 바꿔봐도 균형이 잡히지 않습니다.
그래서 오늘은 균형을 포기하고 그냥 포스팅을 길게 할 예정입니다. 양해해 주시면 좋겠어요.
클라우드의 기본 특성은 쓴만큼 지불하는 종량제입니다.
예를 들어 1) 서울 리전에서 2) Linux로 된 3) m5.large 인스턴스를 4) 한시간동안 쓰면 100원정도 합니다.
문제는 이 동일한 상품을 on demand로 쓰느냐, spot으로 쓰느냐, RI로 쓰느냐에 따라 가격이 달라집니다.
공산품도 마찬가지죠. 저희집 애가 하루에 4개씩 먹는 파x퇴x 우유로 치면, 옥x에서 사나 지xx에서 사나 동일한 상품입니다.
하지만 판매자나 구매방식에 따라 가격은 다르죠. 저는 물론 갑부가 아니니 최저가로 검색해서 삽니다.
AWS도 마찬가지입니다. 판매자는 모두 같지만, 같은 상품을 싸게 쓸 수 있는 방법이 있습니다.
선약정을 걸면 깎아주는 RI, 경매 방식으로 잔여 인스턴스를 잡아오는 spot 까지 일부 단점을 감수한다면 싸게 쓸 수 있습니다.
이 부분까지 설명하면 글이 너무 길어지기 때문에, 관련 정보가 필요하시면
여기를 참조하세요.
오늘 주제인 EC2 Fleet은 spot 인스턴스 중심으로 多량의 인스턴스를 한꺼번에 만들거나.. (필요하다면) 유지해주는 서비스입니다.
좀 더 자세한 내용은 다음칸에서 확인해 보시죠.
EC2 Fleet를 활용해볼까?
Spot이 정말 싼지 예시를 하나 보겠습니다. 최근 1개월 가격 히스토리입니다.
- Region: Seoul Region
- OS: Linux
- Instance Type: c5.2xlarge
쌉니다. 대부분의 가격 패턴이 이렇습니다. 아직까지는 활용이 잘 되지 않는건지 변동성이 크지 않습니다.
보통 Linux 계열은 on demand의 25%정도, Windows 계열은 on demand의 50%정도 가격대를 형성하고 있습니다.
이제 이 spot 인스턴스를 기반으로 여러개의 인스턴스群을 한꺼번에 만들어야 하는 상황입니다.
이때 어떤 정보를 사전에 조율해야 할까요?
① EC2 생성 조건이 필요합니다. 어떤 AMI를 쓰고, 어느 VPC Subnet 위에 올리고, 어느 크기의 EBS를 붙일지 등등
② 수량도 필요합니다. 어느 Instance Type이 몇개가 필요한지. vCPU 단위로 환산한다면 총 몇개의 vCPU가 필요한지 등등
③ 타 입찰에 밀려 내 spot이 폐기되었을때, 그냥 냅둘지. 아님 부족분을 다시 보충할지도 정책이 정해져 있어야 합니다
자, 우선 이 정도만 환기를 하고, 나머지 부분은 데모와 함께 설명 드리겠습니다.
데모는 총 Lv1부터 Lv3까지 총 3단계로 진행합니다.
▣ 기본 전제: 1) spot 인스턴스를 기반으로 2) 다수의 인스턴스를 3) 가격-효율적으로 4) 한번에 생성하겠다
Lv1) 한꺼번에 만들겠다. 이후에 타 입찰에 밀려 폐기되면 정해진 규칙대로 새 인스턴스를 보충하겠다 (maintain)
Lv2) 한꺼번에 만들겠다. 내 임의로 Instance Type별 가중치를 정하고 가중치별 가격으로 가격-효율성을 판단하겠다
Lv3) 한꺼번에 만들겠다. spot으로 만들되, 이 중 일부 고정된 수량의 인스턴스는 on demand 형태로 섞어서 만들겠다
지금은 이해가 안가도 됩니다. 데모에서 상세히 설명 드리겠습니다.
사실 예전에도 spot Fleet이라는 기능이 있었습니다. 사실 EC2 Fleet은 그 연장선상에 있기 때문에 동작 구조가 크게 다르지 않습니다.
Lv1. 가장 간단한 구성
참고로 EC2 Fleet 조작은 아직 AWS Management Console 환경을 지원하지 않습니다. 따라서 AWSCLI를 사용합니다.
- Instance Type은 c5.large로 합니다
- EC2 수량은 6개이며, 모두 spot으로 구성합니다
이 요구사항을 json 형식으로 정리하면 다음과 같습니다.
$ more lv1.json
{
"LaunchTemplateConfigs": [
{
"LaunchTemplateSpecification": {
"LaunchTemplateId": "lt-042ddcb87d422e407",
"Version": "1"
},
"Overrides": [
{
"InstanceType": "c5.large"
}
]
}
],
"TargetCapacitySpecification": {
"TotalTargetCapacity": 6,
"OnDemandTargetCapacity": 0,
"SpotTargetCapacity": 6,
"DefaultTargetCapacityType": "spot"
}
}
- LaunchTemplateId 객체는 사전에 따로 생성해야 합니다. 사용하는 AMI나 VPC Subnet, Instance Type 기본값 등을 정의합니다
- Overrides 항목은 만들 Instance Type을 지정합니다. 기존 LaunchTemplateId에 정의된 인스턴스 타입은 무효처리(Override)합니다
- 전체 수량(TotalTargetCapacity)은 6으로 하고, Spot 수량(SpotTargetCapacity)도 6으로 하겠습니다
자, 이제 함대(Fleet)를 만들어 봅시다.
$ aws ec2 create-fleet --cli-input-json file://`pwd`/lv1.json
{
"FleetId": "fleet-e68ee0a5-3502-440e-9425-126f1f95431f"
}
정상적으로 요청이 처리되면 위와 같이 FleetId 값이 반환됩니다. Id값을 넣고 세부 정보를 보면.
$ aws ec2 describe-fleets --fleet-ids fleet-e68ee0a5-3502-440e-9425-126f1f95431f
{
"Fleets": [
{
"Type": "maintain",
"FulfilledCapacity": 6.0,
"LaunchTemplateConfigs": [
{
"LaunchTemplateSpecification": {
"Version": "1",
"LaunchTemplateId": "lt-042ddcb87d422e407"
},
"Overrides": [
{
"InstanceType": "c5.large"
}
]
}
],
"TerminateInstancesWithExpiration": false,
"TargetCapacitySpecification": {
"OnDemandTargetCapacity": 0,
"SpotTargetCapacity": 6,
"TotalTargetCapacity": 6,
"DefaultTargetCapacityType": "spot"
},
"FulfilledOnDemandCapacity": 0.0,
"ActivityStatus": "fulfilled",
"FleetId": "fleet-e68ee0a5-3502-440e-9425-126f1f95431f",
"ReplaceUnhealthyInstances": false,
"SpotOptions": {
"InstanceInterruptionBehavior": "terminate",
"AllocationStrategy": "lowestPrice"
},
"FleetState": "active",
"ExcessCapacityTerminationPolicy": "termination",
"CreateTime": "2018-05-15T06:05:30.000Z"
}
]
}
fulfilled라고 써있는거 보니 잘 진행이 되었나 봅니다. 그럼 인스턴스가 정말 생겼는지 확인해 보겠습니다.
$ aws ec2 describe-fleet-instances --fleet-id fleet-e68ee0a5-3502-440e-9425-126f1f95431f --output text
fleet-e68ee0a5-3502-440e-9425-126f1f95431f
ACTIVEINSTANCES healthy i-09c04149aa9d0684c c5.large sir-2rribrmg
ACTIVEINSTANCES healthy i-011cd91e97ea39054 c5.large sir-h9ei8dcg
ACTIVEINSTANCES healthy i-0e6ea0b6040d2b0d7 c5.large sir-9pgib85k
ACTIVEINSTANCES healthy i-0631dbf28d89da9ad c5.large sir-az5r9aag
ACTIVEINSTANCES healthy i-0d1f401f766c1f441 c5.large sir-r35897hk
ACTIVEINSTANCES healthy i-03dc3b2b61a0a1384 c5.large sir-2tega6yj
6개 모두 sir로 시작하는 인덱스가 붙은거 보니, 6개의 spot 인스턴스가 잘 생성된 모양입니다.
참고로 Fleet을 생성할때 Type을 지정할 수 있는데요. "request"와 "maintain"이 있고 기본값은 "maintain"입니다.
- maintain의 경우 타 입찰에 의해 spot 인스턴스가 폐기되면, 미리 정한 수량을 충족하도록 부족한 수량을 새로 할당 받습니다
- request의 경우 동일한 상황에서, 새로은 spot 인스턴스를 할당받지 않습니다
이제 삭제합시다. 만들때와 마찬가지로 삭제도 Fleet 단위로 합니다. 물론 여기에 속한 인스턴스는 모두 삭제됩니다.
$ aws ec2 delete-fleets --fleet-ids fleet-e68ee0a5-3502-440e-9425-126f1f95431f --terminate-instances
{
"UnsuccessfulFleetDeletions": [],
"SuccessfulFleetDeletions": [
{
"CurrentFleetState": "deleted_terminating",
"PreviousFleetState": "active",
"FleetId": "fleet-e68ee0a5-3502-440e-9425-126f1f95431f"
}
]
}
정리가 잘 되었습니다.
자, 이제 Lv2로 넘어갑시다. 다른 옵션이 몇개 있는 모양입니다.
Lv2. 복수의 Instance Type 군을 섞어서 구성
Fleet을 생성할때 꼭 1개의 Instance Type을 사용해야 하는 것은 아닙니다.
여러개의 후보 Instance Type을 정해놓고, 그 중에 가격대 성능비가 좋은 애들을 판단해서 만들도록 제어할수도 있습니다.
- Instance Type은 c5.large 또는 c5.2xlarge로 합니다
- 필요한 분석 Job을 기준으로 단위 성능을 측정하니, c5.large를 1이라고 하면 c5.2xlarge는 3정도로 계측되었습니다
- 단위 성능을 기준으로 총 6단위가 필요한 상황입니다. 6단위 모두 spot으로 구성합니다
이 요구사항을 json 형식으로 정리하면 다음과 같습니다. WeightedCapacity 항목이 제가 임의로 정한 성능값입니다.
$ more lv2.json
{
"LaunchTemplateConfigs": [
{
"LaunchTemplateSpecification": {
"LaunchTemplateId": "lt-042ddcb87d422e407",
"Version": "1"
},
"Overrides": [
{
"InstanceType": "c5.large",
"WeightedCapacity": 1
},
{
"InstanceType": "c5.2xlarge",
"WeightedCapacity": 3
}
]
}
],
"TargetCapacitySpecification": {
"TotalTargetCapacity": 6,
"OnDemandTargetCapacity": 0,
"SpotTargetCapacity": 6,
"DefaultTargetCapacityType": "spot"
}
}
자, 이 json을 기반으로 fleet를 만들어 보겠습니다.
$ aws ec2 create-fleet --cli-input-json file://`pwd`/lv2.json
{
"FleetId": "fleet-81c1f93e-b271-436a-b569-7ba6cfa43295"
}
자, 그럼 여기서 퀴즈.
현재 spot의 가격은 c5.large가 25원이고 c5.2xlarge가 99원입니다.
둘 중에 어떤 인스턴스로 6단위를 채우게 될까요? 결과를 확인해 보겠습니다.
$ aws ec2 describe-fleet-instances --fleet-id fleet-81c1f93e-b271-436a-b569-7ba6cfa43295 --output text
fleet-81c1f93e-b271-436a-b569-7ba6cfa43295
ACTIVEINSTANCES i-0af6456aa59b5c021 c5.large sir-f4egabhg
ACTIVEINSTANCES i-053112982cd65091a c5.large sir-ybng9s7j
ACTIVEINSTANCES i-08c08ae5038a422b6 c5.large sir-m1bi9mdh
ACTIVEINSTANCES i-0ae009eed537f3f74 c5.large sir-m2h88jrg
ACTIVEINSTANCES i-0156bc45838870cfc c5.large sir-1c98aq1g
ACTIVEINSTANCES i-0db804d6123bf4112 c5.large sir-i9egas3j
결국 c5.large로 6개가 만들어졌군요. 그 이유는 다음과 같습니다.
- c5.large의 weight가 1이니, weight당 가격은 25원입니다
- c5.2xlarge의 weight는 3이니, weight당 가격은 3/99=33원입니다
- 둘중에 weight(라고 쓰고 단위 성능으로 읽는다)당 비용은 c5.large가 8원 쌉니다
- 따라서 이 부등식이 만족하는 한 Fleet에서는 c5.large로 인스턴스를 생성합니다
이해가 가시나요? 안가신다구요?
그럼 포스팅 맨뒤에 공식문서 링크를 드리겠습니다. 참고로 한글번역은 안되어 있습니다.
다음 단계로 넘어갑시다. Lv3입니다.
Lv3. 복수의 Instance Type + 일부를 On demand로 구성
드디어 마지막입니다. 여기까지 읽으신분은 jscxxx@gscdn.com으로 메일 주시면 파x퇴x 우유를 선물로 드리겠습니다.
마지막 구성은 일부를 on demand 형태로, 나머지를 spot 형태로 구성하는 방법입니다.
- Instance Type은 c5.large 또는 c5.2xlarge로 합니다
- c5.large의 단위 성능을 1, c5.2xlarge의 단위 성능을 3으로 지정했습니다
- 단위 성능을 기준으로 총 6단위가 필요합니다. 이 중 3단위는 on-demand로, 나머지 3단위는 spot으로 구성하려 합니다
이 요구사항을 json 형식으로 정리하면 이렇습니다.
$ more lv3.json
{
"LaunchTemplateConfigs": [
{
"LaunchTemplateSpecification": {
"LaunchTemplateId": "lt-042ddcb87d422e407",
"Version": "1"
},
"Overrides": [
{
"InstanceType": "c5.large",
"WeightedCapacity": 1
},
{
"InstanceType": "c5.2xlarge",
"WeightedCapacity": 3
}
]
}
],
"TargetCapacitySpecification": {
"TotalTargetCapacity": 6,
"OnDemandTargetCapacity": 3,
"SpotTargetCapacity": 3,
"DefaultTargetCapacityType": "spot"
}
}
전체 수량(TotalTargetCapacity)를 6으로 잡고, On demand 수량(OnDemandTargetCapacity)을 3으로 설정했습니다.
$ aws ec2 create-fleet --cli-input-json file://`pwd`/lv3.json
{
"FleetId": "fleet-619f9ed2-654b-4e23-a902-3a7832f13039"
}
Fleet을 만든 후 Fleet에서 만든 인스턴스를 확인해보겠습니다.
$ aws ec2 describe-fleet-instances --fleet-id fleet-619f9ed2-654b-4e23-a902-3a7832f13039 --output text
fleet-619f9ed2-654b-4e23-a902-3a7832f13039
ACTIVEINSTANCES i-06d1fe4e0e5ac0668 c5.large sir-3afra78h
ACTIVEINSTANCES i-03e038b5ce93f54cb c5.large sir-3gdr8jdj
ACTIVEINSTANCES i-079fbbd03c73d7f41 c5.large sir-ds18bwyh
ACTIVEINSTANCES i-0f5548462d76b7012 c5.large
ACTIVEINSTANCES i-043442ee0fc7dfc27 c5.large
ACTIVEINSTANCES i-0ae7f665bb3193cc2 c5.large
요청한대로 on demand 인스턴스가 3개 생기고, 이후 최적의 조건에서 spot 인스턴스 3개가 추가로 생성되었습니다.
이 구성에서는 on demand는 계속 유지될 것이고, spot은 설정에 따라 폐기되거나 이후 보충될 것입니다.
첨언하면 여기서 생성된 on demand 인스턴스는 조건에 맞는 RI를 구매해 놓은 경우 일반적인 프로세스에 따라 RI 또한 적용됩니다.
마치며
이외에도 세부 옵션이 매우 많습니다.
각 pool 마다 최소 1개씩의 인스턴스를 놓고, 나머지를 최적의 경우의 수로 선택하는 diversified 옵션도 있고..
상세한 내용은 제가 다 설명할 수가 없어, 관심 있으신 분들은 아래 공식 링크를 참조하시기 바랍니다.
EC2 Fleet Configuration Strategies
AWS는 결국 가격 API까지 다 제공하기 때문에, 이런 선택 매트릭스를 외부에서 직접 구현해서 사용할 수도 있습니다.
대단한 로직은 아니지만, 아마 UI까지 그럴듯하게 입혀서 서비스하는 제품도 어딘가에 분명 있을 겁니다.
하지만 이렇게 AWS가 내재화(?)해놓은 부분을 사용할때의 장점이 분명히 있습니다.
기본적인 관리포인트가 줄어들고. 일부 영역에 대한 업데이트에도 전체 동작의 무결성이 보존되는 효과도 있고..
암튼 저는 장점이 많다고 생각합니다.
뭔가 빡센 배치 job을 단시간에 싸게 돌리고 싶은데, 인프라 구성이 귀찮으신 분들께 작은 힌트가 되었으면 좋겠네요.
그럼 마치겠습니다. 끝!