AWS 인프라 프로비저닝(Provision AWS Infrastructure)
AWS 인프라 프로비저닝(Provision AWS Infrastructure)
Confident AI가 실행되는 클라우드 인프라를 프로비저닝해요: EKS 클러스터, RDS PostgreSQL 데이터베이스, S3 버킷, 그리고 키리스 IAM 연결(EKS Pod Identity). 완료되면 실행 중인 클러스터와 다음 페이지의 Helm 차트에 넣을 출력값들이 생겨요.
출처: 문서
본문
리전은 AWS provider와 프로파일에서 오며 리전 변수가 없어요. 리전과 두 개의 가용영역(AZ)을 한 번 설정하세요:
export AWS_REGION=us-east-1
export AWS_AZ_1=${AWS_REGION}a
export AWS_AZ_2=${AWS_REGION}b
네트워크 생성 (선택)
서로 다른 AZ에 두 개의 비공개 서브넷이 있고 NAT 게이트웨이를 통해 인터넷에 도달하는 VPC를 이미 갖고 있다면 이 단계는 건너뛰세요. 다음 단계에서 기존 ID를 사용하세요.
두 개의 가용영역에 걸쳐 두 개의 공개·비공개 서브넷과 NAT 게이트웨이가 있는 VPC를 만들어요. EKS와 RDS는 비공개 서브넷에서, 공개 서브넷은 NAT 게이트웨이와 인터넷 연결 로드 밸런서를 담당해요. 블록을 순서대로 실행하세요. 각 블록이 다음 블록에 ID를 전달해요.
VPC를 만들고 클러스터와 데이터베이스가 비공개 호스트네임을 확인할 수 있게 DNS를 켜요:
VPC_ID=$(aws ec2 create-vpc --cidr-block 10.20.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=confident-prod-vpc}]' \
--query Vpc.VpcId --output text)
aws ec2 modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-hostnames
aws ec2 modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-support
인터넷 게이트웨이를 연결해요. 공개 서브넷은 인터넷 접근을 위해 여기로 라우팅돼요:
INTERNET_GATEWAY_ID=$(aws ec2 create-internet-gateway --query InternetGateway.InternetGatewayId --output text)
aws ec2 attach-internet-gateway --internet-gateway-id $INTERNET_GATEWAY_ID --vpc-id $VPC_ID
가용영역마다 하나씩, 공개·비공개 서브넷을 각각 두 개 만드세요:
PUBLIC_SUBNET_1=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.20.0.0/20 --availability-zone $AWS_AZ_1 --query Subnet.SubnetId --output text)
PUBLIC_SUBNET_2=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.20.16.0/20 --availability-zone $AWS_AZ_2 --query Subnet.SubnetId --output text)
PRIVATE_SUBNET_1=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.20.128.0/20 --availability-zone $AWS_AZ_1 --query Subnet.SubnetId --output text)
PRIVATE_SUBNET_2=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.20.144.0/20 --availability-zone $AWS_AZ_2 --query Subnet.SubnetId --output text)
ClickHouse는 이 모듈이 만드는 IPv4 전용 EKS 클러스터에서 깔끔하게 실행돼요: 차트가 오퍼레이터 파드를 IPv4(
0.0.0.0)로 청취하도록 고정해서, 주소 패밀리 오류 없이 듀얼 스택 설정이 필요 없어요. 듀얼 스택 VPC만으로는 바뀌지 않아요. 클러스터 자체가 듀얼 스택으로 생성되지 않는 한 노드는 IPv4 전용으로 유지돼요.
나중에 로드 밸런서 컨트롤러가 발견할 수 있게 서브넷에 태그를 붙여요:
aws ec2 create-tags --resources $PUBLIC_SUBNET_1 $PUBLIC_SUBNET_2 --tags Key=kubernetes.io/role/elb,Value=1
aws ec2 create-tags --resources $PRIVATE_SUBNET_1 $PRIVATE_SUBNET_2 --tags Key=kubernetes.io/role/internal-elb,Value=1
첫 번째 공개 서브넷에 NAT 게이트웨이를 만들어요. 비공개 노드는 아웃바운드 풀을 위해 이걸 통해 인터넷에 도달하되, 인바운드 노출은 없어요:
NAT_EIP_ALLOCATION_ID=$(aws ec2 allocate-address --domain vpc --query AllocationId --output text)
NAT_GATEWAY_ID=$(aws ec2 create-nat-gateway --subnet-id $PUBLIC_SUBNET_1 --allocation-id $NAT_EIP_ALLOCATION_ID --query NatGateway.NatGatewayId --output text)
aws ec2 wait nat-gateway-available --nat-gateway-ids $NAT_GATEWAY_ID
공개 서브넷을 인터넷 게이트웨이로 라우팅해요:
PUBLIC_ROUTE_TABLE_ID=$(aws ec2 create-route-table --vpc-id $VPC_ID --query RouteTable.RouteTableId --output text)
aws ec2 create-route --route-table-id $PUBLIC_ROUTE_TABLE_ID --destination-cidr-block 0.0.0.0/0 --gateway-id $INTERNET_GATEWAY_ID
aws ec2 associate-route-table --route-table-id $PUBLIC_ROUTE_TABLE_ID --subnet-id $PUBLIC_SUBNET_1
aws ec2 associate-route-table --route-table-id $PUBLIC_ROUTE_TABLE_ID --subnet-id $PUBLIC_SUBNET_2
비공개 서브넷을 NAT 게이트웨이로 라우팅해요:
PRIVATE_ROUTE_TABLE_ID=$(aws ec2 create-route-table --vpc-id $VPC_ID --query RouteTable.RouteTableId --output text)
aws ec2 create-route --route-table-id $PRIVATE_ROUTE_TABLE_ID --destination-cidr-block 0.0.0.0/0 --nat-gateway-id $NAT_GATEWAY_ID
aws ec2 associate-route-table --route-table-id $PRIVATE_ROUTE_TABLE_ID --subnet-id $PRIVATE_SUBNET_1
aws ec2 associate-route-table --route-table-id $PRIVATE_ROUTE_TABLE_ID --subnet-id $PRIVATE_SUBNET_2
Terraform 설정에 붙여 넣을 VPC와 비공개 서브넷 ID를 출력해요:
echo "confident_vpc_id = \"$VPC_ID\""
echo "confident_private_subnet_ids = [\"$PRIVATE_SUBNET_1\", \"$PRIVATE_SUBNET_2\"]"
코드 샌드박스 이미지 미러링 (필수)
코드 기반 및 트랜스포머 지표는 샌드박스형 Lambda에서 실행되며, confident-code-sandbox-aws 이미지를 실행해요. Lambda는 같은 계정의 ECR에 있는 컨테이너 이미지만 실행할 수 있으므로, 공개 이미지를 여러분의 ECR로 미러링해야 해요.
ECR 리포지토리를 만들고 Docker를 로그인해요:
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
ECR_REGISTRY=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
aws ecr create-repository --repository-name confident-code-sandbox-aws --region $AWS_REGION
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_REGISTRY
공개 이미지를 가져와 ECR로 푸시해요. 마지막 줄이 Terraform 설정용 이미지 URI를 출력해요:
docker pull confidentai/confident-code-sandbox-aws:latest
docker tag confidentai/confident-code-sandbox-aws:latest $ECR_REGISTRY/confident-code-sandbox-aws:latest
docker push $ECR_REGISTRY/confident-code-sandbox-aws:latest
echo "confident_code_executor_lambda_image_uri = \"$ECR_REGISTRY/confident-code-sandbox-aws:latest\""
Terraform 설정 작성
공개 모듈을 참조하는 main.tf를 만들고, 앞의 두 단계에서 나온 값을 채워요. 각 변수의 역할:
- 네트워크:
confident_vpc_id와confident_private_subnet_ids는 네트워크 단계에서 (또는 자체 VPC를 써서). - 네이밍:
confident_environment와confident_environment_code가prod네이밍 컨벤션을 모든 리소스에 적용해요. - 접근:
confident_public_eks는 클러스터 API를 머신에 노출해요. 비공개 전용 엔드포인트를 원하면false로. - 내구성:
confident_rds_deletion_protection은 데이터베이스를 실수 삭제에서 보호해요. - 관리형 서비스:
confident_create_secrets_manager와confident_managed_redis_enabled가 권장 시크릿 스토어와 Redis를 켜고,confident_database_ingress_cidrs는 노드가 Redis에 닿게 해요 (VPC CIDR 사용). - 코드 실행기:
confident_code_executor_lambda_image_uri는 미러링 단계가 출력한 ECR 이미지 URI.
provider "aws" {
region = "us-east-1"
}
module "confident_ai" {
source = "confident-ai/confident-ai/aws"
version = "~> 0.1"
confident_vpc_id = "vpc-xxxxxxxx"
confident_private_subnet_ids = ["subnet-aaaa", "subnet-bbbb"]
confident_environment = "prod"
confident_environment_code = "p"
confident_public_eks = true
confident_rds_deletion_protection = true
confident_create_secrets_manager = true
confident_managed_redis_enabled = true
confident_database_ingress_cidrs = ["10.20.0.0/16"]
confident_code_executor_enabled = true
confident_code_executor_lambda_image_uri = "<ECR image URI from the mirror step>"
}
output "helm_values" {
value = module.confident_ai.helm_values
sensitive = true
}
리포지토리 안에서 작업하고 싶다면
terraform-aws-confident-ai를 클론해module블록 대신terraform.tfvars파일에 같은 변수를 넣으세요.
원격 상태 구성 (선택)
이걸 건너뛰면 로컬 상태를 사용해요. 팀이나 실제 환경이라면 상태를 S3 버킷에 두세요.
terraform {
backend "s3" {
bucket = "confident-tfstate"
key = "confident-ai/aws/terraform.tfstate"
region = "us-east-1"
}
}
적용(Apply)
terraform init
terraform plan
terraform apply
EKS 클러스터와 RDS를 만드는 데는 대략 15-20분이 걸려요.
클러스터 연결
eval "$(terraform output -raw configure_kubectl)"
kubectl get nodes
EKS에는 기본 스토리지 클래스가 없고, ClickHouse와 Redis는 디스크가 필요해요. gp3 기본값을 한 번 만들어요:
kubectl apply -f - <<'EOF'
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
type: gp3
encrypted: "true"
allowVolumeExpansion: true
EOF
출력값 읽기
다음 페이지의 Helm 차트가 이 값들을 필요로 해요. terraform output helm_values가 바로 붙여 넣을 수 있는 스니펫을 출력하거나, 개별로 읽어요. 각 줄의 주석은 그것이 넣어줄 Helm 값을 나타내요:
terraform output -raw database_url # secrets.data.DATABASE_URL
terraform output test_cases_bucket # storage.testCasesBucket
terraform output payloads_bucket # storage.payloadsBucket
terraform output -raw region # storage.aws.region
terraform output code_executor_function_name # codeExecutor.aws.lambdaFunctionName
앱이 EKS Pod Identity를 사용하므로 ServiceAccount에 어노테이션이 필요 없고, Terraform이 이미 IAM 역할을 연결했어요.
관리형 시크릿과 Redis (권장)
위의 모듈 블록이 둘 다 프로비저닝해요. Deploy 페이지가 External Secrets Operator를 설치하고 차트에 연결해요:
- Secrets Manager + External Secrets Operator (
confident_create_secrets_manager = true): Terraform이 빈 시크릿을 만들고 Pod Identity를 통해 ESO에 읽기 접근을 부여해요. - ElastiCache for Redis (
confident_managed_redis_enabled = true): 클러스터 내부 대신 관리형 Redis.confident_database_ingress_cidrs가 노드가 닿을 수 있도록 VPC에 포트 6379를 열어요.terraform output -raw redis_url이redis.externalUrl값을 줘요.
더 간단한 구성이 좋다면 둘 다
false로 두어 시크릿을 Kubernetes Secret에 담고 Redis를 클러스터에서 실행하세요. Deploy 페이지의 더 간단한 옵션을 참고하세요.
입력 참조(Inputs reference)
가장 자주 설정할 변수들이에요. 완전하고 항상 최신인 목록은 Terraform Registry의 모듈 입력을 참고하세요.
필수
| Variable | 설명 |
|---|---|
confident_vpc_id |
배포할 기존 VPC. |
confident_private_subnet_ids |
서로 다른 가용영역에 있는 기존 비공개 서브넷 두 개 이상 (EKS와 RDS). |
자주 설정 (선택, 프로덕션 기본값 포함)
| Variable | 기본값 | 설명 |
|---|---|---|
confident_environment / confident_environment_code |
stage / s |
리소스에 적용되는 네이밍 컨벤션 (prod / p 사용). |
confident_public_eks |
false |
클러스터 API 엔드포인트 노출. |
confident_eks_admin_arn |
"" |
cluster-admin을 부여받는 추가 IAM 프린시펄. |
confident_node_instance_types / confident_node_group_desired_size |
["m6i.2xlarge"] / 4 |
노드 그룹 크기. |
confident_code_executor_enabled / confident_code_executor_lambda_image_uri |
true / "" |
코드 실행기 Lambda와 그 ECR 이미지 URI. |
confident_create_secrets_manager |
false |
Secrets Manager 시크릿과 ESO Pod Identity. |
confident_managed_redis_enabled / confident_database_ingress_cidrs |
false / [] |
ElastiCache와, 그에 닿도록 허용된 CIDR. |
confident_rds_deletion_protection / confident_rds_multi_az |
false / true |
RDS 내구성 옵션. |
리전은 AWS provider에서 오며 리전 변수가 없어요.
다음 단계
Helm으로 배포
Terraform 출력값으로 앱을 설치하고 HTTPS로 노출.