티스토리 뷰
AWS CloudFormation
AWS CloudFormation은 AWS 인프라 리소스를 수동으로 클릭해서 생성하지 않고, 코드 기반의 정의된 템플릿을 프로비전하거나 업데이트할 수 있는 무료 서비스이다.
JSON과 YAML을 지원하여 IaC(Infrastructure as Code, 클라우드에서 인프라를 코드로 관리하는 방법)를 통해 항상 일관된 아키텍처를 구현할 수 있고, 인프라의 구성을 다른 사람과 공유하거나 복제하여 재사용이 가능하고, 리소스의 변경 및 이력을 추적할 수 있다는 장점이 있다.
AWS CloudFormation 주요 개념

CloudFormation은 위 그림처럼 템플릿을 작성하고 CreateStack 명령을 통해 템플릿 + 파라미터를 입력하면, 해당 논리적 리소스들을 기반으로 EC2 인스턴스, EBS, S3 버킷 등 물리 리소스(Pysical Resource)를 생성한다. CloudFormation을 사용하면서 다루는 주요 키워드 및 개념은 다음과 같다.
- 템플릿(Template): JSON or YAML 형식의 텍스트 파일을 AWS 인프라를 구성하는 리소스들의 청사진
- 프로비전할 리소스를 정의하고 리소스간의 관계를 정의
- 다양한 섹션과 기능들로 구성
- 재사용 가능
- 논리적 리소스(Logical Resource): 템플릿을 기반으로 실제 프로비전되는 리소스를 대표하는 논리적 개념
- 템플릿 + 사용자의 파라메터/프로비전 시점의 값들
- 스택(Stack): CloudFormation으로 리소스를 프로비전할 때 관련된 리소스를 묶은 단위
- 스택 ID와 이름으로 구분 -> ID는 글로벌 고유 값 / 이름은 리전 단위 고유 값
- 논리적 리소스의 구성을 실제 리소스로 반영
- 생성, 업데이트, 삭제가 모두 스택 단위로 처리
- 즉, 논리적 리소스가 변경되면 실제 리소스도 변경, 스택 삭제 시 모든 리소스 삭제
CloudFormation 템플릿의 Section
Format Version/Description(optional)

- 템플릿 버전 및 설명을 명시하는 섹션
- Description 섹션은 반드시 Format Version 바로 뒤에 위치 필요
Resources

- 스택에서 실제로 프로비전할 리소스를 정의하는 유일한 필수 섹션
- 리소스의 구성
- Logical Name: 스택 안에서 리소스를 구분하기 위한 아이디
- 실제 리소스 이름/아이디랑은 다른 개념으로 스택 안에서만 통용(일종의 반 번호)
- 유형(Type): 리소스의 유형(예: S3, EC2, Elastic IP 등)
- AWS::ProductIdentifier:ResourceType 형식(예: AWS::EC2::Instance)
- 리소스 속성(Resource Attribute): 리소스 자체의 공통적인 속성을 정의
- 삭제, 업데이트, 리소스의 전후 관계 등을 정의
- 속성(Property): 리소스의 유형별로 자세한 속성을 정의
- 예시: EC2의 속성 -> EC2 인스턴스 유형, AMI, 보안그룹, EBS 설정, 태그(이름) 등
- 다른 리소스 혹은 받은 파라미터를 참조하여 설정 가능
- Logical Name: 스택 안에서 리소스를 구분하기 위한 아이디
Parameters(optional)


- 템플릿을 프로비전하는 시점에 논리적 리소스에 전달하는 값을 정의하여 커스터마이징하는 섹션
- 종류
- 일반 파라미터: 템플릿 프로비전 시 사용자에게 받는 값
- 예: EC2 Instance 타입, AMI ID / CloudFront DNS 값 / RDS DB 기본 패스워드 등
- 활용 예시: 하나의 정형화된 아키텍처를 찍어낼 때 DNS만 교체 혹은 인스턴스 타입만 교체
- Pseudo 파라미터: CloudFormation에서 템플릿 프로비전 시 동적으로 넣어주는 파라미터
- 종류
- AWS::AccountId: 리소스가 프로비전되는 계정의 Account ID
- AWS::Region: 리소스가 프로비전되는 계정의 리전
- AWS::StackName: 리소스가 프로비전되는 계정의 스택 이름
- 주요 사용 사례
- 리소스의 이름 등에 계정명 혹은 리전명 등을 포함하여 중복된 이름이 나오지 않도록 설정
- 프로비전 시점에 다양한 리소스 조회
- !Ref 혹은 !Sub(특정 값들(파라미터, 다른 함수 등)로 스트링을 만드는 함수)로 활용
- 종류
- 일반 파라미터: 템플릿 프로비전 시 사용자에게 받는 값
- 형식
- Logical ID: 스택 내에서 통용되는 파라미터의 이름
- 타입: String, Number, List<Number> 등 + AWS 지정 타입으로 AWS 리소스 지정 가능(예: Subnet, EC2 Keypair, AMI ID 등)
- 설명: 파라미터의 설명
- Default: 기본값
- Allowed Value: 허용 가능한 값
- 기타: 파라미터 조건(길이, 정규식 등), NoEcho(암호 등에 활용)
- !Ref Intrinsic Function으로 참조
Mappings(optional)

- CloudFormation에서 미리 Map으로 데이터를 정의할 수 있는 섹션
- 프로비전하는 상황에 따라 알맞은 값을 선택할 수 있도록 미리 데이터를 저장
- Fn::FindInMap intrinsic function으로 활용
- Fn::FindInMap [MapName, TopLevelKey, SecondLevelKey]
- !FindInMap [MapName, TopLevelKey, SecondLevelKey]
- 주용 사용사례
- 리전별 AMI 선택
- Route53 Hosted Zone 선택 등
Outputs(optional)

- 리소스가 프로비전된 후에 필요한 정보를 스택 바깥으로 내보내는 섹션
- 내보낸 정보는 다른 스택에서 참조해서 쓰거나 콘솔에서 확인 가능
- 구성
- Logical ID
- 설명
- 값
- 이름
Conditions(optional)

- 조건에 따라 리소스 생성의 의사결정 가능
- 예: Dev 리소스라면 더 작은 타입의 EC2 인스턴스
- 예: Prod라면 Multi-AZ로 DB 구성
- !If Intrinsic Function으로 활용
그 외 Section
Metadata(optional)
- 템플릿에 대한 추가 데이터 명시
Rules(optional)
- 파라미터를 검증하는 정책 명시
Transform(optional)
- 템플릿에서 사용하는 매크로 등을 정의
Intrinsic function

- CloudFormation에서 지원하는 기본 함수로 스택의 관리를 위한 다양한 기능을 제공
- Resource 속성, Outputs, Metadata, Update Policy에서만 사용 가능
- 두 가지 호출 방식
- Full Function: Fn:: 함수명
- Short Form: !함수명
- 예: Ref: 파라미터 혹은 리소스를 참조하기 위한 함수 -> "Ref: Logical ID" / !Ref Logical ID
- 주요 사용 사례
- 다른 리소스 참조, AWS 계정의 AZ 목록 확보, 리소스의 속성 불러오기 등
- 주요 Intrinsic function 목록
- Ref: 파라미터 혹은 리소스를 참조하기 위한 함수
- "Ref : Logical ID" / !Ref Logical ID
- Fn::GetAtt : 리소스의 속성을 가져오는 함수
- Fn::GetAtt: [LogicalID, attributeName] / !GetAtt logicalID.attributeName
- Ref: 파라미터 혹은 리소스를 참조하기 위한 함수
- Fn::Sub: 특정 값들(파라미터, 다른 함수 등)로 스트링을 만드는 함수
- 기타: GetAz, Join, Length, Base64, Transform, Cidr 등
리소스 속성(Resource Attribute)
리소스 속성은 리소스마다 각각 다른 속성들을 정의하는 것이 아닌 모든 리소스의 공통적인 속성을 정의
CreationPolicy

- 리소스의 생성 시 특정 조건을 만족해야 완료 처리될 수 있도록 설정
- 예: Wait Condition을 사용하여 EC2에서 웹서버가 설치되어야 EC2 생성이 완료되도록 설정
- Wait Condition: 리소스의 프로비전 중 특정 주체가 로직을 수행 후 성공을 알릴 때까지 리소스 프로비전을 멈추는 구성
- N개의 신호 성공을 N초까지 대기 가능(최대 12시간)
- 별도의 AWS::CloudFormation::WaitCondition 리소스를 생성하거나 리소스의 CreationPolicy에서 설정 가능
- CloudFormation과 소통을 도와주기 위한 Python 기반 스크립트를 사용하여 완료 신호를 설정할 수 있다.
- cfn-signal: CloudFormation의 Wait Condition 리소스(혹은 CreationPolicy가 붙은 리소스)에 처리 완료 신호를 보내주는 스크립트
- cfn-init: 리소스 메타데이터 기반으로 패키지 설치나 파일 생성 등을 담당
- cfn-get-metadata: 특정 경로의 메타데이터를 확보하는 스크립트
DeletionPolicy

- 리소스 삭제 정책
- Delete: 스택 삭제 시 같이 삭제(몇 몇 리소스를 제외하고 기본 옵션)
- Retain: 스택 삭제 시 해당 리소스는 삭제하지 않고 보존
- 주의: 리소스 생성에 실패하여 롤백할 때도 보존되기 때문에 원치않는 리소스가 계속 늘어날 수 있음
- RetainExcepOnCreate: 리소스 처음 생성할 때를 제외하고 보존, 즉 처음 생성 시 실패한다면 삭제
- Snapshot(지원 시): 스냅샷을 지원하는 리소스(EC2, RDS 등)의 경우 삭제 시 스냅샷을 생성하고 삭제
- DB는 백업을 위해 스냅샷을 두는 것을 권장한다.
DependsOn

- 특정 리소스가 생성된 이후 해당 리소스 생성을 시작하도록 설정
- 참고: !Ref, !GetAtt, !Sub로 묶인 경우에는 암시적으로 참조하는 리소스를 생성 후 해당 리소스 생성
- 예: 반드시 RDS가 생성된 이후에 EC2 생성을 시작해서 원활하게 서버가 설정되도록 구성
- 즉 해당 참조가 없는 상태에서 리소스의 생성 순서를 제어하기 위해 사용
UpdatgePolicy / UpdateReplacePolicy
- UpdatePolicy: 리소스의 업데이트시 동작 방식을 정의
- 예: AutoScale의 경우 업데이트 시 인스턴스 업데이트 방식 정의(Replace, Rolling, Schedule)
- 예: ElasticCache의 샤드의 업데이트 방식 정의
- UpdateReplacePolicy: 리소스의 업데이트시 기존 리소스의 교체 방식을 정의
- 예: EC2 인스턴, RDS의 업데이트 시 기존 EBS 볼륨의 스냅샷을 만들 것인지 여부 등을 정의
AWS Systems Manager
AWS Systems Manager는 AWS에서 인프라를 보고 제어하기 위해 사용할 수 있는 AWS 서비스이다. Systems Manager 콘솔을 사용하여 여러 AWS 서비스의 운영 데이터를 보고 AWS 리소스에서 운영 태스크를 자동화할 수 있다.
AWS SSM Parameter Store
AWS에서 API 주소, AMI ID, API Token, 유저아이디/패스워드, 환경변수 등의 정보 등의 주요 설정과 값들을 저장/관리/활용하기 위한 서비스이다. 그 중 Public Parameter는 AWS에서 공식적으로 배포하는 파라미터로 다음 설정값들을 제공한다.
- 각 OS별 최신 AMI의 아이디
- AWS의 모든 리전 목록
- AWS의 모든 서비스 목록
- 특정 서비스를 사용 가능한 리전 목록


Cloudformation 템플릿 안에서 SSM Parameter Store의 값이 참조 가능하기 때문에 AMI Image ID, Endpoint 등의 퍼블릭 파라미터나 DB 패스워드, DB Host명 등의 환경 설정 값을 공유하여 사용할 수 있다. 위에서 확인할 수 있듯이 파라미터 스토어 내 공용 파라미터에서 EC2 이미지 아이디를 담은 파라미터 스토어 타입으로 정의해서 사용할 수 있다.
Amazon EKS 배포
| 자원 | 이름 | 정보 | |||||
| VPC | myeks-VPC | IP CIDR: 192.168.0.0/16 | |||||
| 서브넷 | myeks-PublicSubnet1 | IP CIDR: 192.168.1.0/24, ap-northeast-2a | |||||
| 서브넷 | myeks-PublicSubnet2 | IP CIDR: 192.168.2.0/24, ap-northeast-2b | |||||
| 서브넷 | myeks-PublicSubnet3 | IP CIDR: 192.168.3.0/24, ap-northeast-2c | |||||
| 서브넷 | myeks-PrivateSubnet1 | IP CIDR: 192.168.11.0/24, ap-northeast-2a | |||||
| 서브넷 | myeks-PrivateSubnet2 | IP CIDR: 192.168.12.0/24, ap-northeast-2b | |||||
| 서브넷 | myeks-PrivateSubnet3 | IP CIDR: 192.168.13.0/24, ap-northeast-2c | |||||
| 인터넷 게이트웨이 | igw | 연결: myeks-VPC | |||||
| 라우팅 테이블 | myeks-PublicSubnetRT | 연결: myeks-PublicSubnet1/2, 경로: 0.0.0.0/0 -> igw | |||||
| 라우팅 테이블 | myeks-PrivateSubnetRT | 연결: myeks-PrivateSubnet1/2, 경로: local | |||||
| EC2 인스턴스 | myeks-host | 연결: myeks-PublicSubnet1, 퍼블릭 IP 할당 설치: kubectl, helm, eksctl, awscli, docker, krew, kube_ps1, etc. |
|||||
| 보안 그룹 | myeks-host-SG | 연결: myeks-host, 인바운드 규칙: 각자 PC의 퍼블릭 IP/32, 모든 트래픽 | |||||
위에서 확인한 CloudFormation을 통해 템플릿을 작성하여 Amazon EKS 배포를 진행할 수 있다. 스택에서 프로비전될 리소스는 위와 같다.
EKS 배포 아키텍처

myeks-VPC가 생성되고, 서울 리전 내 세 개의 가용 영역에 퍼블릭 서브넷 3개와 프라이빗 서브넷 3개가 각각 생성된다. 각 서브넷은 개별 라우팅 테이블을 가지고 있으며, 퍼블릭 서브넷에는 인터넷 게이트웨이가 연결되어 인터넷 통신이 가능하도록 구성된다.
그리고 myeks-host라는 EC2 인스턴스가 퍼블릭 서브넷에 생성되어 EKS 관리 작업을 위한 Bastion Host 역할을 수행한다. 해당 인스턴스에 SSH CIDR에 따라 보안 그룹을 설정한 후 접근하여 EKS를 직접 관리할 수 있다.
작업용 인스턴스에서 정의된 명령을 통해 Amazon EKS 클러스터를 생성하면 컨트롤 플레인은 AWS에서 관리하는 별도의 VPC에 구성되고, EKS owned ENI를 통해 연결된다. 그리고 관리형 노드 그룹이 함께 생성되며, 3개의 가용 영역에 워커 노드가 하나씩 총 3개가 배포된다.
파라미터 및 메타데이터
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "<<<<< Deploy EC2 >>>>>"
Parameters:
- KeyName
- MyIamUserAccessKeyID
- MyIamUserSecretAccessKey
- SgIngressSshCidr
- MyInstanceType
- LatestAmiId
- Label:
default: "<<<<< EKS Config >>>>>"
Parameters:
- ClusterBaseName
- KubernetesVersion
- WorkerNodeInstanceType
- WorkerNodeCount
- WorkerNodeVolumesize
- Label:
default: "<<<<< Region AZ >>>>>"
Parameters:
- TargetRegion
- AvailabilityZone1
- AvailabilityZone2
- AvailabilityZone3
- Label:
default: "<<<<< VPC Subnet >>>>>"
Parameters:
- VpcBlock
- PublicSubnet1Block
- PublicSubnet2Block
- PublicSubnet3Block
- PrivateSubnet1Block
- PrivateSubnet2Block
- PrivateSubnet3Block
파라미터
Parameters:
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instances. Linked to AWS Parameter
Type: AWS::EC2::KeyPair::KeyName
ConstraintDescription: must be the name of an existing EC2 KeyPair.
MyIamUserAccessKeyID:
Description: IAM User - AWS Access Key ID (won't be echoed)
Type: String
NoEcho: true
MyIamUserSecretAccessKey:
Description: IAM User - AWS Secret Access Key (won't be echoed)
Type: String
NoEcho: true
SgIngressSshCidr:
Description: The IP address range that can be used to communicate to the EC2 instances
Type: String
MinLength: '9'
MaxLength: '18'
Default: 0.0.0.0/0
AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
MyInstanceType:
Description: Enter t2.micro, t2.small, t2.medium, t3.micro, t3.small, t3.medium. Default is t2.micro.
Type: String
Default: t3.medium
AllowedValues:
- t2.micro
- t2.small
- t2.medium
- t3.micro
- t3.small
- t3.medium
LatestAmiId:
Description: (DO NOT CHANGE)
Type: 'AWS::SSM::Parameter::Value'
Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64'
AllowedValues:
- /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
ClusterBaseName:
Type: String
Default: myeks
AllowedPattern: "[a-zA-Z][-a-zA-Z0-9]*"
Description: must be a valid Allowed Pattern '[a-zA-Z][-a-zA-Z0-9]*'
ConstraintDescription: ClusterBaseName - must be a valid Allowed Pattern
KubernetesVersion:
Description: Enter Kubernetes Version, 1.25 ~ 1.32
Type: String
Default: 1.32
WorkerNodeInstanceType:
Description: Enter EC2 Instance Type. Default is t3.medium.
Type: String
Default: t3.medium
WorkerNodeCount:
Description: Worker Node Counts
Type: String
Default: 3
WorkerNodeVolumesize:
Description: Worker Node Volumes size
Type: String
Default: 30
TargetRegion:
Type: String
Default: ap-northeast-2
AvailabilityZone1:
Type: String
Default: ap-northeast-2a
AvailabilityZone2:
Type: String
Default: ap-northeast-2b
AvailabilityZone3:
Type: String
Default: ap-northeast-2c
VpcBlock:
Type: String
Default: 192.168.0.0/16
PublicSubnet1Block:
Type: String
Default: 192.168.1.0/24
PublicSubnet2Block:
Type: String
Default: 192.168.2.0/24
PublicSubnet3Block:
Type: String
Default: 192.168.3.0/24
PrivateSubnet1Block:
Type: String
Default: 192.168.11.0/24
PrivateSubnet2Block:
Type: String
Default: 192.168.12.0/24
PrivateSubnet3Block:
Type: String
Default: 192.168.13.0/24
Metadata Section을 활용하여 CloudFormation의 파라미터를 입력 받을 때 파라미터 그룹 / 라벨링 / 순서 조정이 가능하다. 파라미터는 길어서 토글로 정리했다. 그러면 메타데이터 섹션으로 그룹화된 파라미터를 하나씩 살펴보자.
Deploy EC2

Deploy EC2 파라미터 그룹은 Bastion Host용 인스턴스 설정이다. Bastion Host는 외부에서 내부망에 있는 리소스에 접근하기 위해 보안 게이트웨이 역할의 EC2 인스턴스이다. 따라서 퍼블릭 서브넷에 위치해야 하며, 프라이빗 서브넷 안의 리소스에 접근하기 위해서는 오직 Bastion을 통해서만 접근할 수 있기 때문에 네트워크 보안상 가장 중요한 방화벽 호스트로 위에서는 SgIngressSshCidr 설정을 통해 접근 가능한 IP 범위를 조정할 수 있다.
- KeyName: EC2 인스턴스에 SSH로 접근 시 사용될 키를 지정
- IAM 유저 설정
- MyIamUserAccessKeyID: IAM 유저의 Access Key ID로 EC2 내에서 aws configure나 CLI 접근 시 사용 가능
- MyIamUserSecretAccessKey: 위 AccessKeyID와 쌍을 이루는 Secret Access Key
- "NoEcho: true"로 설정해서 스택에서 별표(***)로 마스킹 처리된 파라미터 값을 반환하여 노출 방지
- SgIngressSshCidr: EC2 인스턴스의 SSH 포트에 접근 가능한 IP 범위를 지정
- "{본인 IP}/32"로 설정하는 경우 본인 IP 외 외부에서 접근 방지 가능
- MyInstanceType: 배포할 EC2 인스턴스의 타입 지정
- LastestAmiId: SSM Manager Store의 공유 파라미터에서 설정된 AMI ID 설정
EKS Config

EKS Config 파라미터 그룹은 EKS 클러스터 생성을 위한 설정이다. 각 입력 파라미터는 다음과 같다.
- ClusterBaseName: EKS 클러스터의 기본 이름 설정하여 리소스 이름, NodeGroup 등에 접두사처럼 사용됨
- KubernetesVersion: 생성할 클러스터의 쿠버네티스 버전
- WorkerNodeInstanceType: 워커 노드의 EC2 인스턴스 타입 지정
- t3.medium은 vCPU 2개, 메모리 4GB의 범용 인스턴스
- WorkerNodeCount: 생성할 워커 노드 개수
- WorkerNodeVolumesize: 각 워커 노드의 EBS 루트 볼륨 크기로 OS, 컨테이너 이밎, 로그, 임시 파일 등에 사용됨
Region AZ 및 VPC Subnet

위 파라미터 그룹은 EKS 클러스터가 생성될 리전과 가용 영역(AZ), 그리고 VPC와 서브넷(CIDR) 구성을 지정하는 설정이다.
- Region AZ
- TargetRegion으로 리전을 설정하고, AvailabilityZone을 통해 가용 영역을 설정
- EKS 클러스터와 모든 리소스가 해당 리전에 생성
- VPC Subnet
- VpcBlock은 전체 VPC의 CIDR 블록으로 192.168.0.0/16로 설정하면 최대 2^16(65,535)개의 IP 주소 제공
- 퍼블릭 서브넷으로 외부 인터넷 통신이 가능한 인스턴스를 배치
- 프라이빗 서브넷으로 인터넷 접근은 없으며, 보통 EKS 워커 노드나 내부 서비스 배치
VPC 및 Subnet 리소스
VPC 리소스
EksVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcBlock
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub ${ClusterBaseName}-VPC

- CidrBlock: VPC가 갖는 IP 주소 범위 설정
- EnableDnsSupport: VPC 내 인스턴스에서 Amazon Route 53 Resolver를 통해 DNS 이름을 IP로 해석할 수 있도록 설정
- EnableDnsHostnames: 서브넷에 생성된 인스턴스에 대해 DNS 호스트 이름 자동 부여 여부
서브넷 리소스
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZone1
CidrBlock: !Ref PublicSubnet1Block
VpcId: !Ref EksVPC
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${ClusterBaseName}-PublicSubnet1
- Key: kubernetes.io/role/elb
Value: 1
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Ref AvailabilityZone1
CidrBlock: !Ref PrivateSubnet1Block
VpcId: !Ref EksVPC
Tags:
- Key: Name
Value: !Sub ${ClusterBaseName}-PrivateSubnet1
- Key: kubernetes.io/role/internal-elb
Value: 1
- MapPublicIpOnLaunch: true
- 서브넷에 EC2 인스턴스를 생성할 때 자동으로 퍼블릭 IP를 부여하는 설정
- kubernetes.io/role/elb: 1, kubernetes.io/role/internal-elb: 1
- 해당 태그를 설정해야 EKS가 해당 서브넷을 로드밸런서 배포 대상으로 인식하고, ELB를 해당 서브넷에 생성한다.
- 참고: https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/network-load-balancing.html#_prerequisites
인터넷 게이트웨이 및 라우팅 테이블
InternetGateway:
Type: AWS::EC2::InternetGateway
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref EksVPC
PublicSubnetRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref EksVPC
Tags:
- Key: Name
Value: !Sub ${ClusterBaseName}-PublicSubnetRouteTable
PublicSubnetRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicSubnetRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicSubnetRouteTable
PrivateSubnetRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref EksVPC
Tags:
- Key: Name
Value: !Sub ${ClusterBaseName}-PrivateSubnetRouteTable
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet1
RouteTableId: !Ref PrivateSubnetRouteTable


위 서브넷에서 MapPublicIpOnLaunch: true 설정을 통해 EC2 인스턴스 생성 시 퍼블릭 IP을 자동으로 부여한다고 해서 인터넷 통신이 가능한 것이 아니다. 서브넷 라우팅 테이블이 인터넷 게이트웨이를 경유하도록 설정되어 있어야 하고, 보안 그룹에서 인바운드/아웃바운드 규칙 허용이 필요하다. 위 리소스에 대한 설명은 다음과 같다.
- InternetGateway: 퍼블릭 서브넷이 외부 인터넷과 통신할 수 있는 진입점 생성
- VPCGatewayAttachment: IGW와 EksVPC 연결할 수 있도록 설정
- PublicSubnetRouteTable: EksVPC 내 퍼블릭 서브넷이 사용할 라우팅 테이블 리소스
- PublicSubnetRoute: 위 PublicSubnetRouteTable 라우팅 테이블에 0.0.0.0/0 IP 대역에 대해 인터넷 게이트웨이로 경로 지정
- PublicSubnet1RouteTableAssociation: 퍼블릭용 라우팅 테이블과 서브넷을 1:1로 연결
- PrivateSubnetRouteTable: EksVPC 내 프라이빗 서브넷이 사용할 라우팅 테이블 리소스
- PrivateSubnet1RouteTableAssociation: 프라이빗용 라우팅 테이블과 서브넷을 1:1로 연결
Bastion Host 인스턴스 및 EKS 클러스터, 노드 그룹 생성
보안 그룹
EKSEC2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: eksctl-host Security Group
VpcId: !Ref EksVPC
Tags:
- Key: Name
Value: !Sub ${ClusterBaseName}-HOST-SG
SecurityGroupIngress:
- IpProtocol: '-1'
#FromPort: '22'
#ToPort: '22'
CidrIp: !Ref SgIngressSshCidr

보안 그룹 리소스로 파라미터 SgIngressSshCidr를 통해 소스를 지정하여 Bastion Host용 인스턴스가 접근할 수 있는 블록 범위를 제어할 수 있다.
Bastion Host 인스턴스 및 EKS 클러스터, 노드 그룹 생성
EKSEC2:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref MyInstanceType
ImageId: !Ref LatestAmiId
KeyName: !Ref KeyName
Tags:
- Key: Name
Value: !Sub ${ClusterBaseName}-bastion-EC2
NetworkInterfaces:
- DeviceIndex: 0
SubnetId: !Ref PublicSubnet1
GroupSet:
- !Ref EKSEC2SG
AssociatePublicIpAddress: true
PrivateIpAddress: 192.168.1.100
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp3
VolumeSize: 30
DeleteOnTermination: true
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
hostnamectl --static set-hostname "${ClusterBaseName}-bastion-EC2"
# IAM User Credentials
export AWS_ACCESS_KEY_ID=${MyIamUserAccessKeyID}
export AWS_SECRET_ACCESS_KEY=${MyIamUserSecretAccessKey}
export AWS_DEFAULT_REGION=${AWS::Region}
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
echo "export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" >> /etc/profile
echo "export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" >> /etc/profile
echo "export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION" >> /etc/profile
echo "export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)" >> /etc/profile
# ...
# Create EKS Cluster & Nodegroup
#eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=ng1 --node-type=${WorkerNodeInstanceType} --nodes ${WorkerNodeCount} --node-volume-size=${WorkerNodeVolumesize} --vpc-public-subnets "$PubSubnet1","$PubSubnet2","$PubSubnet3" --version ${KubernetesVersion} --ssh-access --ssh-public-key ${KeyName} --with-oidc --external-dns-access --full-ecr-access --dry-run > myeks.yaml
eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=ng1 --node-type=${WorkerNodeInstanceType} --nodes ${WorkerNodeCount} --node-volume-size=${WorkerNodeVolumesize} --node-ami-family AmazonLinux2023 --vpc-public-subnets "$PubSubnet1","$PubSubnet2","$PubSubnet3" --version ${KubernetesVersion} --ssh-access --ssh-public-key /root/.ssh/id_rsa.pub --with-oidc --external-dns-access --full-ecr-access --dry-run > myeks.yaml
sed -i 's/certManager: false/certManager: true/g' myeks.yaml
sed -i 's/ebs: false/ebs: true/g' myeks.yaml
cat <<EOT >> myeks.yaml
addons:
- name: vpc-cni
version: latest
attachPolicyARNs:
- arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
- name: kube-proxy
version: latest
- name: coredns
version: latest
EOT
nohup eksctl create cluster -f myeks.yaml --verbose 4 --kubeconfig "/root/.kube/config" 1> /root/create-eks.log 2>&1 &
echo 'cloudinit End!'
위 Bastion Host를 생성한 후 UserData를 통해 클러스터를 생성하는 것을 확인할 수 있다. 그 전에 파라미터로 등록한 IAM 유저의 Access Key ID와 Secret Access Key를 설정하여 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION을 환경변수로 등록하여 AWS CLI, eksctl, kubectl 등의 명령어를 사용할 수 있도록 한다.
그리고, EKS 클러스터에는 Add-on을 통해 Amazon이 관리하는 쿠버네티스 필수 구성 요소(컴포넌트)가 필요하다. eksctl 명령어를 살펴보면 처음에 --dry-run 플래그를 통해 실제 클러스터를 만들지 않고, eksctl 내부적으로 생성하는 구성을 myeks.yaml에 저장하고, 클러스터에 필요한 Addon들을 선언한 후 실제 클러스터를 생성하고 있다.
- CorDNS: DNS 서비스
- kube-proxy: 네트워크 프록시 및 서비스 로드밸런싱
- VPC CNI: AWS VPC와 연동되는 네트워크 플러그인
생성 결과



myeks 클러스터가 생성되고, ng1이라는 노드 그룹과 가용 영역 마다 myeks-ng-Node라는 워커 노드가 생성된 것을 확인할 수 있다. 그리고 Bastion Host용 인스턴스가 생성된 것도 확인할 수 있다. Bastion Host에서 EKS 클러스터를 관리 작업을 수행할 수 있다.
CloudFormation 다운
출처
[AWS] CloudFormation으로 쿠버네티스 클러스터 생성
CloudNet@과 함께하는 Amazon EKS 기본 강의
'기타 > AWS' 카테고리의 다른 글
| Terraform (1) | 2025.08.15 |
|---|---|
| K8S - 서비스 API 카테고리 (1) | 2025.07.24 |
| EKS 기본 아키텍처 (2) | 2025.07.17 |
| Amazon ELB (0) | 2025.07.08 |
| Amazon VPC (3) | 2025.07.03 |
- Total
- Today
- Yesterday
- spring session
- socket
- Synchronized
- 람다
- annotation
- EKS
- NeXTSTEP
- 낙관적 락
- 구름톤챌린지
- 구름톤 챌린지
- 비관적 락
- pessimistic lock
- jvm 메모리 구조
- 트랜잭션
- postgresql
- mdcfilter
- 넥스트스탭
- Java
- redis session
- sql
- TDD
- Redisson
- nginx
- mysql
- 카프카
- 분산 락
- nginx configuration
- Kafka
- transaction
- spring webflux
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
