인프라 구축기
EC2의 t3.large로 Airflow를 구축한 상황에서 AI 학습 및 예측을 진행해야 하는 문제에 직면했다. 그러나 Airflow Worker(LocalExecutor)만 사용한다면, 과부하가 올 것이라는 확신이 있었기에 AI를 위한 추가 인스턴스를 생성하고자 하였다. 이에 따라 Terraform 작업을 진행하게 되었으며, 진행 내용은 다음과 같다.
- AI Server를 위한 EC2 인스턴스 추가
- Airflow에서 EC2를 Start/Stop 하기 위한 IAM 사용자 생성
- lambda 함수에 AI Server를 추가하고, 특정 시간에 Start/Stop 되도록 수정
EC2 인스턴스 추가 및 사용자 생성
instance/ec2.tf
- AMI는 Amazon Linux 2023, 인스턴스는 t2.micro 사용
- EC2에서 AI 학습 과정을 진행하므로 python과 가상환경을 구성하는 user_data 작성
- public subnet에 위치시킨 뒤 이후 코딩 작업이 마무리 되면 private로 이동 예정
...
# Create ec2 (ai server)
resource "aws_instance" "ai_server" {
ami = "ami-02c329a4b4aba6a48"
instance_type = "t2.micro"
subnet_id = data.terraform_remote_state.vpc.outputs.public_subnet_2c_1_id
key_name = "popboard-ai-server-keypair"
associate_public_ip_address = true
vpc_security_group_ids = [
data.terraform_remote_state.vpc.outputs.bastion_host_ssh_access_sg_id,
data.terraform_remote_state.vpc.outputs.all_outbound_traffic_sg_id
]
user_data = <<EOF
#! /bin/bash
sudo yum update -y
sudo yum groupinstall "Development Tools" -y
sudo yum install gcc bzip2-devel libffi-devel -y
sudo wget https://www.python.org/ftp/python/3.8.4/Python-3.8.4.tgz
tar -xf Python-3.8.4.tgz
cd Python-3.8.4
./configure --enable-optimizations
sudo make altinstall
cd /home/ec2-user
python3 -m venv venv_ai
source venv_ai/bin/activate
pip install --upgrade pip
EOF
root_block_device {
volume_type = "gp3"
volume_size = 10
delete_on_termination = true
}
tags = {
Name = "popboard-ai-server"
}
}
instance/output.tf
- lambda 함수에서 ai_server의 id를 환경변수에 등록하기 위한 output 추가
...
output "ai_server_id" {
value = aws_instance.ai_server.id
}
instance/iam.tf
- AmazonEC2FullAccess 정책을 적용한 IAM 사용자 생성
- 이 사용자를 Airflow의 Connection에 등록해 EC2Start/StopInstanceOperator로 조작
...
# Create iam user to access ai ec2 from airflow ec2
resource "aws_iam_user" "ec2_access_user" {
name = "popboard-ec2-access"
path = "/"
}
# Create iam policy to access ec2 for airflow ec2
resource "aws_iam_policy" "ec2_ec2_policy" {
name = "popboard-ec2-ec2-policy"
path = "/"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "ec2:*"
Effect = "Allow"
Resource = "*"
},
{
Action = "elasticloadbalancing:*"
Effect = "Allow"
Resource = "*"
},
{
Action = "cloudwatch:*"
Effect = "Allow"
Resource = "*"
},
{
Action = "autoscaling:*"
Effect = "Allow"
Resource = "*"
},
{
Action = "iam:CreateServiceLinkedRole"
Effect = "Allow"
Resource = "*"
Condition = {
StringEquals = {
"iam:AWSServiceName" = [
"autoscaling.amazonaws.com",
"ec2scheduled.amazonaws.com",
"elasticloadbalancing.amazonaws.com",
"spot.amazonaws.com",
"spotfleet.amazonaws.com",
"transitgateway.amazonaws.com"
]
}
}
}
]
})
}
# Connect policy to user
resource "aws_iam_policy_attachment" "ec2_ec2_attachment" {
name = "popboard-ec2-ec2-attachment"
users = [aws_iam_user.ec2_access_user.name]
policy_arn = aws_iam_policy.ec2_ec2_policy.arn
}
lambda 함수 수정
lambda/lambda_stop.tf : 인스턴스 종료 시간 변경
- 인스턴스가 켜져 있는 시간을 10:00 ~ 22:00 (UTC+9)에서 10:00 ~ 22:30 (UTC+9)로 변경
- 이유는 20분마다 실행되는 DAG의 Logical Date을 올바르게 유지시키기 위함 (자세한 내용은 링크 참고)
...
# Create cloudwatch event rule
resource "aws_cloudwatch_event_rule" "stop_aws_service_schedule" {
name = "popboard-stop-aws-service-schedule"
description = "Stop AWS services at 10:30 PM (UTC+9)"
schedule_expression = "cron(30 13 * * ? *)"
}
...
lambda/lambda_start.tf / lambda/lambda_stop.tf : 환경 변수에 ai_server_id 추가
- 새롭게 생성한 EC2 인스턴스도 10:00 ~ 22:30 (UTC+9)에만 동작하도록 lambda 함수에 등록
# Create lambda function to stop aws service at 10:30 PM (UTC+9)
resource "aws_lambda_function" "stop_aws_service" {
function_name = "popboard-stop-aws-service"
...
environment {
variables = {
INSTANCE_IDS = "${data.terraform_remote_state.instance.outputs.airflow_id},${data.terraform_remote_state.instance.outputs.bastion_host_id},${data.terraform_remote_state.instance.outputs.ai_server_id}"
RDS_INSTANCE_ID = data.terraform_remote_state.storage.outputs.airflow_meta_db_name
}
}
}
# Create lambda function to start aws service at 10 AM (UTC+9)
resource "aws_lambda_function" "start_aws_service" {
function_name = "popboard-start-aws-service"
...
environment {
variables = {
INSTANCE_IDS = "${data.terraform_remote_state.instance.outputs.airflow_id},${data.terraform_remote_state.instance.outputs.bastion_host_id},${data.terraform_remote_state.instance.outputs.ai_server_id}"
RDS_INSTANCE_ID = data.terraform_remote_state.storage.outputs.airflow_meta_db_name
}
}
}
'Infra > [인프라 구축기] Terraform 활용 AWS 인프라 구축' 카테고리의 다른 글
인프라 구축기 (16) : Tableau에서 Metabase로 변경 (0) | 2024.11.21 |
---|---|
인프라 구축기 (15) : Public EC2 Tableau 구축 (0) | 2024.11.15 |
인프라 구축기 (13) : 진행 내용 & 진행 예정 내용 정리 (5) | 2024.11.03 |
인프라 구축기 (12) - S3에 있는 Terraform 상태 파일 활용하기 (0) | 2024.11.02 |
인프라 구축기 (11) - lambda IAM role 수정 (1) | 2024.10.29 |