diff --git a/environment/prod/main.tf b/environment/prod/main.tf index 320f5e4..960ead5 100644 --- a/environment/prod/main.tf +++ b/environment/prod/main.tf @@ -6,8 +6,8 @@ data "aws_vpc" "default" { module "prod_stack" { source = "../../modules/app_stack" - env_name = "prod" - vpc_id = data.aws_vpc.default.id + env_name = "prod" + vpc_id = data.aws_vpc.default.id ami_id = var.ami_id @@ -15,8 +15,8 @@ module "prod_stack" { ec2_iam_instance_profile = var.ec2_iam_instance_profile # 키페어 및 접속 허용 - key_name = var.key_name - + key_name = var.key_name + # 인스턴스 스펙 instance_type = var.server_instance_type db_instance_class = var.db_instance_class @@ -27,29 +27,26 @@ module "prod_stack" { # RDS 식별자 설정 rds_identifier = var.rds_identifier - + # DB 계정 정보 - db_username = var.db_root_username - db_password = var.db_root_password + db_username = var.db_root_username + db_password = var.db_root_password # DB 엔진 및 암호화 설정 - db_engine_version = var.db_engine_version # MySQL 버전 지정 + db_engine_version = var.db_engine_version # MySQL 버전 지정 db_parameter_group_name = var.db_parameter_group_name # MySQL 파라미터 그룹 지정 - kms_key_arn = var.kms_key_arn # KMS ARN 변수 전달 + kms_key_arn = var.kms_key_arn # KMS ARN 변수 전달 # 추가 유저마다 다른 권한 부여 additional_db_users = var.additional_db_users # Nginx 및 도메인 설정 - domain_name = var.domain_name - cert_email = var.cert_email + domain_name = var.domain_name + cert_email = var.cert_email nginx_conf_name = var.nginx_conf_name - # ssh key 경로 전달 - ssh_key_path = var.ssh_key_path - # Side Infra 관련 변수 전달 - work_dir = var.work_dir + work_dir = var.work_dir alloy_env_name = var.alloy_env_name redis_version = var.redis_version diff --git a/environment/prod/variables.tf b/environment/prod/variables.tf index 0a74365..c81bcf2 100644 --- a/environment/prod/variables.tf +++ b/environment/prod/variables.tf @@ -99,11 +99,6 @@ variable "nginx_conf_name" { type = string } -variable "ssh_key_path" { - description = "Path to the SSH private key file for remote-exec" - type = string -} - variable "work_dir" { description = "Working directory for the application" type = string diff --git a/environment/stage/main.tf b/environment/stage/main.tf index a0b0b44..05baf67 100644 --- a/environment/stage/main.tf +++ b/environment/stage/main.tf @@ -31,9 +31,6 @@ module "stage_stack" { cert_email = var.cert_email nginx_conf_name = var.nginx_conf_name - # ssh key 경로 전달 - ssh_key_path = var.ssh_key_path - # Side Infra 관련 변수 전달 work_dir = var.work_dir alloy_env_name = var.alloy_env_name diff --git a/environment/stage/variables.tf b/environment/stage/variables.tf index e432b29..487ea6a 100644 --- a/environment/stage/variables.tf +++ b/environment/stage/variables.tf @@ -44,11 +44,6 @@ variable "nginx_conf_name" { type = string } -variable "ssh_key_path" { - description = "Path to the SSH private key file for remote-exec" - type = string -} - variable "work_dir" { description = "Working directory for the application" type = string diff --git a/modules/app_stack/ec2.tf b/modules/app_stack/ec2.tf index 6734a28..c8514ba 100644 --- a/modules/app_stack/ec2.tf +++ b/modules/app_stack/ec2.tf @@ -55,7 +55,37 @@ resource "aws_instance" "api_server" { } } -# 설정 및 컨테이너 실행 +locals { + nginx_script_b64 = base64encode(templatefile("${path.module}/scripts/nginx_setup.sh.tftpl", { + domain_name = var.domain_name + email = var.cert_email + conf_file_name = var.nginx_conf_name + })) + + alloy_config = templatefile("${path.module}/../../config/side-infra/config.alloy.tftpl", { + loki_ip = data.aws_instance.monitoring_server.private_ip + }) + + side_infra_script_b64 = base64encode(templatefile("${path.module}/scripts/side_infra_setup.sh.tftpl", { + work_dir = var.work_dir + alloy_env_name = var.alloy_env_name + alloy_config_content = local.alloy_config + redis_version = var.redis_version + redis_exporter_version = var.redis_exporter_version + alloy_version = var.alloy_version + })) + + nginx_ssm_params = jsonencode({ + commands = ["cloud-init status --wait > /dev/null", "echo ${local.nginx_script_b64} | base64 -d | sudo bash"] + executionTimeout = ["3600"] + }) + + side_infra_ssm_params = jsonencode({ + commands = ["cloud-init status --wait > /dev/null", "echo ${local.side_infra_script_b64} | base64 -d | sudo bash"] + executionTimeout = ["3600"] + }) +} + # [리소스 1] Nginx 설정 변경 감지 및 실행 resource "null_resource" "update_nginx" { depends_on = [aws_instance.api_server] @@ -68,30 +98,39 @@ resource "null_resource" "update_nginx" { })) } - connection { - type = "ssh" - user = "ubuntu" - host = aws_instance.api_server.public_ip - private_key = file(var.ssh_key_path) - } - - provisioner "file" { - content = templatefile("${path.module}/scripts/nginx_setup.sh.tftpl", { - domain_name = var.domain_name - email = var.cert_email - conf_file_name = var.nginx_conf_name - }) - destination = "/tmp/update_nginx.sh" - } - - provisioner "remote-exec" { - inline = [ - "cloud-init status --wait > /dev/null", # Docker 설치 대기 - "chmod +x /tmp/update_nginx.sh", - "echo 'Running Updated Nginx Script...'", - "sudo /tmp/update_nginx.sh", - "rm /tmp/update_nginx.sh" - ] + provisioner "local-exec" { + interpreter = ["bash", "-c"] + command = <<-EOT + set -euo pipefail + INSTANCE_ID='${aws_instance.api_server.id}' + COMMAND_ID=$(aws ssm send-command \ + --instance-ids "$INSTANCE_ID" \ + --document-name "AWS-RunShellScript" \ + --parameters '${local.nginx_ssm_params}' \ + --output text \ + --query "Command.CommandId") + ATTEMPTS=0 + while [ "$ATTEMPTS" -lt 360 ]; do + STATUS=$(aws ssm get-command-invocation \ + --command-id "$COMMAND_ID" \ + --instance-id "$INSTANCE_ID" \ + --query "Status" --output text 2>/dev/null || echo "Pending") + case "$STATUS" in + Success) exit 0 ;; + Failed|Cancelled|TimedOut|Undeliverable) + echo "SSM command $STATUS" >&2 + aws ssm get-command-invocation \ + --command-id "$COMMAND_ID" \ + --instance-id "$INSTANCE_ID" \ + --query "StandardErrorContent" --output text >&2 + exit 1 ;; + esac + ATTEMPTS=$((ATTEMPTS + 1)) + sleep 10 + done + echo "SSM command timed out after 3600s" >&2 + exit 1 + EOT } } @@ -112,34 +151,38 @@ resource "null_resource" "update_side_infra" { })) } - connection { - type = "ssh" - user = "ubuntu" - host = aws_instance.api_server.public_ip - private_key = file(var.ssh_key_path) - } - - provisioner "file" { - content = templatefile("${path.module}/scripts/side_infra_setup.sh.tftpl", { - work_dir = var.work_dir - alloy_env_name = var.alloy_env_name - alloy_config_content = templatefile("${path.module}/../../config/side-infra/config.alloy.tftpl", { - loki_ip = data.aws_instance.monitoring_server.private_ip - }) - redis_version = var.redis_version - redis_exporter_version = var.redis_exporter_version - alloy_version = var.alloy_version - }) - destination = "/tmp/update_side_infra.sh" - } - - provisioner "remote-exec" { - inline = [ - "cloud-init status --wait > /dev/null", # Docker 설치 대기 - "chmod +x /tmp/update_side_infra.sh", - "echo 'Running Updated Side Infra Script...'", - "sudo /tmp/update_side_infra.sh", - "rm /tmp/update_side_infra.sh" - ] + provisioner "local-exec" { + interpreter = ["bash", "-c"] + command = <<-EOT + set -euo pipefail + INSTANCE_ID='${aws_instance.api_server.id}' + COMMAND_ID=$(aws ssm send-command \ + --instance-ids "$INSTANCE_ID" \ + --document-name "AWS-RunShellScript" \ + --parameters '${local.side_infra_ssm_params}' \ + --output text \ + --query "Command.CommandId") + ATTEMPTS=0 + while [ "$ATTEMPTS" -lt 360 ]; do + STATUS=$(aws ssm get-command-invocation \ + --command-id "$COMMAND_ID" \ + --instance-id "$INSTANCE_ID" \ + --query "Status" --output text 2>/dev/null || echo "Pending") + case "$STATUS" in + Success) exit 0 ;; + Failed|Cancelled|TimedOut|Undeliverable) + echo "SSM command $STATUS" >&2 + aws ssm get-command-invocation \ + --command-id "$COMMAND_ID" \ + --instance-id "$INSTANCE_ID" \ + --query "StandardErrorContent" --output text >&2 + exit 1 ;; + esac + ATTEMPTS=$((ATTEMPTS + 1)) + sleep 10 + done + echo "SSM command timed out after 3600s" >&2 + exit 1 + EOT } } diff --git a/modules/app_stack/rds.tf b/modules/app_stack/rds.tf index 47d4f0d..9cda261 100644 --- a/modules/app_stack/rds.tf +++ b/modules/app_stack/rds.tf @@ -2,16 +2,16 @@ resource "aws_db_instance" "default" { count = var.enable_rds ? 1 : 0 - identifier = var.rds_identifier - allocated_storage = 20 - engine = "mysql" - engine_version = var.db_engine_version - instance_class = var.db_instance_class - username = var.db_username - password = var.db_password - parameter_group_name = var.db_parameter_group_name - copy_tags_to_snapshot = true - skip_final_snapshot = true + identifier = var.rds_identifier + allocated_storage = 20 + engine = "mysql" + engine_version = var.db_engine_version + instance_class = var.db_instance_class + username = var.db_username + password = var.db_password + parameter_group_name = var.db_parameter_group_name + copy_tags_to_snapshot = true + skip_final_snapshot = true vpc_security_group_ids = [aws_security_group.db_sg[count.index].id] storage_encrypted = true diff --git a/modules/app_stack/variables.tf b/modules/app_stack/variables.tf index 1c5028d..aa41e15 100644 --- a/modules/app_stack/variables.tf +++ b/modules/app_stack/variables.tf @@ -124,12 +124,6 @@ variable "nginx_conf_name" { type = string } -# [Remote SSH용 변수] -variable "ssh_key_path" { - description = "Path to the SSH private key file for remote-exec" - type = string -} - # [Side Infrastructure 관련 변수] variable "work_dir" { description = "Working directory for the application"