1 # VPC B의 CIDR을 10.0.0.0/16으로 설정하는 CloudFormation 템플릿입니다. 4-1 vpc.yaml AWSTemplateFormatVersion: '2010-09-09' Description: "간단한 VPC 생성 예제" # 1. 변수 입력 (Parameters): 재사용성을 위해 값을 입력받음 Parameters: VpcCidr: Type: String Default: 10.0.0.0/16 Description: "VPC의 IP 대역" # 2. 리소스 정의 (Resources): 실제 생성할 AWS 자원 Resources: MyVPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCidr EnableDnsSupport: true Tags: - Key: Name Value: My-CFN-VPC # 3. 결과 출력 (Outputs): 생성된 자원의 ID나 값을 출력 Outputs: VpcId: Description: "생성된 VPC의 ID" Value: !Ref MyVPC 2 # VPC B(10.0.0.0/16) 내부에 Public 서브넷과 Private 서브넷을 나누고, 외부 통신을 위한 인터넷 게이트웨이(IGW)까지 연결하는 전체 구성 코드를 작성했습니다. 4-2. vpc-pub1,pri1.yaml AWSTemplateFormatVersion: '2010-09-09' Description: VPC B with Public/Private Subnets and IGW Parameters: VpcCidr: Type: String Default: 10.0.0.0/16 PublicSubnetCidr: Type: String Default: 10.0.1.0/24 PrivateSubnetCidr: Type: String Default: 10.0.2.0/24 Resources: # 1. VPC 생성 VPCB: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCidr EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: VPC-B # 2. 인터넷 게이트웨이 (IGW) 생성 및 연결 InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: VPC-B-IGW GatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPCB InternetGatewayId: !Ref InternetGateway # 3. 서브넷 생성 PublicSubnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPCB CidrBlock: !Ref PublicSubnetCidr MapPublicIpOnLaunch: true # EC2 생성 시 자동으로 공인 IP 할당 AvailabilityZone: !Select [ 0, !GetAZs '' ] # 첫 번째 AZ 사용 (예: ap-northeast-2a) Tags: - Key: Name Value: VPC-B-Public-Subnet PrivateSubnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPCB CidrBlock: !Ref PrivateSubnetCidr AvailabilityZone: !Select [ 0, !GetAZs '' ] Tags: - Key: Name Value: VPC-B-Private-Subnet # 4. 라우팅 테이블 (표지판) 설정 # Public Route Table: 모든 트래픽(0.0.0.0/0)을 IGW로 보냄 PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPCB Tags: - Key: Name Value: VPC-B-Public-RT PublicRoute: Type: AWS::EC2::Route DependsOn: GatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway # 서브넷과 라우팅 테이블 연결 (Association) PublicSubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet RouteTableId: !Ref PublicRouteTable # Private Subnet은 별도 라우팅이 없으면 기본적으로 Local 통신만 가능 (안전함) PrivateRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPCB Tags: - Key: Name Value: VPC-B-Private-RT PrivateSubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnet RouteTableId: !Ref PrivateRouteTable Outputs: VpcId: Value: !Ref VPCB PublicSubnetId: Value: !Ref PublicSubnet PrivateSubnetId: Value: !Ref PrivateSubnet ----------------------- 3 # Public 서브넷에 EC2 인스턴스를 하나 띄워서 SSH로 접속해 보는 템플릿 1) # EC2 접속을 위해 미리 키페어를 콘솔에서 만들자. 2) CloudFormation 실행 추가된 기능 EC2 인스턴스: Amazon Linux 2023 최신 이미지를 자동으로 가져와 t3.micro(프리 티어 가능)로 생성합니다. 보안 그룹 (Security Group): 22번 포트(SSH)를 열어 접속을 허용합니다. 키 페어 (Key Pair): 기존에 가지고 계신 키 페어 이름을 입력받아 사용합니다. AWSTemplateFormatVersion: '2010-09-09' Description: VPC B with Public Subnet and EC2 Instance Parameters: # 1. 키 페어 입력 (필수) KeyName: Description: Name of an existing EC2 KeyPair to enable SSH access to the instance Type: AWS::EC2::KeyPair::KeyName ConstraintDescription: must be the name of an existing EC2 KeyPair. # 2. VPC 및 서브넷 설정 VpcCidr: Type: String Default: 10.0.0.0/16 PublicSubnetCidr: Type: String Default: 10.0.1.0/24 # 3. 최신 Amazon Linux 2023 AMI ID 자동 조회 (SSM Parameter Store 사용) LatestAmiId: Type: 'AWS::SSM::Parameter::Value' Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64' Resources: # --- 네트워크 구성 --- VPCB: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCidr EnableDnsSupport: true EnableDnsHostnames: true Tags: [{Key: Name, Value: VPC-B}] InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: [{Key: Name, Value: VPC-B-IGW}] GatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPCB InternetGatewayId: !Ref InternetGateway PublicSubnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPCB CidrBlock: !Ref PublicSubnetCidr MapPublicIpOnLaunch: true # 공인 IP 자동 할당 AvailabilityZone: !Select [ 0, !GetAZs '' ] Tags: [{Key: Name, Value: VPC-B-Public-Subnet}] PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPCB Tags: [{Key: Name, Value: VPC-B-Public-RT}] PublicRoute: Type: AWS::EC2::Route DependsOn: GatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet RouteTableId: !Ref PublicRouteTable # --- 서버 및 보안 구성 (새로 추가됨) --- # 4. 보안 그룹: SSH(22) 허용 InstanceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable SSH access via port 22 VpcId: !Ref VPCB SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 # 주의: 실무에서는 본인의 IP(예: 203.0.113.0/32)로 제한하는 것이 좋습니다. Tags: [{Key: Name, Value: VPC-B-SG}] # 5. EC2 인스턴스 생성 PublicInstance: Type: AWS::EC2::Instance Properties: InstanceType: t3.micro ImageId: !Ref LatestAmiId KeyName: !Ref KeyName NetworkInterfaces: - AssociatePublicIpAddress: true DeviceIndex: 0 GroupSet: - !Ref InstanceSecurityGroup SubnetId: !Ref PublicSubnet Tags: [{Key: Name, Value: VPC-B-Web-Server}] Outputs: # 6. 접속 정보 출력 InstancePublicIP: Description: Public IP address of the newly created EC2 instance Value: !GetAtt PublicInstance.PublicIp SSHCommand: Description: SSH connection command Value: !Sub "ssh -i ${KeyName}.pem ec2-user@${PublicInstance.PublicIp}" 4 사용 방법 키 페어 준비: AWS 콘솔(EC2 > Key Pairs)에 my-key 같은 키 페어가 미리 있어야 합니다. 스택 생성: CloudFormation 콘솔에서 이 파일을 업로드합니다. 파라미터 입력: KeyName 칸에 준비한 키 페어 이름(예: my-key)을 입력합니다. 접속: 생성이 완료되면 Outputs 탭에서 InstancePublicIP를 확인하고 SSH로 접속합니다. ssh -i my-key.pem ec2-user@<출력된_IP> 5 이 서버에 Nginx나 Apache 같은 웹 서버를 자동으로 설치하고, 브라우저에서 바로 접속되는 페이지를 띄우고 싶으신가요? (User Data 스크립트를 추가하면 가능합니다) 네, 좋은 선택입니다. Apache 웹 서버(httpd)를 자동으로 설치하고, 80번 포트(HTTP)를 개방하여 브라우저에서 접속할 수 있는 페이지를 띄우겠습니다. 이를 위해 템플릿에 두 가지 중요한 변경 사항이 적용되었습니다. 보안 그룹 (Security Group): 기존 22번(SSH) 외에 80번(HTTP) 포트를 추가로 허용합니다. 사용자 데이터 (User Data): 서버가 처음 부팅될 때 자동으로 실행할 리눅스 명령어를 심어놓습니다. (웹 서버 설치 및 HTML 파일 생성) 6 AWSTemplateFormatVersion: '2010-09-09' Description: VPC B with Public Web Server (Apache) Parameters: KeyName: Description: Name of an existing EC2 KeyPair Type: AWS::EC2::KeyPair::KeyName VpcCidr: Type: String Default: 10.0.0.0/16 PublicSubnetCidr: Type: String Default: 10.0.1.0/24 LatestAmiId: Type: 'AWS::SSM::Parameter::Value' Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64' Resources: # --- 1. 네트워크 구성 (VPC, IGW, Subnet, RouteTable) --- VPCB: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCidr EnableDnsSupport: true EnableDnsHostnames: true Tags: [{Key: Name, Value: VPC-B}] InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: [{Key: Name, Value: VPC-B-IGW}] GatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPCB InternetGatewayId: !Ref InternetGateway PublicSubnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPCB CidrBlock: !Ref PublicSubnetCidr MapPublicIpOnLaunch: true AvailabilityZone: !Select [ 0, !GetAZs '' ] Tags: [{Key: Name, Value: VPC-B-Public-Subnet}] PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPCB Tags: [{Key: Name, Value: VPC-B-Public-RT}] PublicRoute: Type: AWS::EC2::Route DependsOn: GatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet RouteTableId: !Ref PublicRouteTable # --- 2. 보안 그룹 (HTTP 포트 80 추가) --- WebServerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable SSH and HTTP access VpcId: !Ref VPCB SecurityGroupIngress: - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Tags: [{Key: Name, Value: VPC-B-Web-SG}] # --- 3. EC2 인스턴스 (User Data 추가) --- PublicInstance: Type: AWS::EC2::Instance Properties: InstanceType: t3.micro ImageId: !Ref LatestAmiId KeyName: !Ref KeyName NetworkInterfaces: - AssociatePublicIpAddress: true DeviceIndex: 0 GroupSet: - !Ref WebServerSecurityGroup SubnetId: !Ref PublicSubnet Tags: [{Key: Name, Value: VPC-B-Web-Server}] # 서버 부팅 시 실행될 스크립트 (Base64 인코딩 필수) UserData: Fn::Base64: !Sub | #!/bin/bash dnf update -y dnf install -y httpd systemctl start httpd systemctl enable httpd echo "

Hello from CloudFormation!

VPC B Created Successfully.

" > /var/www/html/index.html Outputs: WebsiteURL: Description: URL to access the web server Value: !Sub "http://${PublicInstance.PublicIp}" InstancePublicIP: Value: !GetAtt PublicInstance.PublicIp 7 확인 방법 스택 생성 완료 대기: 상태가 CREATE_COMPLETE가 될 때까지 기다립니다. 약 1~2분 추가 대기: EC2는 바로 생성되지만, 내부에서 yum update 및 Apache 설치가 완료되는 데 시간이 조금 걸립니다. 접속: Outputs 탭에 있는 WebsiteURL을 클릭하거나 브라우저 주소창에 붙여넣으세요. 화면에 "Hello from CloudFormation!"이 보이면 성공입니다. 8 # 지금은 서버가 1대뿐입니다. 만약 트래픽이 늘어나거나 서버가 죽을 것을 대비해, 오토 스케일링 그룹(ASG)과 로드 밸런서(ALB)를 붙여서 고가용성(HA) 아키텍처로 확장 # 4-5-cf-ASG.yaml AWSTemplateFormatVersion: '2010-09-09' Description: High Availability Web Server with ALB and Auto Scaling Parameters: KeyName: Description: Name of an existing EC2 KeyPair Type: AWS::EC2::KeyPair::KeyName LatestAmiId: Type: 'AWS::SSM::Parameter::Value' Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64' Resources: # --- 1. 네트워크 (VPC, IGW, 2개의 Public Subnet) --- VPCB: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsSupport: true EnableDnsHostnames: true Tags: [{Key: Name, Value: HA-VPC}] InternetGateway: Type: AWS::EC2::InternetGateway GatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPCB InternetGatewayId: !Ref InternetGateway # 첫 번째 가용 영역 서브넷 PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPCB CidrBlock: 10.0.1.0/24 MapPublicIpOnLaunch: true AvailabilityZone: !Select [ 0, !GetAZs '' ] # 첫 번째 AZ (예: ap-northeast-2a) Tags: [{Key: Name, Value: HA-Public-Subnet-1}] # 두 번째 가용 영역 서브넷 PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPCB CidrBlock: 10.0.2.0/24 MapPublicIpOnLaunch: true AvailabilityZone: !Select [ 1, !GetAZs '' ] # 두 번째 AZ (예: ap-northeast-2b) Tags: [{Key: Name, Value: HA-Public-Subnet-2}] PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPCB PublicRoute: Type: AWS::EC2::Route DependsOn: GatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway # 두 서브넷 모두 라우팅 테이블 연결 Subnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet1 RouteTableId: !Ref PublicRouteTable Subnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet2 RouteTableId: !Ref PublicRouteTable # --- 2. 보안 그룹 (Security Groups) --- # ALB용 보안 그룹: 전 세계 모든 곳(0.0.0.0/0)에서 80번 포트 허용 ALBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable HTTP access for ALB VpcId: !Ref VPCB SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 # 웹 서버용 보안 그룹: 오직 ALB로부터 오는 트래픽만 허용 (보안 강화) WebServerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow traffic only from ALB and SSH VpcId: !Ref VPCB SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref ALBSecurityGroup # ALB만 통과 - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 # 관리용 SSH # --- 3. 로드 밸런서 (ALB) 구성 --- ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: My-HA-ALB Scheme: internet-facing Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 SecurityGroups: - !Ref ALBSecurityGroup ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 10 HealthCheckPath: / HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 UnhealthyThresholdCount: 2 Matcher: HttpCode: '200' Port: 80 Protocol: HTTP VpcId: !Ref VPCB TargetType: instance ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref ALBTargetGroup LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 80 Protocol: HTTP # --- 4. 오토 스케일링 그룹 (ASG) & 시작 템플릿 --- LaunchTemplate: Type: AWS::EC2::LaunchTemplate Properties: LaunchTemplateName: !Sub ${AWS::StackName}-LaunchTemplate LaunchTemplateData: ImageId: !Ref LatestAmiId InstanceType: t3.micro KeyName: !Ref KeyName SecurityGroupIds: - !Ref WebServerSecurityGroup UserData: Fn::Base64: !Sub | #!/bin/bash dnf update -y dnf install -y httpd systemctl start httpd systemctl enable httpd # 어떤 서버가 응답하는지 확인하기 위해 인스턴스 ID와 AZ 정보를 표시 EC2ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) AZ=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone) echo "

High Availability Demo

Server ID: $EC2ID

Zone: $AZ

" > /var/www/html/index.html AutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: My-HA-ASG VPCZoneIdentifier: - !Ref PublicSubnet1 - !Ref PublicSubnet2 LaunchTemplate: LaunchTemplateId: !Ref LaunchTemplate Version: !GetAtt LaunchTemplate.LatestVersionNumber MinSize: '2' # 최소 2대는 항상 유지 MaxSize: '4' # 최대 4대까지 확장 가능 DesiredCapacity: '2' TargetGroupARNs: - !Ref ALBTargetGroup HealthCheckType: ELB HealthCheckGracePeriod: 300 Outputs: LoadBalancerDNS: Description: Access this URL to see the Load Balancer in action Value: !Sub "http://${ApplicationLoadBalancer.DNSName}" ------- 테스트 방법 스택 생성: 위 코드로 CloudFormation 스택을 생성합니다. (약 3~5분 소요) 접속: 출력(Outputs) 탭의 LoadBalancerDNS 주소로 접속합니다. 화면에 Server ID: i-0xxxx...와 Zone: ap-northeast-2a 등이 보입니다. 새로고침 연타: 브라우저에서 새로고침을 계속 누르면, Server ID와 Zone이 계속 바뀌는 것을 볼 수 있습니다. (로드 밸런서가 일을 하고 있다는 증거입니다!) 장애 복구 실험 (카오스 엔지니어링): AWS 콘솔(EC2)로 가서 실행 중인 인스턴스 중 하나를 과감하게 '종료(Terminate)' 시키세요. 잠시 후 새로고침을 하면 살아있는 다른 서버가 응답합니다. (서비스 중단 없음) 1~2분 뒤 다시 콘솔을 보면, ASG가 인스턴스 개수가 부족함을 감지하고 새로운 인스턴스를 자동으로 생성해 놓은 것을 볼 수 있습니다. 감사합니다.