एक संसाधन को एक लिस्ट/मैप द्वारा संचालित समान नेस्टेड ब्लॉकों (जैसे इनग्रेस नियम) की परिवर्तनीय संख्या की आवश्यकता होती है।
→`dynamic` ब्लॉक का उपयोग करें जिसका `for_each` कलेक्शन को दोहराता है; `content {}` के अंदर ब्लॉक इटरेटर (डिफ़ॉल्ट नाम = ब्लॉक लेबल) के माध्यम से प्रत्येक तत्व को संदर्भित करें।
क्यों: डायनामिक ब्लॉक कॉपी-पेस्ट के बिना दोहराए गए नेस्टेड ब्लॉक उत्पन्न करते हैं; इटरेटर प्रत्येक जनरेट किए गए ब्लॉक को उसके स्रोत तत्व से बांधे रखता है।
संदर्भ↗
ऑब्जेक्ट के मैप में प्रत्येक प्रविष्टि के लिए एक संसाधन बनाएं, जिसे स्थिर रूप से कुंजीबद्ध किया गया हो ताकि पुनर्व्यवस्था कभी भी प्रतिस्थापन के लिए मजबूर न करे।
→`for_each = var.objects` (एक मैप) सेट करें। स्थिर कुंजी के लिए `each.key` और फ़ील्ड के लिए `each.value.<attr>` का उपयोग करें। यहाँ `count` से बचें — इंडेक्स शिफ्ट से हलचल होती है।
क्यों: मैप कुंजियाँ स्टेट में स्थिर पहचान हैं; लिस्ट इंडेक्स स्थितिजन्य होते हैं और तत्वों को जोड़ने/हटाने पर शिफ्ट हो जाते हैं।
कई इंस्टेंस के लिए `count` और `for_each` के बीच निर्णय लें।
→जब इंस्टेंस की अलग-अलग पहचान (एक सेट/मैप) हो तो `for_each` का उपयोग करें; `count` का उपयोग केवल N समान, क्रम-असंवेदनशील प्रतियों के लिए करें। किसी भी चीज़ के लिए `for_each` को प्राथमिकता दें जो बढ़ या घट सकती है।
क्यों: for_each कुंजी द्वारा पता करता है (resource["key"]); count इंडेक्स द्वारा पता करता है (resource[0]) जो इंसर्शन/डिलीशन पर पुनर्व्यवस्थित होता है।
एक इनपुट वेरिएबल एक ऑब्जेक्ट है जहाँ कुछ विशेषताएँ वैकल्पिक हैं और उन्हें डिफ़ॉल्ट की आवश्यकता है।
→इसे `object({ name = string, size = optional(number, 10) })` के रूप में टाइप करें। जब कॉलर एट्रिब्यूट को छोड़ देता है तो `optional(type, default)` डिफ़ॉल्ट प्रदान करता है।
क्यों: एक डिफ़ॉल्ट के साथ `optional()` कॉलर्स को संक्षिप्त रखता है, जबकि डाउनस्ट्रीम में एक ठोस मान की गारंटी देता है - हर जगह नल-हैंडलिंग की आवश्यकता नहीं होती है।
संदर्भ↗
लागू करने से पहले एक संसाधन के बारे में एक धारणा को मान्य करें, या बाद में परिणाम की गारंटी दें।
→बनाने/अपडेट करने से पहले इनपुट को सत्यापित करने के लिए `lifecycle { precondition { ... } }` का उपयोग करें, और आउटपुट को सत्यापित करने के लिए `postcondition` का उपयोग करें। दोनों `condition` + `error_message` लेते हैं।
क्यों: कस्टम शर्तें एक स्पष्ट संदेश के साथ तेज़ी से विफल हो जाती हैं, बजाय इसके कि एक टूटा हुआ अप्लाई या एक भ्रमित करने वाली डाउनस्ट्रीम त्रुटि उत्पन्न हो।
संदर्भ↗
एक संसाधन को तब फिर से बनाना होगा जब कोई अन्य संसाधन या विशेषता बदल जाए।
→`lifecycle { replace_triggered_by = [aws_x.y.id] }` जोड़ें। जब संदर्भित मान बदलता है, तो Terraform इस संसाधन के प्रतिस्थापन को मजबूर करता है।
क्यों: एक प्रतिस्थापन निर्भरता को घोषणात्मक रूप से व्यक्त करता है, हर संबंधित परिवर्तन पर मैनुअल `-replace` से बचाता है।
एक संसाधन को बदलने से डाउनटाइम होता है क्योंकि नया बनने से पहले पुराना नष्ट हो जाता है।
→`lifecycle { create_before_destroy = true }` सेट करें ताकि Terraform पहले प्रतिस्थापन को प्रोविजन करे, फिर पुराने को नष्ट करे। अद्वितीय नाम/कोई कठिन संघर्ष सुनिश्चित करें।
क्यों: ज़ीरो-डाउनटाइम प्रतिस्थापन; लेकिन नाम के टकराव और कोटा सीमाओं के लिए देखें जब दोनों संक्षेप में मौजूद हों।
अमान्य इनपुट मानों को जल्दी अस्वीकार करें (उदाहरण के लिए, एक वातावरण जो dev/stage/prod नहीं है)।
→वेरिएबल में एक `validation { condition = contains(["dev","stage","prod"], var.env), error_message = "..." }` ब्लॉक जोड़ें।
क्यों: एक प्रदाता कॉल में गहराई से विफल होने के बजाय एक पठनीय संदेश के साथ प्लान समय पर खराब इनपुट को पकड़ता है।
एक ऐसे मान को संदर्भित करें जो प्लान को क्रैश किए बिना मौजूद न हो।
→त्रुटियों पर वापस लौटने के लिए `try(local.maybe.value, "default")` का उपयोग करें, या यह जानने के लिए कि क्या कोई एक्सप्रेशन सफल होता है, एक बूलियन प्राप्त करने के लिए `can(expr)` का उपयोग करें।
क्यों: वैकल्पिक/परिवर्तनीय-आकार के डेटा का शालीनता से प्रबंधन; अनुपस्थित कुंजियों पर "Error: Unsupported attribute" से बचाता है।
एक लिस्ट को एक मैप में बदलें, या एक संसाधन तर्क के लिए एक कलेक्शन को फ़िल्टर/आकार दें।
→एक `for` एक्सप्रेशन का उपयोग करें: `{ for u in var.users : u.name => u.role if u.active }` (मैप) या `[for x in list : upper(x)]` (लिस्ट)।
क्यों: for एक्सप्रेशन डेटा को नया आकार देने का मुहावरेदार तरीका है; `if` क्लॉज़ फ़िल्टर करता है, `k => v` फॉर्म मैप बनाता है।
एक वेरिएबल या आउटपुट में एक रहस्य होता है जिसे प्लान/अप्लाई आउटपुट में प्रिंट नहीं होना चाहिए।
→वेरिएबल को `sensitive = true` के रूप में चिह्नित करें (और आउटपुट को भी)। Terraform इसे CLI आउटपुट में संशोधित करता है, हालांकि यह अभी भी स्टेट में संग्रहीत होता है।
क्यों: लॉग/CI आउटपुट में आकस्मिक प्रकटीकरण से बचाता है; स्टेट को अभी भी संरक्षित किया जाना चाहिए (एन्क्रिप्टेड बैकएंड, एक्सेस कंट्रोल)।
एक ही कॉन्फ़िगरेशन के भीतर दो क्षेत्रों/खातों में संसाधनों का प्रबंधन करें।
→एलियास प्रदाताओं (`provider "aws" { alias = "west" region = "us-west-2" }`) को घोषित करें और संसाधनों पर `provider = aws.west` सेट करें या मॉड्यूल में पास करें।
क्यों: एलियास एक कॉन्फ़िग को कई प्रदाता इंस्टेंस को लक्षित करने देते हैं; मॉड्यूल उन्हें `providers` तर्क के माध्यम से स्पष्ट रूप से प्राप्त करते हैं।
एक छिपी हुई निर्भरता (संदर्भों के माध्यम से व्यक्त नहीं की गई) क्रम संबंधी समस्याएं पैदा करती है।
→क्रम को लागू करने के लिए `depends_on = [aws_iam_role_policy.x]` जोड़ें। इसका उपयोग कम करें — विशेषता संदर्भों के माध्यम से निहित निर्भरताओं को प्राथमिकता दें।
क्यों: स्पष्ट `depends_on` उन निर्भरताओं को संभालता है जिनका ग्राफ़ अनुमान नहीं लगा सकता, लेकिन अत्यधिक उपयोग से रूढ़िवादी, धीमे प्लान बनते हैं।
संरचित वेरिएबल्स के साथ एक टेम्पलेट से एक कॉन्फ़िग फ़ाइल/यूज़र-डेटा प्रस्तुत करें।
→`templatefile("${path.module}/tpl.tftpl", { items = local.items })` का उपयोग करें; टेम्पलेट `%{ for }` / `${}` इंटरपोलेशन का उपयोग करता है।
क्यों: templatefile रेंडरिंग को शुद्ध/प्लान समय पर रखता है (अप्रचलित टेम्पलेट प्रदाता के विपरीत) और लूप/कंडीशनल्स का समर्थन करता है।
एक `for_each` को फीड करने के लिए हर (सबनेट, नियम) संयोजन की एक फ्लैट लिस्ट बनाएं।
→क्रॉस-प्रोडक्ट के लिए `setproduct(var.subnets, var.rules)` का उपयोग करें, या नेस्टेड लिस्ट को एक में संपीड़ित करने के लिए `flatten([for ...])` का उपयोग करें।
क्यों: ये फ़ंक्शन नेस्टेड डेटा को फ्लैट, अद्वितीय-कुंजीय संग्रह में बदल देते हैं जिनकी `for_each` को आवश्यकता होती है।