실습 예제 · 2
ALB + ASG 웹 티어
실습 1에서 만든 네트워크 위에 Application Load Balancer와 Auto Scaling 그룹을 얹습니다. 핵심은 대수를 늘리는 것이 아니라 여러 가용 영역에 퍼뜨리고, 상태 확인으로 자동 교체되게 만드는 것입니다.
학습 목표
- 시작 템플릿과 Auto Scaling 그룹을 만들어 여러 가용 영역에 인스턴스를 분산할 수 있습니다.
- 대상 그룹의 상태 확인과 Auto Scaling의 상태 확인 유형 차이를 구분할 수 있습니다.
- 대상 추적 스케일링 정책을 붙이고 목표 지표를 고를 수 있습니다.
- 상태 확인 실패가 인스턴스 교체로 이어지는 과정을 관찰할 수 있습니다.
- 삭제 순서를 지켜 리소스를 남김없이 정리할 수 있습니다.
시나리오
HTTP로 응답하는 웹 애플리케이션을 배포합니다. 요구는 이렇습니다.
- 인터넷에서 로드 밸런서를 통해서만 접근할 수 있어야 합니다.
- 인스턴스는 프라이빗 서브넷에 있어야 합니다.
- 가용 영역 하나가 손실돼도 서비스가 계속되어야 합니다.
- 애플리케이션이 응답하지 못하는 인스턴스는 자동으로 교체되어야 합니다.
- 부하에 따라 대수가 조절되어야 합니다.
아키텍처 개요
| 구성 요소 | 배치 | 역할 |
|---|---|---|
| Application Load Balancer | 퍼블릭 서브넷(가용 영역 2곳) | 인터넷 요청을 받아 대상 그룹으로 분배 |
| 대상 그룹 | — | 상태 확인으로 정상 인스턴스만 트래픽 대상에 유지 |
| Auto Scaling 그룹 | 프라이빗 서브넷(가용 영역 2곳) | 용량 유지와 확장·축소, 비정상 인스턴스 교체 |
| 시작 템플릿 | — | 인스턴스 사양·이미지·보안 그룹·사용자 데이터 정의 |
| 보안 그룹 2개 | — | 로드 밸런서용(인터넷 허용) · 인스턴스용(로드 밸런서 보안 그룹만 허용) |
보안 그룹을 두 개로 나누고 인스턴스 쪽 소스를 로드 밸런서 보안 그룹 ID로 지정하는 것이 이 실습의 설계 요점입니다. 인스턴스가 늘거나 서브넷이 바뀌어도 규칙을 고칠 필요가 없습니다.
구성 단계
1 · 보안 그룹 두 개
VPC_ID=vpc-0123456789abcdef0
ALB_SG=$(aws ec2 create-security-group \
--group-name lab02-alb-sg \
--description "ALB ingress from internet" \
--vpc-id "$VPC_ID" \
--query 'GroupId' --output text)
aws ec2 authorize-security-group-ingress \
--group-id "$ALB_SG" \
--protocol tcp --port 80 --cidr 0.0.0.0/0
APP_SG=$(aws ec2 create-security-group \
--group-name lab02-app-sg \
--description "App ingress from ALB only" \
--vpc-id "$VPC_ID" \
--query 'GroupId' --output text)
# 소스를 CIDR 이 아니라 보안 그룹으로 지정합니다.
aws ec2 authorize-security-group-ingress \
--group-id "$APP_SG" \
--ip-permissions "[{
\"IpProtocol\": \"tcp\", \"FromPort\": 80, \"ToPort\": 80,
\"UserIdGroupPairs\": [{\"GroupId\": \"$ALB_SG\"}]
}]"
2 · 시작 템플릿
인스턴스에는 액세스 키를 심지 않습니다. 필요한 권한은 IAM 역할을 인스턴스 프로파일로 연결해 전달하고, 메타데이터는 IMDSv2를 요구하도록 설정합니다.
{
"ImageId": "ami-0123456789abcdef0",
"InstanceType": "t3.micro",
"SecurityGroupIds": ["sg-0app000000000000"],
"IamInstanceProfile": { "Name": "Lab02WebProfile" },
"MetadataOptions": {
"HttpTokens": "required",
"HttpEndpoint": "enabled",
"HttpPutResponseHopLimit": 1
},
"TagSpecifications": [
{
"ResourceType": "instance",
"Tags": [{ "Key": "Name", "Value": "lab02-web" }]
}
]
}
aws ec2 create-launch-template \
--launch-template-name lab02-web-lt \
--launch-template-data file://launch-template.json \
--query 'LaunchTemplate.[LaunchTemplateId,LatestVersionNumber]' \
--output table
3 · 로드 밸런서와 대상 그룹
ALB_ARN=$(aws elbv2 create-load-balancer \
--name lab02-alb \
--type application \
--scheme internet-facing \
--subnets subnet-0pub00000000000a subnet-0pub00000000000b \
--security-groups "$ALB_SG" \
--query 'LoadBalancers[0].LoadBalancerArn' --output text)
TG_ARN=$(aws elbv2 create-target-group \
--name lab02-tg \
--protocol HTTP --port 80 \
--vpc-id "$VPC_ID" \
--target-type instance \
--health-check-protocol HTTP \
--health-check-path /health \
--health-check-interval-seconds 15 \
--health-check-timeout-seconds 5 \
--healthy-threshold-count 2 \
--unhealthy-threshold-count 2 \
--query 'TargetGroups[0].TargetGroupArn' --output text)
aws elbv2 create-listener \
--load-balancer-arn "$ALB_ARN" \
--protocol HTTP --port 80 \
--default-actions "Type=forward,TargetGroupArn=$TG_ARN"
4 · Auto Scaling 그룹
aws autoscaling create-auto-scaling-group \
--auto-scaling-group-name lab02-asg \
--launch-template "LaunchTemplateName=lab02-web-lt,Version=\$Latest" \
--min-size 2 --max-size 6 --desired-capacity 2 \
--vpc-zone-identifier "subnet-0prv00000000000a,subnet-0prv00000000000b" \
--target-group-arns "$TG_ARN" \
--health-check-type ELB \
--health-check-grace-period 300 \
--default-instance-warmup 180
상태 확인 유형에는 EC2, EBS, ELB,
VPC_LATTICE가 있고 EC2는 기본이며 끌 수 없습니다.
ELB를 추가해야 인스턴스는 살아 있는데 애플리케이션이 응답하지 못하는 상태가
교체 대상이 됩니다.
5 · 스케일링 정책
ALB_LABEL=$(aws elbv2 describe-load-balancers --load-balancer-arns "$ALB_ARN" \
--query 'LoadBalancers[0].LoadBalancerArn' --output text | cut -d: -f6)
TG_LABEL=$(echo "$TG_ARN" | cut -d: -f6)
aws autoscaling put-scaling-policy \
--auto-scaling-group-name lab02-asg \
--policy-name lab02-track-requests \
--policy-type TargetTrackingScaling \
--target-tracking-configuration "{
\"TargetValue\": 500.0,
\"PredefinedMetricSpecification\": {
\"PredefinedMetricType\": \"ALBRequestCountPerTarget\",
\"ResourceLabel\": \"$ALB_LABEL/$TG_LABEL\"
}
}"
검증 방법
# 1) 인스턴스가 두 가용 영역에 나뉘어 있는지
aws autoscaling describe-auto-scaling-groups \
--auto-scaling-group-names lab02-asg \
--query 'AutoScalingGroups[0].Instances[].[InstanceId,AvailabilityZone,LifecycleState,HealthStatus]' \
--output table
# 2) 대상 그룹의 상태 확인 결과
aws elbv2 describe-target-health \
--target-group-arn "$TG_ARN" \
--query 'TargetHealthDescriptions[].[Target.Id,TargetHealth.State,TargetHealth.Reason]' \
--output table
# 3) 로드 밸런서의 DNS 이름으로 실제 응답 확인
aws elbv2 describe-load-balancers \
--load-balancer-arns "$ALB_ARN" \
--query 'LoadBalancers[0].[DNSName,State.Code,AvailabilityZones[].ZoneName]' \
--output json
장애를 일부러 만들어 본다
구성이 실제로 동작하는지는 실패를 만들어 봐야 압니다.
- 인스턴스 하나에서 애플리케이션 프로세스를 중지시킵니다.
- 대상 그룹의 상태가
unhealthy로 바뀌는지 봅니다. - Auto Scaling이 그 인스턴스를 종료하고 새로 시작하는지 봅니다.
- 그동안 로드 밸런서가 남은 인스턴스로만 트래픽을 보내는지 확인합니다.
aws autoscaling set-instance-health \
--instance-id i-0123456789abcdef0 \
--health-status Unhealthy \
--no-should-respect-grace-period
aws autoscaling describe-scaling-activities \
--auto-scaling-group-name lab02-asg \
--max-items 5 \
--query 'Activities[].[StartTime,StatusCode,Description]' \
--output table
비용 고려
| 구성 요소 | 요금 항목의 성격 |
|---|---|
| Application Load Balancer | 가동 시간과 처리한 용량 단위 |
| EC2 인스턴스 | 실행 시간. 최소 용량이 곧 하한 비용이다 |
| EBS 볼륨 | 인스턴스를 중지해도 계속 발생한다 |
| 가용 영역 간 전송 | 교차 영역 분배로 경계를 넘는 트래픽에 붙는다 |
| Auto Scaling | 서비스 자체로는 항목이 늘지 않는다. 늘어난 인스턴스가 항목이다 |
비용 관점에서 중요한 설정은 최소 용량입니다. 가용성을 위해 최소 2대를 유지한다면 그것이 상시 비용의 바닥이 됩니다. 예측 가능한 한산한 시간대가 있다면 예약 스케일링으로 최소 용량을 낮출 수 있습니다 (케이스 7).
프로덕션 고려사항
- HTTPS로 종료합니다. ACM 인증서를 로드 밸런서 리스너에 붙이고 HTTP 요청은 HTTPS로 리디렉션합니다.
- 가용 영역 셋 이상. 두 곳이면 하나가 빠질 때 남은 한 곳이 전부를 감당해야 합니다.
- 상태를 인스턴스 밖으로. 세션과 업로드 파일이 인스턴스에 있으면 자동 교체가 사용자에게 장애로 보입니다(케이스 5).
- 워밍업과 유예 기간을 실제 기동 시간으로. 너무 짧으면 준비 중인 인스턴스가 교체되어 기동과 종료가 반복됩니다.
- 배포는 인스턴스 새로 고침으로. 시작 템플릿의 새 버전을 만들고 점진적으로 교체하면 중단 없이 배포할 수 있습니다.
- 수명주기 훅으로 종료 직전에 로그를 회수하거나 연결 드레이닝을 기다릴 수 있습니다.
- 접근 로그를 켭니다. 로드 밸런서 접근 로그는 기본이 꺼짐이며, 문제가 생긴 뒤에 켜면 이전 기록이 없습니다.
정리 — 리소스 삭제
aws autoscaling delete-auto-scaling-group \
--auto-scaling-group-name lab02-asg \
--force-delete
aws elbv2 delete-listener --listener-arn "$LISTENER_ARN"
aws elbv2 delete-load-balancer --load-balancer-arn "$ALB_ARN"
aws elbv2 delete-target-group --target-group-arn "$TG_ARN"
aws ec2 delete-launch-template --launch-template-name lab02-web-lt
# 보안 그룹은 참조가 모두 사라진 뒤에야 삭제됩니다.
aws ec2 delete-security-group --group-id "$APP_SG"
aws ec2 delete-security-group --group-id "$ALB_SG"
자주 하는 실수
| 실수 | 증상 | 고치는 법 |
|---|---|---|
| 로드 밸런서를 서브넷 하나에만 등록 | 가용 영역 장애 시 전면 중단 | 둘 이상의 가용 영역 서브넷을 지정한다 |
| Auto Scaling 그룹의 서브넷이 한 가용 영역에만 | 인스턴스가 전부 같은 곳에 몰린다 | --vpc-zone-identifier에 여러 가용 영역 서브넷을 넣는다 |
상태 확인 유형을 EC2만 사용 |
애플리케이션이 죽어도 교체되지 않는다 | --health-check-type ELB |
| 유예 기간이 기동 시간보다 짧음 | 새 인스턴스가 준비 전에 비정상으로 교체되어 반복된다 | 기동 시간을 재고 유예 기간을 늘린다 |
인스턴스 보안 그룹이 0.0.0.0/0 허용 |
로드 밸런서를 우회한 직접 접근이 가능해진다 | 소스를 로드 밸런서 보안 그룹 ID로 지정한다 |
| 상태 확인 경로가 정적 파일 | 의존 서비스가 끊긴 인스턴스가 계속 정상으로 남는다 | 애플리케이션이 실제로 일할 수 있는지 반환하는 경로로 바꾼다 |
| 단순 조정 정책으로 1대씩 확장 | 급증을 따라가지 못한다 | 대상 추적 정책으로 바꾼다(케이스 7) |
이어서 볼 곳
- 7장 · 로드 밸런싱과 오토스케일링 ALB·NLB·GWLB 선택 기준, 대상 그룹, 스케일링 정책과 수명주기 훅을 다룹니다.
- 실습 1 · 3계층 VPC 직접 구성 이 실습이 전제하는 네트워크를 먼저 만듭니다.
- 케이스 5 · 단일 AZ 설계가 장애로 전면 중단됐다 이 구성이 없을 때 무엇이 순서대로 끊기는지 확인합니다.
- 케이스 7 · 트래픽 급증에 스케일아웃이 못 따라갔다 스케일링 정책과 워밍업 설정이 반응 속도를 어떻게 바꾸는지 다룹니다.
- 실습 12 · CloudWatch 알람 + SNS 알림 이 웹 티어의 지표에 알람을 걸어 이상을 알리는 파이프라인을 만듭니다.
공식 문서 출처
- Elastic Load Balancing API 레퍼런스 — CreateLoadBalancer
— 유형(
application·network·gateway)과 체계, 서브넷 지정 - Elastic Load Balancing API 레퍼런스 — CreateTargetGroup
— 대상 유형(
instance·ip·lambda·alb)과 상태 확인 파라미터 - Elastic Load Balancing API 레퍼런스 — CreateListener — 기본 작업으로 대상 그룹에 전달하는 구성
- Amazon EC2 Auto Scaling API 레퍼런스 — CreateAutoScalingGroup
—
VPCZoneIdentifier,TargetGroupARNs, 상태 확인 유형과 유예 기간, 기본 인스턴스 워밍업 - Amazon EC2 Auto Scaling API 레퍼런스 — PutScalingPolicy — 대상 추적 정책과 사전 정의 지표
- Amazon EC2 API 레퍼런스 — CreateLaunchTemplate — 시작 템플릿 데이터의 구성 요소
- Amazon EC2 사용 설명서 — 인스턴스 메타데이터 옵션
—
HttpTokens와 홉 제한 설정