From e59c206a95ab8e701437b53c94cbdff5591082c1 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 17:42:40 +0900 Subject: [PATCH 1/9] =?UTF-8?q?chore:=20=EB=A1=9C=EB=93=9C=EB=B0=B8?= =?UTF-8?q?=EB=9F=B0=EC=84=9C=20=EC=A0=91=EA=B7=BC=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EB=B0=8F=20=EC=BB=B4=ED=93=A8=ED=8A=B8=20=EC=9A=A9=EB=9F=89=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/environments/prod/compute.tf | 4 ++-- terraform/environments/prod/load-balancer.tf | 14 +++++++++----- terraform/environments/prod/variables.tf | 18 ++++++++++++++++++ terraform/modules/load-balancer/main.tf | 9 +++++++++ terraform/modules/load-balancer/variables.tf | 7 ++++++- 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/terraform/environments/prod/compute.tf b/terraform/environments/prod/compute.tf index 83dbf16..71aeedb 100644 --- a/terraform/environments/prod/compute.tf +++ b/terraform/environments/prod/compute.tf @@ -52,8 +52,8 @@ module "web_servers" { # 공통 인스턴스 설정 machine_type = var.web_machine_type source_image = var.web_source_image - boot_disk_size_gb = 50 - boot_disk_type = "pd-ssd" # 프로덕션 환경은 SSD 디스크를 사용합니다. + boot_disk_size_gb = var.web_machine_ssd + boot_disk_type = "pd-ssd" enable_external_ip = false tags = ["web-server", var.environment] labels = { diff --git a/terraform/environments/prod/load-balancer.tf b/terraform/environments/prod/load-balancer.tf index e357df1..10638c2 100644 --- a/terraform/environments/prod/load-balancer.tf +++ b/terraform/environments/prod/load-balancer.tf @@ -25,11 +25,15 @@ module "load_balancer" { backend_timeout_sec = 30 session_affinity = "CLIENT_IP" backend_groups = var.use_instance_group ? [ - { - group = module.web_servers.instance_group_instance_group - balancing_mode = "UTILIZATION" - max_utilization = 0.8 - } + merge( + { + group = module.web_servers.instance_group_instance_group + balancing_mode = var.lb_type == "NETWORK" ? "CONNECTION" : "UTILIZATION" + }, + var.lb_type == "NETWORK" ? {} : { + max_utilization = 0.8 + } + ) ] : [] ssl_certificates = var.ssl_certificates diff --git a/terraform/environments/prod/variables.tf b/terraform/environments/prod/variables.tf index a13fe2c..c5d02c6 100644 --- a/terraform/environments/prod/variables.tf +++ b/terraform/environments/prod/variables.tf @@ -91,6 +91,12 @@ variable "web_machine_type" { default = "e2-standard-2" # 운영 환경에 맞춘 고성능 인스턴스입니다. } +variable "web_machine_ssd" { + description = "웹 서버에 사용할 머신 용량입니다." + type = number + default = 30 +} + variable "web_source_image" { description = "웹 서버 부팅 디스크에 사용할 이미지입니다." type = string @@ -144,3 +150,15 @@ variable "ssl_certificates" { type = list(string) default = [] } + +# Tags +variable "common_tags" { + description = "공통 태그입니다." + type = map(string) + default = { + Project = "pinhouse" + Environment = "prod" + Version = "v1" + ManagedBy = "Terraform" + } +} diff --git a/terraform/modules/load-balancer/main.tf b/terraform/modules/load-balancer/main.tf index e0b5c71..907d218 100644 --- a/terraform/modules/load-balancer/main.tf +++ b/terraform/modules/load-balancer/main.tf @@ -127,6 +127,15 @@ resource "google_compute_region_backend_service" "backend_service" { # 선택적으로 연결 드레이닝 타임아웃을 적용합니다. connection_draining_timeout_sec = var.connection_draining_timeout + + lifecycle { + precondition { + condition = alltrue([ + for backend in var.backend_groups : lookup(backend, "balancing_mode", "CONNECTION") == "CONNECTION" + ]) + error_message = "NETWORK 로드 밸런서의 backend_groups balancing_mode는 CONNECTION만 사용할 수 있습니다." + } + } } # ======================================== diff --git a/terraform/modules/load-balancer/variables.tf b/terraform/modules/load-balancer/variables.tf index da8833d..581b1eb 100644 --- a/terraform/modules/load-balancer/variables.tf +++ b/terraform/modules/load-balancer/variables.tf @@ -84,9 +84,14 @@ variable "health_check_ids" { # 백엔드 서비스 변수 # ======================================== variable "backend_protocol" { - description = "백엔드 서비스 프로토콜입니다. TCP, UDP, SSL 중 하나를 사용합니다." + description = "백엔드 서비스 프로토콜입니다. TCP, UDP, UNSPECIFIED 중 하나를 사용합니다." type = string default = "TCP" + + validation { + condition = contains(["TCP", "UDP", "UNSPECIFIED"], var.backend_protocol) + error_message = "backend_protocol은 TCP, UDP, UNSPECIFIED 중 하나여야 합니다." + } } variable "backend_timeout_sec" { From 4f889f7b5e71e9502ee4bf5d4da672fc834a97c9 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 17:53:10 +0900 Subject: [PATCH 2/9] =?UTF-8?q?style:=20=ED=85=8C=EB=9D=BC=ED=8F=BC=20?= =?UTF-8?q?=EA=B3=B5=ED=86=B5=20=ED=83=9C=EA=B7=B8=20=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?(#5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/environments/prod/compute.tf | 35 ++++++------------- .../prod/terraform.tfvars.example | 2 +- terraform/environments/prod/variables.tf | 18 +++++----- terraform/modules/compute/main.tf | 23 ++++++++---- terraform/modules/compute/variables.tf | 6 ++-- terraform/modules/nat-instance/main.tf | 6 ++-- terraform/modules/nat-instance/variables.tf | 4 +-- terraform/modules/storage/main.tf | 10 ++++-- terraform/modules/storage/variables.tf | 6 ++-- 9 files changed, 56 insertions(+), 54 deletions(-) diff --git a/terraform/environments/prod/compute.tf b/terraform/environments/prod/compute.tf index 71aeedb..9868db6 100644 --- a/terraform/environments/prod/compute.tf +++ b/terraform/environments/prod/compute.tf @@ -24,29 +24,13 @@ module "web_servers" { # 관리형 인스턴스 그룹을 사용하지 않을 때만 개별 인스턴스를 정의합니다. instances = !var.use_instance_group && var.create_web_instances ? tomap({ web1 = { - name = "${var.environment}-web-01" - zone = "${var.region}-a" - machine_type = var.web_machine_type - enable_external_ip = false # 프로덕션 환경은 로드 밸런서를 통한 접근만 허용합니다. - tags = ["web-server", var.environment] - labels = { - environment = var.environment - role = "web" - } + name = "${var.environment}-web-01" + zone = "${var.region}-a" + machine_type = var.web_machine_type + enable_external_ip = false # 프로덕션 환경은 로드 밸런서를 통한 접근만 허용합니다. + tags = ["web-server", var.environment] deletion_protection = true # 실수로 삭제되지 않도록 보호합니다. } - web2 = { - name = "${var.environment}-web-02" - zone = "${var.region}-b" - machine_type = var.web_machine_type - enable_external_ip = false - tags = ["web-server", var.environment] - labels = { - environment = var.environment - role = "web" - } - deletion_protection = true - } }) : tomap({}) # 공통 인스턴스 설정 @@ -56,10 +40,11 @@ module "web_servers" { boot_disk_type = "pd-ssd" enable_external_ip = false tags = ["web-server", var.environment] - labels = { - environment = var.environment - role = "web" - } + + # 태그 + common_tags = merge(var.common_tags, { + Service = "Backend" + }) # 서비스 계정 설정 service_account_email = var.service_account_email diff --git a/terraform/environments/prod/terraform.tfvars.example b/terraform/environments/prod/terraform.tfvars.example index b98ede3..0180814 100644 --- a/terraform/environments/prod/terraform.tfvars.example +++ b/terraform/environments/prod/terraform.tfvars.example @@ -30,7 +30,7 @@ autoscaling_max_replicas = 5 web_machine_type = "e2-standard-2" web_source_image = "ubuntu-os-cloud/ubuntu-2204-lts" - +web_machine_ssd = 30 # ======================================== # 스토리지 관련 값 # ======================================== diff --git a/terraform/environments/prod/variables.tf b/terraform/environments/prod/variables.tf index c5d02c6..6e0db8a 100644 --- a/terraform/environments/prod/variables.tf +++ b/terraform/environments/prod/variables.tf @@ -64,7 +64,7 @@ variable "create_web_instances" { variable "instance_group_size" { description = "관리형 인스턴스 그룹의 목표 인스턴스 수입니다." type = number - default = 2 + default = 1 } variable "enable_autoscaling" { @@ -76,7 +76,7 @@ variable "enable_autoscaling" { variable "autoscaling_min_replicas" { description = "오토스케일링 최소 인스턴스 수입니다." type = number - default = 2 + default = 1 } variable "autoscaling_max_replicas" { @@ -121,7 +121,7 @@ variable "create_storage_buckets" { variable "storage_location" { description = "스토리지 버킷을 생성할 위치입니다." type = string - default = "ASIA" # 운영 환경에서는 멀티 리전을 기본값으로 사용합니다. + default = "ASIA-NORTHEAST3" # 비용 절감을 위해 단일 리전을 기본값으로 사용합니다. } variable "allowed_cors_origins" { @@ -151,14 +151,16 @@ variable "ssl_certificates" { default = [] } -# Tags +# ======================================== +# 공통 태그 변수 +# ======================================== variable "common_tags" { description = "공통 태그입니다." type = map(string) default = { - Project = "pinhouse" - Environment = "prod" - Version = "v1" - ManagedBy = "Terraform" + project = "pinhouse" + environment = "prod" + version = "v1" + managed_by = "terraform" } } diff --git a/terraform/modules/compute/main.tf b/terraform/modules/compute/main.tf index a639930..ed50b39 100644 --- a/terraform/modules/compute/main.tf +++ b/terraform/modules/compute/main.tf @@ -52,8 +52,10 @@ resource "google_compute_instance_template" "template" { # 네트워크 태그입니다. tags = var.tags - # 공통 레이블입니다. - labels = var.labels + # 공통 태그를 GCP 레이블에 반영합니다. + labels = { + for k, v in var.common_tags : lower(k) => lower(v) + } # 선점형 인스턴스일 때 스케줄링 정책을 조정합니다. scheduling { @@ -107,11 +109,11 @@ resource "google_compute_instance" "instances" { enable-oslogin = var.enable_os_login }, var.metadata, - lookup(each.value, "metadata", {}) + coalesce(lookup(each.value, "metadata", null), {}) ) # 인스턴스별 시작 스크립트를 우선 적용합니다. - metadata_startup_script = lookup(each.value, "startup_script", var.startup_script) + metadata_startup_script = coalesce(lookup(each.value, "startup_script", null), var.startup_script) # 서비스 계정 설정입니다. service_account { @@ -120,10 +122,17 @@ resource "google_compute_instance" "instances" { } # 공통 태그와 인스턴스별 태그를 합칩니다. - tags = concat(var.tags, lookup(each.value, "tags", [])) + tags = concat(var.tags, coalesce(lookup(each.value, "tags", null), [])) - # 공통 레이블과 인스턴스별 레이블을 합칩니다. - labels = merge(var.labels, lookup(each.value, "labels", {})) + # 공통 태그와 인스턴스별 태그 맵을 GCP 레이블에 반영합니다. + labels = merge( + { + for k, v in var.common_tags : lower(k) => lower(v) + }, + { + for k, v in coalesce(lookup(each.value, "common_tags", null), {}) : lower(k) => lower(v) + } + ) # 선점형 여부에 따라 스케줄링 정책을 조정합니다. scheduling { diff --git a/terraform/modules/compute/variables.tf b/terraform/modules/compute/variables.tf index 25975d5..2c4ec06 100644 --- a/terraform/modules/compute/variables.tf +++ b/terraform/modules/compute/variables.tf @@ -109,8 +109,8 @@ variable "tags" { default = [] } -variable "labels" { - description = "인스턴스에 적용할 공통 레이블입니다." +variable "common_tags" { + description = "인스턴스에 적용할 공통 태그입니다." type = map(string) default = {} } @@ -135,7 +135,7 @@ variable "instances" { metadata = optional(map(string)) startup_script = optional(string) tags = optional(list(string)) - labels = optional(map(string)) + common_tags = optional(map(string)) deletion_protection = optional(bool) })) default = {} diff --git a/terraform/modules/nat-instance/main.tf b/terraform/modules/nat-instance/main.tf index 5412a66..9dd8e8f 100644 --- a/terraform/modules/nat-instance/main.tf +++ b/terraform/modules/nat-instance/main.tf @@ -60,8 +60,10 @@ resource "google_compute_instance" "nat_instance" { } } - tags = concat(var.tags, [var.nat_instance_tag]) - labels = var.labels + tags = concat(var.tags, [var.nat_instance_tag]) + labels = { + for k, v in var.common_tags : lower(k) => lower(v) + } allow_stopping_for_update = true } diff --git a/terraform/modules/nat-instance/variables.tf b/terraform/modules/nat-instance/variables.tf index 0caab88..06912ea 100644 --- a/terraform/modules/nat-instance/variables.tf +++ b/terraform/modules/nat-instance/variables.tf @@ -105,8 +105,8 @@ variable "tags" { default = [] } -variable "labels" { - description = "NAT 인스턴스에 부여할 레이블입니다." +variable "common_tags" { + description = "NAT 인스턴스에 부여할 공통 태그입니다." type = map(string) default = {} } diff --git a/terraform/modules/storage/main.tf b/terraform/modules/storage/main.tf index 0f8414b..cba1fc3 100644 --- a/terraform/modules/storage/main.tf +++ b/terraform/modules/storage/main.tf @@ -11,10 +11,14 @@ resource "google_storage_bucket" "buckets" { # 버킷이 생성될 프로젝트입니다. project = var.project_id - # 기본 레이블과 버킷별 레이블을 병합합니다. + # 기본 태그와 버킷별 태그를 GCP 레이블에 반영합니다. labels = merge( - var.default_labels, - lookup(each.value, "labels", {}) + { + for k, v in var.common_tags : lower(k) => lower(v) + }, + { + for k, v in coalesce(lookup(each.value, "common_tags", null), {}) : lower(k) => lower(v) + } ) # 균일한 버킷 수준 액세스 설정입니다. diff --git a/terraform/modules/storage/variables.tf b/terraform/modules/storage/variables.tf index 6e77f53..83bf49b 100644 --- a/terraform/modules/storage/variables.tf +++ b/terraform/modules/storage/variables.tf @@ -23,8 +23,8 @@ variable "default_storage_class" { } } -variable "default_labels" { - description = "모든 버킷에 공통 적용할 레이블입니다." +variable "common_tags" { + description = "모든 버킷에 공통 적용할 태그입니다." type = map(string) default = {} } @@ -38,7 +38,7 @@ variable "buckets" { name = string location = optional(string) storage_class = optional(string) - labels = optional(map(string)) + common_tags = optional(map(string)) uniform_bucket_level_access = optional(bool) versioning_enabled = optional(bool) force_destroy = optional(bool) From d4f0309947594cdba36e830b9f1fea917be182b0 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 17:55:10 +0900 Subject: [PATCH 3/9] =?UTF-8?q?chore:=20=EB=8B=A8=EC=9D=BC=20=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=20=EB=B0=B8=EB=9F=B0=EC=84=9C=20=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/environments/prod/vpc.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/environments/prod/vpc.tf b/terraform/environments/prod/vpc.tf index f43d0f4..a874a2c 100644 --- a/terraform/environments/prod/vpc.tf +++ b/terraform/environments/prod/vpc.tf @@ -6,7 +6,7 @@ module "vpc" { vpc_name = "${var.project}-${var.environment}-vpc" description = "프로덕션 환경용 VPC 네트워크" - routing_mode = "GLOBAL" + routing_mode = "REGIONAL" # 서브넷 정의 subnets = { From 5b5c4565541c3f48a6963ba77b712f5afd708ab4 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 17:55:34 +0900 Subject: [PATCH 4/9] =?UTF-8?q?fix:=20=EA=B3=B5=ED=86=B5=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=20=EB=B2=84=ED=82=B7?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/environments/prod/storage.tf | 65 +++----------------------- 1 file changed, 6 insertions(+), 59 deletions(-) diff --git a/terraform/environments/prod/storage.tf b/terraform/environments/prod/storage.tf index a893bfa..1b125e5 100644 --- a/terraform/environments/prod/storage.tf +++ b/terraform/environments/prod/storage.tf @@ -6,16 +6,17 @@ module "storage" { project_id = var.project_id default_location = var.storage_location - default_labels = { - environment = var.environment - managed_by = "terraform" - } + + # 태그 + common_tags = merge(var.common_tags, { + Service = "Storage" + }) # 버킷 정의 buckets = merge( var.create_storage_buckets ? tomap({ static_assets = { - name = "${var.project_id}-${var.environment}-static-assets" + name = "${var.project_id}-${var.environment}" storage_class = "STANDARD" uniform_bucket_level_access = true versioning_enabled = true @@ -45,60 +46,6 @@ module "storage" { } ] : [] } - }) : tomap({}), - var.create_storage_buckets ? tomap({ - backups = { - name = "${var.project_id}-${var.environment}-backups" - storage_class = "NEARLINE" - uniform_bucket_level_access = true - versioning_enabled = true - force_destroy = false - public_access_prevention = "enforced" - - # 오래된 백업은 저장 등급을 낮추고 최종적으로 삭제합니다. - lifecycle_rules = [ - { - action = { - type = "SetStorageClass" - storage_class = "COLDLINE" - } - condition = { - age = 90 - } - }, - { - action = { - type = "Delete" - } - condition = { - age = 365 - num_newer_versions = 10 - } - } - ] - } - }) : tomap({}), - var.create_storage_buckets ? tomap({ - logs = { - name = "${var.project_id}-${var.environment}-logs" - storage_class = "STANDARD" - uniform_bucket_level_access = true - versioning_enabled = false - force_destroy = false - public_access_prevention = "enforced" - - # 로그 버킷은 30일 이후 자동 삭제합니다. - lifecycle_rules = [ - { - action = { - type = "Delete" - } - condition = { - age = 30 - } - } - ] - } }) : tomap({}) ) } From f8e075d4b3ddb7f6917702e774032adc692c1624 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 18:04:51 +0900 Subject: [PATCH 5/9] =?UTF-8?q?style:=20=ED=85=8C=EB=9D=BC=ED=8F=BC=20?= =?UTF-8?q?=EA=B3=B5=ED=86=B5=20=ED=83=9C=EA=B7=B8=20=EC=A0=81=EC=9A=A9=20?= =?UTF-8?q?(#5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terraform/environments/prod/compute.tf | 39 +++++++++------------ terraform/environments/prod/variables.tf | 20 +++++++++++ terraform/modules/compute/main.tf | 23 ++++++++---- terraform/modules/compute/variables.tf | 6 ++-- terraform/modules/nat-instance/main.tf | 6 ++-- terraform/modules/nat-instance/variables.tf | 4 +-- terraform/modules/storage/main.tf | 10 ++++-- terraform/modules/storage/variables.tf | 6 ++-- 8 files changed, 71 insertions(+), 43 deletions(-) diff --git a/terraform/environments/prod/compute.tf b/terraform/environments/prod/compute.tf index 83dbf16..db6426f 100644 --- a/terraform/environments/prod/compute.tf +++ b/terraform/environments/prod/compute.tf @@ -24,27 +24,19 @@ module "web_servers" { # 관리형 인스턴스 그룹을 사용하지 않을 때만 개별 인스턴스를 정의합니다. instances = !var.use_instance_group && var.create_web_instances ? tomap({ web1 = { - name = "${var.environment}-web-01" - zone = "${var.region}-a" - machine_type = var.web_machine_type - enable_external_ip = false # 프로덕션 환경은 로드 밸런서를 통한 접근만 허용합니다. - tags = ["web-server", var.environment] - labels = { - environment = var.environment - role = "web" - } + name = "${var.environment}-web-01" + zone = "${var.region}-a" + machine_type = var.web_machine_type + enable_external_ip = false # 프로덕션 환경은 로드 밸런서를 통한 접근만 허용합니다. + tags = ["web-server", var.environment] deletion_protection = true # 실수로 삭제되지 않도록 보호합니다. } web2 = { - name = "${var.environment}-web-02" - zone = "${var.region}-b" - machine_type = var.web_machine_type - enable_external_ip = false - tags = ["web-server", var.environment] - labels = { - environment = var.environment - role = "web" - } + name = "${var.environment}-web-02" + zone = "${var.region}-b" + machine_type = var.web_machine_type + enable_external_ip = false + tags = ["web-server", var.environment] deletion_protection = true } }) : tomap({}) @@ -52,14 +44,15 @@ module "web_servers" { # 공통 인스턴스 설정 machine_type = var.web_machine_type source_image = var.web_source_image - boot_disk_size_gb = 50 + boot_disk_size_gb = var.web_machine_ssd boot_disk_type = "pd-ssd" # 프로덕션 환경은 SSD 디스크를 사용합니다. enable_external_ip = false tags = ["web-server", var.environment] - labels = { - environment = var.environment - role = "web" - } + + # 태그 + common_tags = merge(var.common_tags, { + Service = "Backend" + }) # 서비스 계정 설정 service_account_email = var.service_account_email diff --git a/terraform/environments/prod/variables.tf b/terraform/environments/prod/variables.tf index a13fe2c..1024448 100644 --- a/terraform/environments/prod/variables.tf +++ b/terraform/environments/prod/variables.tf @@ -91,6 +91,12 @@ variable "web_machine_type" { default = "e2-standard-2" # 운영 환경에 맞춘 고성능 인스턴스입니다. } +variable "web_machine_ssd" { + description = "웹 서버 부팅 디스크 크기(GB)입니다." + type = number + default = 50 +} + variable "web_source_image" { description = "웹 서버 부팅 디스크에 사용할 이미지입니다." type = string @@ -144,3 +150,17 @@ variable "ssl_certificates" { type = list(string) default = [] } + +# ======================================== +# 공통 태그 변수 +# ======================================== +variable "common_tags" { + description = "공통 태그입니다." + type = map(string) + default = { + Project = "pinhouse" + Environment = "prod" + Version = "v1" + ManagedBy = "Terraform" + } +} diff --git a/terraform/modules/compute/main.tf b/terraform/modules/compute/main.tf index a639930..ed50b39 100644 --- a/terraform/modules/compute/main.tf +++ b/terraform/modules/compute/main.tf @@ -52,8 +52,10 @@ resource "google_compute_instance_template" "template" { # 네트워크 태그입니다. tags = var.tags - # 공통 레이블입니다. - labels = var.labels + # 공통 태그를 GCP 레이블에 반영합니다. + labels = { + for k, v in var.common_tags : lower(k) => lower(v) + } # 선점형 인스턴스일 때 스케줄링 정책을 조정합니다. scheduling { @@ -107,11 +109,11 @@ resource "google_compute_instance" "instances" { enable-oslogin = var.enable_os_login }, var.metadata, - lookup(each.value, "metadata", {}) + coalesce(lookup(each.value, "metadata", null), {}) ) # 인스턴스별 시작 스크립트를 우선 적용합니다. - metadata_startup_script = lookup(each.value, "startup_script", var.startup_script) + metadata_startup_script = coalesce(lookup(each.value, "startup_script", null), var.startup_script) # 서비스 계정 설정입니다. service_account { @@ -120,10 +122,17 @@ resource "google_compute_instance" "instances" { } # 공통 태그와 인스턴스별 태그를 합칩니다. - tags = concat(var.tags, lookup(each.value, "tags", [])) + tags = concat(var.tags, coalesce(lookup(each.value, "tags", null), [])) - # 공통 레이블과 인스턴스별 레이블을 합칩니다. - labels = merge(var.labels, lookup(each.value, "labels", {})) + # 공통 태그와 인스턴스별 태그 맵을 GCP 레이블에 반영합니다. + labels = merge( + { + for k, v in var.common_tags : lower(k) => lower(v) + }, + { + for k, v in coalesce(lookup(each.value, "common_tags", null), {}) : lower(k) => lower(v) + } + ) # 선점형 여부에 따라 스케줄링 정책을 조정합니다. scheduling { diff --git a/terraform/modules/compute/variables.tf b/terraform/modules/compute/variables.tf index 25975d5..2c4ec06 100644 --- a/terraform/modules/compute/variables.tf +++ b/terraform/modules/compute/variables.tf @@ -109,8 +109,8 @@ variable "tags" { default = [] } -variable "labels" { - description = "인스턴스에 적용할 공통 레이블입니다." +variable "common_tags" { + description = "인스턴스에 적용할 공통 태그입니다." type = map(string) default = {} } @@ -135,7 +135,7 @@ variable "instances" { metadata = optional(map(string)) startup_script = optional(string) tags = optional(list(string)) - labels = optional(map(string)) + common_tags = optional(map(string)) deletion_protection = optional(bool) })) default = {} diff --git a/terraform/modules/nat-instance/main.tf b/terraform/modules/nat-instance/main.tf index 5412a66..9dd8e8f 100644 --- a/terraform/modules/nat-instance/main.tf +++ b/terraform/modules/nat-instance/main.tf @@ -60,8 +60,10 @@ resource "google_compute_instance" "nat_instance" { } } - tags = concat(var.tags, [var.nat_instance_tag]) - labels = var.labels + tags = concat(var.tags, [var.nat_instance_tag]) + labels = { + for k, v in var.common_tags : lower(k) => lower(v) + } allow_stopping_for_update = true } diff --git a/terraform/modules/nat-instance/variables.tf b/terraform/modules/nat-instance/variables.tf index 0caab88..06912ea 100644 --- a/terraform/modules/nat-instance/variables.tf +++ b/terraform/modules/nat-instance/variables.tf @@ -105,8 +105,8 @@ variable "tags" { default = [] } -variable "labels" { - description = "NAT 인스턴스에 부여할 레이블입니다." +variable "common_tags" { + description = "NAT 인스턴스에 부여할 공통 태그입니다." type = map(string) default = {} } diff --git a/terraform/modules/storage/main.tf b/terraform/modules/storage/main.tf index 0f8414b..cba1fc3 100644 --- a/terraform/modules/storage/main.tf +++ b/terraform/modules/storage/main.tf @@ -11,10 +11,14 @@ resource "google_storage_bucket" "buckets" { # 버킷이 생성될 프로젝트입니다. project = var.project_id - # 기본 레이블과 버킷별 레이블을 병합합니다. + # 기본 태그와 버킷별 태그를 GCP 레이블에 반영합니다. labels = merge( - var.default_labels, - lookup(each.value, "labels", {}) + { + for k, v in var.common_tags : lower(k) => lower(v) + }, + { + for k, v in coalesce(lookup(each.value, "common_tags", null), {}) : lower(k) => lower(v) + } ) # 균일한 버킷 수준 액세스 설정입니다. diff --git a/terraform/modules/storage/variables.tf b/terraform/modules/storage/variables.tf index 6e77f53..83bf49b 100644 --- a/terraform/modules/storage/variables.tf +++ b/terraform/modules/storage/variables.tf @@ -23,8 +23,8 @@ variable "default_storage_class" { } } -variable "default_labels" { - description = "모든 버킷에 공통 적용할 레이블입니다." +variable "common_tags" { + description = "모든 버킷에 공통 적용할 태그입니다." type = map(string) default = {} } @@ -38,7 +38,7 @@ variable "buckets" { name = string location = optional(string) storage_class = optional(string) - labels = optional(map(string)) + common_tags = optional(map(string)) uniform_bucket_level_access = optional(bool) versioning_enabled = optional(bool) force_destroy = optional(bool) From 2931d8222bc5c575887304603375eecf5d9928a2 Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 18:31:46 +0900 Subject: [PATCH 6/9] =?UTF-8?q?fix:=20PR=20=ED=8C=8C=EC=9D=B4=ED=94=84?= =?UTF-8?q?=EB=9D=BC=EC=9D=B8=20=EC=8A=A4=ED=82=B5=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/terraform-plan.yml | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index 04a54ec..49b82c6 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -45,25 +45,22 @@ jobs: echo "변경된 파일 목록:" echo "$CHANGED_FILES" - # 변경된 환경을 JSON 배열 문자열로 수집합니다. - ENVIRONMENTS="" - - # prod 환경 파일 변경 여부를 확인합니다. + # prod 환경 또는 공통 모듈 변경 시 prod 환경 Plan을 수행합니다. + ENVIRONMENTS='[]' if echo "$CHANGED_FILES" | grep -q "terraform/environments/prod/"; then - ENVIRONMENTS="$ENVIRONMENTS\"prod\"," + ENVIRONMENTS='["prod"]' fi - # 공통 모듈이 바뀌면 모든 환경에서 Plan을 수행합니다. if echo "$CHANGED_FILES" | grep -q "terraform/modules/"; then - ENVIRONMENTS="\"prod\"" + ENVIRONMENTS='["prod"]' fi - # 마지막 쉼표를 제거하고 JSON 배열 형식으로 변환합니다. - ENVIRONMENTS=$(echo "$ENVIRONMENTS" | sed 's/,$//') - ENVIRONMENTS="[$ENVIRONMENTS]" - echo "감지된 환경: $ENVIRONMENTS" - echo "environments=$ENVIRONMENTS" >> $GITHUB_OUTPUT + { + echo "environments<> "$GITHUB_OUTPUT" # 환경별 Terraform init/fmt/validate/plan을 수행하고 결과 파일을 아티팩트로 남깁니다. terraform-plan-checks: From 3a547f2ac39d550df42166571513c3b37245cc1b Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 18:39:48 +0900 Subject: [PATCH 7/9] =?UTF-8?q?fix:=20PR=20=ED=8C=8C=EC=9D=B4=ED=94=84?= =?UTF-8?q?=EB=9D=BC=EC=9D=B8=20=EC=8A=A4=ED=82=B5=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EC=A7=81=EB=A0=AC=ED=99=94=20=EB=AC=B8=EC=A0=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/terraform-plan.yml | 46 ++++++++++++---------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index 49b82c6..5dc6561 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -26,7 +26,7 @@ jobs: # 변경된 Terraform 파일을 기준으로 영향받는 환경을 계산 detect-changes: name: 변경 환경 감지 - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 outputs: environments: ${{ steps.detect.outputs.environments || '[]' }} steps: @@ -45,33 +45,36 @@ jobs: echo "변경된 파일 목록:" echo "$CHANGED_FILES" - # prod 환경 또는 공통 모듈 변경 시 prod 환경 Plan을 수행합니다. - ENVIRONMENTS='[]' + # 변경된 환경 목록을 배열로 수집합니다. + ENVIRONMENTS=() if echo "$CHANGED_FILES" | grep -q "terraform/environments/prod/"; then - ENVIRONMENTS='["prod"]' + ENVIRONMENTS+=("prod") fi if echo "$CHANGED_FILES" | grep -q "terraform/modules/"; then - ENVIRONMENTS='["prod"]' + ENVIRONMENTS+=("prod") fi - echo "감지된 환경: $ENVIRONMENTS" - { - echo "environments<> "$GITHUB_OUTPUT" + # 중복을 제거한 뒤 JSON 배열 문자열로 변환합니다. + if [ ${#ENVIRONMENTS[@]} -eq 0 ]; then + ENVIRONMENTS_JSON='[]' + else + ENVIRONMENTS_JSON=$(printf '%s\n' "${ENVIRONMENTS[@]}" | sort -u | jq -R . | jq -cs .) + fi + + echo "감지된 환경: $ENVIRONMENTS_JSON" + echo "environments=$ENVIRONMENTS_JSON" >> "$GITHUB_OUTPUT" # 환경별 Terraform init/fmt/validate/plan을 수행하고 결과 파일을 아티팩트로 남깁니다. terraform-plan-checks: name: 체크 - ${{ matrix.environment }} - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 needs: detect-changes if: (needs.detect-changes.outputs.environments || '[]') != '[]' # 변경된 환경이 있을 때만 실행합니다. strategy: fail-fast: false # 한 환경 실패가 다른 환경 확인을 막지 않도록 유지합니다. matrix: - environment: ${{ fromJson(needs.detect-changes.outputs.environments || '[]') }} # 감지된 환경별로 병렬 실행합니다. + environment: ${{ fromJson(needs.detect-changes.outputs.environments || '[]') }} steps: - name: 코드 체크아웃 @@ -117,16 +120,8 @@ jobs: if: steps.init.outcome == 'success' working-directory: terraform/environments/${{ matrix.environment }} run: | - case "${{ matrix.environment }}" in - prod) - TFVARS_CONTENT="${TERRAFORM_TFVARS_PROD}" - SECRET_NAME="TERRAFORM_TFVARS_PROD" - ;; - *) - echo "오류: 지원하지 않는 환경입니다: ${{ matrix.environment }}" - exit 1 - ;; - esac + TFVARS_CONTENT="${TERRAFORM_TFVARS_PROD}" + SECRET_NAME="TERRAFORM_TFVARS_PROD" if [ -z "${TFVARS_CONTENT}" ]; then echo "오류: GitHub Secret ${SECRET_NAME}를 설정해야 합니다." @@ -191,16 +186,13 @@ jobs: # 업로드된 결과 파일을 읽어 PR 댓글을 환경별로 갱신 comment-plan-results: name: PR 댓글 갱신 - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 needs: - detect-changes - terraform-plan-checks if: always() && (needs.detect-changes.outputs.environments || '[]') != '[]' && github.event_name == 'pull_request' - - # 특정 환경 댓글 실패가 다른 환경 댓글을 막지 않도록 유지 strategy: fail-fast: false - # 감지된 환경별로 댓글을 분리 matrix: environment: ${{ fromJson(needs.detect-changes.outputs.environments || '[]') }} From 2d03cdc9a042c118745a62c3e5ae1abaa746020f Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 18:42:33 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20PR=20=ED=8C=8C=EC=9D=B4=ED=94=84?= =?UTF-8?q?=EB=9D=BC=EC=9D=B8=20=EC=8A=A4=ED=82=B5=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EB=94=94?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=9E=A1=20=EC=B6=94=EA=B0=80=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/terraform-plan.yml | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index 5dc6561..fb061b6 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -65,6 +65,31 @@ jobs: echo "감지된 환경: $ENVIRONMENTS_JSON" echo "environments=$ENVIRONMENTS_JSON" >> "$GITHUB_OUTPUT" + # detect-changes 출력값을 바로 확인하기 위한 디버그 잡 + debug-detect-changes: + name: 디버그 - 감지 결과 + runs-on: ubuntu-22.04 + needs: detect-changes + if: always() + + steps: + - name: detect-changes 출력 확인 + env: + ENVIRONMENTS: ${{ needs.detect-changes.outputs.environments }} + run: | + echo "detect-changes environments 원본: $ENVIRONMENTS" + printf 'detect-changes environments quoted: <%s>\n' "$ENVIRONMENTS" + echo "detect-changes environments 길이: ${#ENVIRONMENTS}" + echo "detect-changes environments 바이트:" + printf '%s' "$ENVIRONMENTS" | od -An -tx1 + + echo "detect-changes environments JSON 파싱 시도:" + if [ -n "$ENVIRONMENTS" ]; then + printf '%s\n' "$ENVIRONMENTS" | jq -c . + else + echo "값이 비어 있습니다." + fi + # 환경별 Terraform init/fmt/validate/plan을 수행하고 결과 파일을 아티팩트로 남깁니다. terraform-plan-checks: name: 체크 - ${{ matrix.environment }} @@ -80,6 +105,11 @@ jobs: - name: 코드 체크아웃 uses: actions/checkout@v4 + - name: Matrix 디버그 + run: | + echo "matrix.environment=${{ matrix.environment }}" + echo "needs.detect-changes.outputs.environments=${{ needs.detect-changes.outputs.environments }}" + # 출력 파일 기반으로 결과를 다루기 위해 wrapper를 비활성화 - name: Terraform 설치 uses: hashicorp/setup-terraform@v3 From 90c428ff8576b27eaa44798c52c09ac9b00c44ae Mon Sep 17 00:00:00 2001 From: eedo_y Date: Sat, 4 Apr 2026 18:46:43 +0900 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20PR=20=ED=8C=8C=EC=9D=B4=ED=94=84?= =?UTF-8?q?=EB=9D=BC=EC=9D=B8=20=EC=8A=A4=ED=82=B5=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/terraform-plan.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/terraform-plan.yml b/.github/workflows/terraform-plan.yml index fb061b6..9114cf6 100644 --- a/.github/workflows/terraform-plan.yml +++ b/.github/workflows/terraform-plan.yml @@ -15,18 +15,16 @@ permissions: pull-requests: write id-token: write -# 환경변수 설정 -env: - GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} - GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }} - TERRAFORM_STATE_BUCKET: ${{ secrets.TERRAFORM_STATE_BUCKET }} - TERRAFORM_TFVARS_PROD: ${{ secrets.TERRAFORM_TFVARS_PROD }} - jobs: # 변경된 Terraform 파일을 기준으로 영향받는 환경을 계산 detect-changes: name: 변경 환경 감지 runs-on: ubuntu-22.04 + env: + GCP_WORKLOAD_IDENTITY_PROVIDER: "" + GCP_SERVICE_ACCOUNT: "" + TERRAFORM_STATE_BUCKET: "" + TERRAFORM_TFVARS_PROD: "" outputs: environments: ${{ steps.detect.outputs.environments || '[]' }} steps: @@ -71,6 +69,11 @@ jobs: runs-on: ubuntu-22.04 needs: detect-changes if: always() + env: + GCP_WORKLOAD_IDENTITY_PROVIDER: "" + GCP_SERVICE_ACCOUNT: "" + TERRAFORM_STATE_BUCKET: "" + TERRAFORM_TFVARS_PROD: "" steps: - name: detect-changes 출력 확인 @@ -96,6 +99,11 @@ jobs: runs-on: ubuntu-22.04 needs: detect-changes if: (needs.detect-changes.outputs.environments || '[]') != '[]' # 변경된 환경이 있을 때만 실행합니다. + env: + GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + GCP_SERVICE_ACCOUNT: ${{ secrets.GCP_SERVICE_ACCOUNT }} + TERRAFORM_STATE_BUCKET: ${{ secrets.TERRAFORM_STATE_BUCKET }} + TERRAFORM_TFVARS_PROD: ${{ secrets.TERRAFORM_TFVARS_PROD }} strategy: fail-fast: false # 한 환경 실패가 다른 환경 확인을 막지 않도록 유지합니다. matrix: