소개
로드 밸런서는 실패한 앱을 피할 수 있지만 대체 서버를 만들지는 않습니다. 이 실습에서는 템플릿과 그룹으로 두 인스턴스를 유지하고 장애를 일으켜 새 인스턴스 ID가 실제 요청을 처리하는지 확인합니다.
EC2 User Data, ALB 대상 그룹 및 앱 상태 검사를 알아야 합니다. 새 환경에는 네트워크, 앱 이미지, 키 페어, HTTP 리스너가 연결된 빈 대상 그룹이 있으며 기존 서버군은 없습니다. CLI와 연결 파일은 이전 실습과 독립적으로 준비됩니다.
자격증 관련성
다음 시험 주제를 입문 수준에서 실습합니다.
- Solutions Architect – Associate (SAA-C03) · 과제 2.1: 시작 템플릿, 그룹 용량, 로드 밸런서 통합. 과제 2.2: 실패한 백엔드 교체를 통한 가용성.
- CloudOps Engineer – Associate (SOA-C03) · 과제 2.1: EC2 용량 유지. 과제 2.2: 앱 상태로 장애 백엔드를 식별하고 교체.
앱 시작 템플릿 만들기
Auto Scaling이 각 서버를 시작할 때 사용할 설정을 정의합니다.
작업 디렉터리로 이동하고 준비된 네트워크 변수를 불러옵니다.
cd /home/labex/project
source launch.env
시작 템플릿은 AMI, 유형, 보안 그룹 및 시작 설정을 저장합니다. 제공된 파일을 확인합니다.
cat launch-template.json
cat application-user-data.sh
JSON은 준비된 AMI, t3.micro, report-key, 앱 보안 그룹을 선택합니다. UserData는 별도로 표시된 스크립트의 base64 인코딩입니다. 스크립트는 메시지를 Application ready, healthy를 true로 초기화합니다. 대체 서버가 준비되도록 매번 적용해야 합니다. 이전 서버 내부 수정은 템플릿을 바꾸지 않습니다.
템플릿을 만듭니다. file://는 CLI가 JSON 내용을 매개변수 값으로 읽도록 합니다.
LT_ID=$(aws ec2 \
create-launch-template \
--launch-template-name application-template \
--launch-template-data file://launch-template.json \
--query 'LaunchTemplate.LaunchTemplateId' \
--output text)
템플릿에는 번호가 있는 버전이 있습니다. 그룹에서 명시적으로 사용할 1을 확인합니다.
aws ec2 \
describe-launch-template-versions \
--launch-template-id "$LT_ID" \
--versions 1 \
--query 'LaunchTemplateVersions[].{Version:VersionNumber,AMI:LaunchTemplateData.ImageId,Type:LaunchTemplateData.InstanceType,Key:LaunchTemplateData.KeyName,Groups:LaunchTemplateData.SecurityGroupIds}'
템플릿 생성은 인스턴스를 시작하지 않습니다. AWS View를 열면 ALB와 대상 그룹은 있지만 등록된 앱 대상은 없습니다.
서버군 시작 및 연결
Auto Scaling 그룹을 만들고 실제 앱 인스턴스를 제공된 ALB에 연결합니다.
Auto Scaling 그룹은 최소와 최대 사이에서 원하는 인스턴스 수를 유지합니다. 원하는 용량은 유지할 수량이며 처리량 측정값이 아닙니다. 최소 2, 원하는 2, 최대 3은 두 서버로 시작하고 한 서버 추가를 허용합니다.
대상 그룹 ARN과 로드 밸런서 DNS 이름을 가져옵니다.
TG_ARN=$(aws elbv2 \
describe-target-groups \
--names application-targets \
--query 'TargetGroups[0].TargetGroupArn' \
--output text)
LB_DNS=$(aws elbv2 \
describe-load-balancers \
--names application-alb \
--query 'LoadBalancers[0].DNSName' \
--output text)
버전 1과 두 서브넷으로 그룹을 만듭니다. --target-group-arns는 인스턴스를 ALB에 자동 등록합니다. --health-check-type ELB는 교체 판단에 로드 밸런서 상태를 포함합니다. EC2 검사만으로는 모든 앱 장애를 찾을 수 없습니다. 유예 기간은 새 인스턴스의 시작 시간을 확보합니다. 여기서는 30초지만 운영 환경에서는 시작 동작에 맞춰야 합니다.
aws autoscaling \
create-auto-scaling-group \
--auto-scaling-group-name application-fleet \
--launch-template "LaunchTemplateId=$LT_ID,Version=1" \
--min-size 2 \
--max-size 3 \
--desired-capacity 2 \
--vpc-zone-identifier "$SUBNET_ID,$SECOND_SUBNET_ID" \
--target-group-arns "$TG_ARN" \
--health-check-type ELB \
--health-check-grace-period 30
그룹과 인스턴스 ID를 확인합니다.
aws autoscaling \
describe-auto-scaling-groups \
--auto-scaling-group-names application-fleet \
--query 'AutoScalingGroups[].{Min:MinSize,Desired:DesiredCapacity,Max:MaxSize,HealthCheck:HealthCheckType,Grace:HealthCheckGracePeriod,Instances:Instances[].InstanceId}'
앱 준비를 기다린 후 ALB 대상을 확인합니다.
aws elbv2 \
wait target-in-service \
--target-group-arn "$TG_ARN"
aws elbv2 \
describe-target-health \
--target-group-arn "$TG_ARN" \
--query 'TargetHealthDescriptions[].{Instance:Target.Id,Health:TargetHealth.State}' \
--output table
정상 ID 두 개가 예상됩니다. 여섯 요청을 보내 응답 ID를 그룹과 비교합니다.
for request in 1 2 3 4 5 6; do
curl --config client.conf -sS "http://$LB_DNS/health"
echo
done
AWS View에서 용량 2와 정상 대상 두 개를 확인하고 Send request로 양쪽 ID의 실제 200 응답을 관찰합니다. 서브넷과 가용 영역 표시는 설정이며 실제 영역 간 복원력을 측정하지 않습니다.
자동 장애 교체 관찰
앱 장애를 일으키고 수동 복구 대신 그룹이 인스턴스를 교체하게 합니다.
현재 그룹 인스턴스 하나를 선택하고 SSH용 공인 주소를 가져옵니다.
OLD_ID=$(aws autoscaling \
describe-auto-scaling-groups \
--auto-scaling-group-names application-fleet \
--query 'AutoScalingGroups[0].Instances[0].InstanceId' \
--output text)
OLD_IP=$(aws ec2 \
describe-instances \
--instance-ids "$OLD_ID" \
--query 'Reservations[0].Instances[0].PublicIpAddress' \
--output text)
healthy만 바꿔 503을 반환하게 합니다. 앞 실습처럼 임시 JSON 파일은 읽는 중 원본 덮어쓰기를 방지합니다.
ssh -F ssh_config "ubuntu@$OLD_IP" \
'sudo jq ".healthy = false" /etc/report-app/config.json > /tmp/report-config.json && sudo install -m 644 /tmp/report-config.json /etc/report-app/config.json'
ssh -F ssh_config "ubuntu@$OLD_IP" \
'curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8081/health'
503이 예상됩니다. 인스턴스 실행 중 앱이 실패했습니다. ALB가 검사 실패를 감지하고 유예 기간 후 그룹이 인스턴스를 교체해 용량을 복원합니다. 같은 템플릿으로 정상 설정의 대체 서버가 시작됩니다.
AWS View에서 ID와 상태 변화를 관찰합니다. 감지 직후 교체되어 비정상 상태가 짧을 수 있고 새 대상은 처음 initial일 수 있습니다. 복구나 추가 run-instances 명령은 실행하지 않습니다.
이전 인스턴스 종료와 대상 그룹 정상화를 기다립니다.
aws ec2 \
wait instance-terminated \
--instance-ids "$OLD_ID"
aws elbv2 \
wait target-in-service \
--target-group-arn "$TG_ARN"
이전 인스턴스와 현재 그룹을 확인합니다.
aws ec2 \
describe-instances \
--instance-ids "$OLD_ID" \
--query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name}'
aws autoscaling \
describe-auto-scaling-groups \
--auto-scaling-group-names application-fleet \
--query 'AutoScalingGroups[].{Desired:DesiredCapacity,Instances:Instances[].InstanceId}'
이전 ID는 terminated여야 합니다. 용량 2를 유지하며 새 ID로 바뀝니다. 대체 서버는 새로 초기화되므로 이전 서버 내부 변경만으로는 자동 보존되지 않습니다.
다시 여섯 요청을 보냅니다.
for request in 1 2 3 4 5 6; do
curl --config client.conf -sS "http://$LB_DNS/health"
echo
done
이전 ID 없이 새 ID를 포함한 현재 두 ID를 찾습니다. AWS View에서 정상 대상 두 개와 Send request를 통한 대체 서버 응답을 확인합니다. 리소스 수만으로 앱 동작을 증명할 수 없습니다.

예: 용량은 두 대를 유지하고 새 인스턴스가 HTTP 200을 반환합니다. 실제 ID는 다릅니다.
서버군과 템플릿 삭제
그룹, 인스턴스와 템플릿을 삭제하고 제공된 ALB와 네트워크는 유지합니다.
최소 용량이 2여도 인스턴스를 종료하도록 --force-delete로 그룹을 삭제합니다. 템플릿만 삭제하면 실행 중 인스턴스는 멈추지 않습니다.
aws autoscaling \
delete-auto-scaling-group \
--auto-scaling-group-name application-fleet \
--force-delete
aws ec2 \
wait instance-terminated \
--filters "Name=tag:aws:autoscaling:groupName,Values=application-fleet"
aws ec2 \
delete-launch-template \
--launch-template-id "$LT_ID"
대기 명령은 Auto Scaling 자동 태그로 그룹 인스턴스를 선택하며 교체된 이전 인스턴스를 포함해 모두 종료될 때까지 기다립니다. 그룹 부재, 템플릿 목록과 대상 등록을 확인합니다.
aws autoscaling \
describe-auto-scaling-groups \
--auto-scaling-group-names application-fleet \
--query 'AutoScalingGroups[].AutoScalingGroupName'
aws ec2 \
describe-launch-templates \
--query 'LaunchTemplates[].LaunchTemplateName'
aws elbv2 \
describe-target-health \
--target-group-arn "$TG_ARN" \
--query 'TargetHealthDescriptions[].Target.Id'
세 목록 모두 []여야 합니다. 등록 해제에 시간이 걸리면 잠시 기다려 마지막 조회를 반복합니다. AWS View는 ALB와 대상 그룹을 유지하지만 서버군과 등록 대상은 없어야 합니다. 제공된 네트워크, AMI와 키 페어를 남깁니다.
요약
버전이 있는 템플릿과 실제 서버 두 대를 유지하는 그룹을 만들었습니다. ALB 검사를 교체 판단에 넣고 장애 후 새 ID의 실제 응답을 검증했습니다. 마지막으로 그룹, 인스턴스와 템플릿을 삭제하고 ALB와 네트워크를 유지했습니다.
다음 실습에서는 단순 조정 정책으로 용량을 바꾸고 그룹 한계를 확인합니다.



