DevOps and Infrastructure

بلوک‌های دینامیک و for_each در ترافورم: الگوهای پیشرفته برای مدیریت مجموعه‌های با طول متغیر

زیرساخت به عنوان کد (IaC) اغلب شامل مدیریت منابعی است که پیکربندی آن‌ها در زمان کامپایل ثابت نیست. چه در حال تأمین گروه‌های امنیتی AWS باشید، چه پیکربندی استقرار Kubernetes یا تنظیم رابط‌های شبکه Azure، تعداد بلوک‌های تو در تو یا آیتم‌های لیست اغلب متفاوت است. کدنویسی سخت‌افزاری (Hardcoding) این پیکربندی‌ها منجر به کدهای تکراری و کابوس‌های نگهداری می‌شود. اینجاست که بلوک‌های دینامیک ترافورم و متا-آرگومان for_each درخشش خود را نشان می‌دهند.

برای توسعه‌دهندگان متوسط تا پیشرفته، تسلط بر این دو ویژگی برای نوشتن کد HCL (زبان پیکربندی HashiCorp) تمیز، مقیاس‌پذیر و قابل نگهداری ضروری است. این پست به بررسی الگوهای پیشرفته برای ترکیب این ابزارها جهت مدیریت مجموعه‌های پیچیده با طول متغیر می‌پردازد.

درک بلوک‌های سازنده

قبل از غوطه‌ور شدن در الگوهای پیشرفته، بیایید تمایز آن‌ها را به طور خلاصه روشن کنیم. for_each یک متا-آرگومان است که می‌تواند روی منابع یا ماژول‌ها استفاده شود تا چندین نمونه از یک منبع را بر اساس یک نقشه یا مجموعه‌ای از رشته‌ها ایجاد کند. این روش برای ایجاد منابع در سطح بالا ایده‌آل است.

از طرف دیگر، بلوک‌های دینامیک به شما امکان می‌دهند بلوک‌های تو در تو (مانند ingress در یک گروه امنیتی) را به صورت پویا در داخل یک منبع تولید کنید. آن‌ها روی یک لیست یا نقشه تکرار شده و پیکربندی بلوک متناظر را برای هر عنصر تزریق می‌کنند.

الگوی ۱: بلوک دینامیک تو در تو

رایج‌ترین مورد استفاده برای بلوک‌های دینامیک، تولید پیکربندی‌های تو در تو است. یک aws_security_group AWS را در نظر بگیرید. می‌خواهید قوانین ingress را بر اساس یک متغیر تعریف کنید، اما تعداد قوانین نامشخص است. با استفاده از یک بلوک دینامیک، می‌توانید روی یک لیست از نقشه‌ها تکرار کنید.

variable "ingress_rules" {
  type = list(object({
    from_port   = number
    to_port     = number
    protocol    = string
    cidr_blocks = list(string)
  }))
  default = []
}

resource "aws_security_group" "example" {
  name = "example-sg"

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }
}

# Usage in main.tf
resource "aws_security_group" "web_sg" {
  ingress_rules = [
    {
      from_port   = 443
      to_port     = 443
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    },
    {
      from_port   = 22
      to_port     = 22
      protocol    = "tcp"
      cidr_blocks = ["10.0.0.0/8"]
    }
  ]
}

این الگو تعاریف متغیر شما را تمیز نگه می‌دارد و به زیرساخت شما اجازه می‌دهد تا به محض اضافه شدن قوانین جدید به لیست ورودی، به سرعت سازگار شود.

الگوی ۲: ترکیب for_each و بلوک‌های دینامیک

سناریوهای پیشرفته اغلب نیاز به ایجاد چندین منبع دارند که هر کدام مجموعه خاص خود را از بلوک‌های دینامیک تو در تو دارند. برای مثال، ممکن است چندین سرویس برنامه را مستقر کنید که هر کدام متغیرهای محیطی یا پورت‌های کانتینر خاصی دارند.

با ترکیب for_each روی منبع و بلوک‌های dynamic در داخل منبع، به انعطاف‌پذیری بالایی دست می‌یابید.

variable "services" {
  type = map(object({
    name = string
    ports = list(object({
      containerPort = number
      protocol      = string
    }))
  }))
}

resource "aws_lb_target_group" "this" {
  for_each = var.services

  name     = each.key
  port     = 80
  protocol = "HTTP"

  # Note: Dynamic blocks inside target groups are limited, 
  # but this pattern applies to resources like aws_instance or aws_lb_listener
  
  tags = {
    Name = each.key
  }
}

در حالی که مثال بالا ساده‌سازی شده است، یک پیاده‌سازی پیچیده‌تر شامل استفاده از for_each برای راه‌اندازی ماژول‌ها یا منابع متمایز است، جایی که هر نمونه یک نقشه پیکربندی خاص را دریافت می‌کند که بلوک‌های دینامیک داخلی آن را هدایت می‌کند.

بهترین شیوه‌ها و ملاحظات عملکرد

هنگام مدیریت مجموعه‌های با طول متغیر، نکات زیر را در نظر داشته باشید:

  • ثبات کلیدها: هنگام استفاده از for_each، مطمئن شوید که کلیدهای شما پایدار هستند. تغییر یک کلید در یک نقشه باعث می‌شود ترافورم به جای به‌روزرسانی، منبع را از بین ببرد و دوباره ایجاد کند.
  • ساده‌سازی متغیرها: از انواع متغیر ساختاریافته (نقشه‌هایی از اشیاء یا لیست‌هایی از اشیاء) استفاده کنید تا ورودی‌ها را در مراحل اولیه اعتبارسنجی کنید. این کار از خطاهای زمان اجرا جلوگیری می‌کند زمانی که بلوک‌های دینامیک سعی می‌کنند به ویژگی‌های تعریف نشده دسترسی پیدا کنند.
  • خوانایی: اگرچه قدرتمند هستند، اما تو در تو شدن بیش از حد بلوک‌های دینامیک می‌تواند کد را به سختی خواند. اگر منطق بسیار پیچیده شد، پیکربندی‌های پیچیده را به مقادیر محلی یا ماژول‌های جداگانه استخراج کنید.

نتیجه‌گیری

بلوک‌های دینامیک و for_each فقط ویژگی‌های راحتی نیستند؛ آن‌ها ابزارهای اساسی برای ساخت زیرساخت‌های قوی و بومی ابری با ترافورم هستند. با بهره‌گیری از این الگوهای پیشرفته، می‌توانید از تکرار کد جلوگیری کنید، خطر انحراف پیکربندی را کاهش دهید و زیرساختی ایجاد کنید که به همان اندازه که برنامه‌های شما مقیاس‌پذیر هستند، به زیبایی مقیاس می‌پذیرد. از امروز شروع به بازنگری بلوک‌های کدنویسی شده سخت کنید تا پتانسیل کامل استراتژی زیرساخت به عنوان کد خود را آزاد کنید.

Share: