
오늘은 AWS 핵심 4개 서비스(VPC, EC2, Aurora RDS, S3)를 직접 연결해서 고가용성 웹 아키텍처를 처음부터 끝까지 구축했다. 각 서비스가 Security Group과 IAM Role을 통해 어떻게 맞물려 돌아가는지 한 번에 볼 수 있었고, Secrets Manager로 DB 자격증명을 관리하는 패턴은 실무에서도 그대로 쓸 수 있는 내용이라 확실히 익혀뒀다.
오늘은 AWS 공인 교육이 있는 날이었다. 원래 주제는 AWS JAM이었는데, 강사님께서 워크샵을 진행하면 더 좋을 것 같다고 하셔서 AWS General Immersion Day 워크샵으로 대체해서 진행했다. VPC부터 EC2, Aurora RDS, S3까지 AWS 핵심 서비스들을 직접 손으로 구축해보는 실습이었는데, 이론으로만 알던 것들을 실제로 연결해보니 훨씬 명확하게 이해됐다.

리전:
us-east-1, 가용 영역:us-east-1a/us-east-1b
VPC 마법사에서 VPC 등 옵션을 선택하면 VPC, 서브넷, 라우팅 테이블, IGW, NAT Gateway를 한 번에 만들어준다.
| 설정 | 값 |
|---|---|
| 이름 태그 | VPC-Lab |
| IPv4 CIDR | 기본값 유지 |
| 가용 영역 수 | 2 (1a, 1b) |
| NAT Gateway | 1개 (비용 절감) |
| DNS 호스트 이름 | 활성화 |
| DNS 확인 | 활성화 |
서브넷 CIDR 설정:
| 서브넷 | CIDR |
|---|---|
| 1a 퍼블릭 | 10.0.10.0/24 |
| 1b 퍼블릭 | 10.0.20.0/24 |
| 1a 프라이빗 | 10.0.100.0/24 |
| 1b 프라이빗 | 10.0.200.0/24 |
프라이빗 서브넷의 EC2가 S3에 접근할 때 인터넷을 거치지 않도록 게이트웨이 엔드포인트를 추가한다.
com.amazonaws.us-east-1.s3 (게이트웨이 타입)VPC-Lab-vpcVPC 엔드포인트를 쓰면 S3 트래픽이 AWS 내부망을 타기 때문에 보안상 이점도 있고, NAT Gateway를 통하지 않아서 NAT Gateway 데이터 처리 비용도 절감된다. 트래픽이 많은 환경에서는 비용 차이가 꽤 크다.
| 설정 | 값 |
|---|---|
| Name | Web server for custom AMI |
| AMI | Amazon Linux 2023 (기본) |
| Instance Type | t3.micro |
| Key pair | Proceed without a key pair |
| VPC | VPC-Lab-vpc |
| Subnet | Public Subnet A |
| Auto-assign Public IP | Enable |
| Security Group | Immersion Day - Web Server (HTTP TCP/80, Source: My IP) |
| Metadata | IMDSv2 only (V2 only, token required) |
User Data에 아래 스크립트를 입력해서 인스턴스 시작 시 LAMP 스택이 자동 설치되도록 한다.
#!/bin/sh
# LAMP 스택 설치
dnf install -y httpd wget php-fpm php-mysqli php-json php php-devel
dnf install -y mariadb105-server
dnf install -y httpd php-mbstring
# 웹 서버 시작
chkconfig httpd on
systemctl start httpd
# 실습용 웹 앱 다운로드
if [ ! -f /var/www/html/immersion-day-app-php7.zip ]; then
cd /var/www/html
wget -O 'immersion-day-app-php7.zip' '<워크샵 제공 URL>'
unzip immersion-day-app-php7.zip
fi
# AWS SDK for PHP 설치
if [ ! -f /var/www/html/aws.zip ]; then
cd /var/www/html
mkdir vendor
cd vendor
wget https://docs.aws.amazon.com/aws-sdk-php/v3/download/aws.zip
unzip aws.zip
fi
dnf update -y
인스턴스가 Running 상태가 되면 Public IP로 접속해서 웹 페이지가 뜨는지 확인한다.
키페어 없이 EC2에 접속하려면 SSM Session Manager를 사용한다.
AmazonSSMManagedInstanceCore 연결SSMInstanceProfileSSMInstanceProfile 선택User Data 스크립트로 매번 패키지를 설치하면 인스턴스가 뜨는 데 시간이 걸린다. Custom AMI를 쓰면 LAMP가 이미 설치된 상태로 스냅샷을 찍어두는 것이기 때문에, Auto Scaling으로 새 인스턴스가 생성될 때 User Data 재실행 없이 바로 서비스 가능한 상태로 올라온다. 이게 Launch Template에서 Custom AMI를 지정하는 핵심 이유다.
Web Server v1LAMP web server AMIALB용 SG (web-ALB-SG):
EC2용 SG (ASG-Web-Inst-SG):
web-ALB-SGEC2의 SG 소스를 IP 대역이 아닌 ALB의 SG로 지정하면, ALB를 통해 들어온 트래픽만 허용하게 된다. 직접 EC2 IP로 접근하는 건 차단되는 구조다.
| 설정 | 값 |
|---|---|
| 이름 | Web-ALB |
| Scheme | Internet-facing |
| VPC | VPC-Lab-vpc |
| AZ | 퍼블릭 서브넷 1a, 1b |
| Security Group | web-ALB-SG |
| Target Group | Web-TG (인스턴스 타입, HTTP/80) |
| 설정 | 값 |
|---|---|
| 이름 | Web |
| AMI | Web Server v1 (Custom AMI) |
| Instance Type | t3.micro |
| Key pair | 없음 |
| Security Group | ASG-Web-Inst-SG |
| IAM Instance Profile | SSMInstanceProfile |
| Tag | Name: Web Instance (Instances and Volumes) |
Auto Scaling guidance 체크박스 반드시 선택할 것.
| 설정 | 값 |
|---|---|
| 이름 | Web-ASG |
| Launch Template | Web |
| VPC | VPC-Lab-vpc |
| Subnets | 프라이빗 서브넷 1a, 1b |
| Load Balancer | 기존 ALB 연결 → Target Group: Web-TG |
| CloudWatch 그룹 지표 | 활성화 |
| Desired capacity | 2 |
| Minimum capacity | 2 |
| Maximum capacity | 4 |
| Scaling Policy | Target Tracking, CPU 30% |
| Tag | Name: ASG-Web-Instance |
ALB DNS로 접속하면 새로고침할 때마다 다른 AZ의 인스턴스가 응답하는 걸 확인할 수 있다 (Round Robin). 웹 페이지의 LOAD TEST 버튼을 누르면 CPU 부하가 올라가고, 약 5분 후 인스턴스가 2개 → 4개로 늘어나는 걸 CloudWatch 그래프와 Activity 탭에서 확인할 수 있다.
DB-SG)| 설정 | 값 |
|---|---|
| VPC | VPC-Lab-vpc |
| Inbound | MySQL/Aurora (3306), Source: ASG-Web-Inst-SG |
EC2에서만 DB에 접근할 수 있도록 소스를 EC2의 SG로 지정하는 게 핵심이다.
| 설정 | 값 |
|---|---|
| 생성 방법 | Standard Create |
| 엔진 | Aurora (MySQL Compatible) |
| 버전 | Aurora MySQL 3.08.2 (MySQL 8.0.39 호환) |
| Template | Production |
| DB cluster identifier | rdscluster |
| Master username | awsuser |
| Master password | awspassword |
| Instance class | db.r5.large (Memory Optimized) |
| Multi-AZ | Create an Aurora Replica in a different AZ |
| VPC | VPC-Lab-vpc |
| Subnet group | Create new DB subnet group |
| Public access | No |
| Security Group | DB-SG |
| Initial database name | immersionday |
Aurora는 Primary(읽기/쓰기)와 Replica(읽기 전용)로 구성된다. 평소에는 EC2가 Primary에 쓰고 Replica에서 읽는 식으로 부하를 분산할 수 있고, Primary에 장애가 생기면 Replica가 자동으로 Primary로 승격(Failover)된다. 이 때문에 반드시 다른 AZ에 Replica를 두는 것이 권장 사항이다.
RDS 콘솔 → 클러스터 선택 → Actions → Failover 클릭 후 잠시 기다리면 Writer/Reader 역할이 바뀌는 걸 확인할 수 있다. Failover 소요 시간은 보통 60~120초다.
immersionday-snapshot코드에 비밀번호를 하드코딩하지 않고 Secrets Manager에서 읽어오는 방식이다.
awsuser, Password: awspasswordmysecretdbname: immersionday 키-값 추가 확인이름을 반드시
mysecret으로 해야 한다. 실습용 앱 코드 내부에 이 이름이 하드코딩되어 있어서, 다른 이름으로 만들면 앱이 Secret을 찾지 못해 DB 연결이 안 된다.
GetSecretValue 허용 → All resourcesReadSecretsSSMInstanceProfile → ReadSecrets 정책 연결이후 ALB DNS로 접속해서 RDS 탭에 들어가면 주소록 앱이 DB와 연결된 걸 확인할 수 있다. Add Contact / Edit / Remove로 데이터를 직접 추가하고 DB에 반영되는 것도 확인 가능하다.
| 설정 | 값 |
|---|---|
| 버킷 이름 | immersion-day-{이름} (전 세계 고유해야 함) |
| Object Ownership | ACLs enabled |
| Block Public Access | 기본값 유지 (나중에 해제) |
aws.png 이미지 파일 업로드index.html 작성 후 업로드<html>
<head>
<meta charset="utf-8">
<title>AWS General Immersion Day S3 HoL</title>
</head>
<body>
<center>
<br>
<h2>Click image to be redirected to the EC2 instance</h2>
<img src="{aws.png의 Object URL}" onclick="window.location='{ALB DNS Name}'"/>
</center>
</body>
</html>
confirm 입력index.html이미지를 클릭하면 ALB를 통해 EC2 웹 서버로 리디렉션된다.
index.html을 수정해서 같은 이름으로 재업로드하면 이전 버전이 보존됨| 단계 | 서비스 | 핵심 포인트 |
|---|---|---|
| 1 | VPC | 퍼블릭/프라이빗/DB 서브넷 분리, S3 VPC 엔드포인트 |
| 2 | EC2 | Custom AMI로 Auto Scaling 기반 마련, Session Manager로 SSH 대체 |
| 3 | ALB + ASG | SG 체이닝으로 트래픽 제어, CPU 30% 기준 자동 스케일링 |
| 4 | Aurora RDS | Multi-AZ Replica, Secrets Manager로 자격증명 관리 |
| 5 | S3 | 정적 웹 호스팅, Versioning으로 파일 이력 관리 |
오늘 실습은 AWS 핵심 서비스들이 어떻게 맞물려 돌아가는지 한 번에 볼 수 있어서 좋았다. 특히 Security Group을 서비스 간 소스로 지정하는 방식, Secrets Manager로 DB 자격증명을 관리하는 패턴은 실무에서도 그대로 쓸 수 있는 내용이라 확실히 익혀뒀다. EKS에서도 결국 이 기반 위에서 돌아가는 거니까 기본기를 다시 다진 느낌이었다.
이번 velog는 AWS Kiro를 통해 작성하였다.