چرا این موضوع مهم است؟
Terraform برای نگاشت resourceهای تعریفشده به objectهای واقعی به state نیاز دارد. State فقط cache نیست؛ شناسهها، dependencyها و بخشی از attributeهای resource را نگه میدارد و به همین دلیل باید backend، access control و locking آن بخشی از معماری باشد.
در یک سیستم واقعی، قبل از انتخاب ابزار باید مدل ذهنی درستی از لایهها داشته باشید. هر بار که یک مشکل را فقط با یک command یا تنظیم حفظی حل میکنیم، دانش به نسخه و محیط خاص گره میخورد. روش بهتر این است که ورودی، state، policy، مسیر داده و خروجی را مشخص کنیم. بعد ابزار را برای مشاهدهٔ یکی از این لایهها انتخاب کنیم. این رویکرد باعث میشود وقتی نسخه یا توزیع عوض شد، هنوز بدانیم دنبال چه evidenceای هستیم.
مدل معماری
در موضوع مدیریت امن Terraform state و کنترل drift در زیرساخت بهعنوان کد، componentها را روی یک مسیر ساده بکشید و مرز مسئولیت هرکدام را مشخص کنید. state پایدار، state runtime، dependency بیرونی و نقطهٔ اعمال policy را جدا کنید. وقتی diagram ساده دارید، خطا از یک «سیستم بزرگ و مبهم» به چند مرحلهٔ قابل آزمون تبدیل میشود.
روش عملی کار
State محلی را برای تیم production کنار بگذارید و backend اشتراکی با encryption، versioning و locking انتخاب کنید. دسترسی read و write را جدا کنید، workspace/state boundary را آگاهانه طراحی کنید و plan را در CI ثبت کنید.
برای Production، تغییر باید قابل اندازهگیری و قابل برگشت باشد. baseline قبل از تغییر شامل نسخه، config مؤثر، log سالم، metric اصلی و یک تست end-to-end است. rollout را با canary شروع کنید؛ بعد از هر مرحله هم تست مثبت و هم تست منفی داشته باشید. اگر success criterion از قبل نوشته نشده باشد، بعد از اجرا بهسادگی هر نتیجهای را میتوان «موفق» تفسیر کرد. rollback هم باید تمرین شود، نه اینکه فقط یک دستور روی کاغذ باشد.
از دید امنیت
State میتواند دادهٔ حساس داشته باشد. Encrypt بودن disk کافی نیست اگر هر کاربر CI بتواند فایل را بخواند. concurrent apply بدون locking، import دستی و تغییر خارج از Terraform نیز drift و conflict میسازند.
از دید امنیت، کمکردن سطح دسترسی مهم است اما availability و قابلیت عیبیابی هم جزو امنیت عملیاتیاند. secretها، tokenها، capabilityها، network path و logهای حساس را جدا بررسی کنید. هر exception باید owner، دلیل و تاریخ بازبینی داشته باشد. کنترلهایی که هیچکس نمیتواند اثرشان را مشاهده یا علتشان را توضیح دهد، در زمان incident به مانع تبدیل میشوند.
آزمایشگاه پیشنهادی
یک resource آزمایشی بسازید، state remote را فعال کنید، همزمان دو apply اجرا کنید و locking را ببینید. سپس resource را خارج از Terraform تغییر دهید و با plan اختلاف را پیدا کنید.
برای هر مرحله timestamp و خروجی را ذخیره کنید. یک failure کنترلشده ایجاد کنید تا مطمئن شوید monitoring واقعاً failure را میبیند. سپس سیستم را به baseline برگردانید و زمان recovery را ثبت کنید.
عیبیابی بر پایهٔ Evidence
Troubleshooting را با تغییر config شروع نکنید. اول محل دقیق failure را پیدا کنید: آیا ورودی وارد سیستم میشود؟ آیا state مورد انتظار ساخته شده؟ آیا policy اجازه میدهد؟ آیا خروجی از component خارج میشود؟ log، packet capture، metric و state API باید به یک timeline مشترک وصل شوند. نبودن event نیز evidence است؛ اگر request قبل از یک component دیده میشود و بعد از آن نه، دامنهٔ مسئله کوچک شده است.
Performance و ظرفیت
عملکرد را فقط با average نسنجید. p95/p99 latency، saturation، queue depth، retry و resource pressure تصویر بهتری میدهند. تغییری که در lab کوچک سریع است ممکن است زیر concurrency یا dataset واقعی bottleneck متفاوتی نشان دهد. capacity limitها را قبل از rollout بزرگ شناسایی کنید و alert را به thresholdهای قابل اقدام وصل کنید.
Production readiness
قبل از rollout نهایی، owner، change window، blast radius، success metric و rollback trigger باید مشخص باشند. اگر dependency خارجی دارید، رفتار هنگام timeout یا unavailable شدن آن را تست کنید. اگر config به چند host میرود، rollout مرحلهای و inventory دقیق لازم است. یک تغییر خوب باید observable، explainable و reversible باشد.
Runbook و انتقال دانش
در مستندسازی، فقط «چه دستورهایی اجرا شد» را ننویسید. سؤال، فرضیه، evidence مورد انتظار، نتیجه و دلیل تصمیم را ثبت کنید. اگر همکار دیگری بتواند با همان ورودی آزمایش را تکرار کند و به نتیجهٔ مشابه برسد، runbook ارزش عملیاتی دارد. اگر فقط نویسنده میداند چرا مرحلهای لازم است، دانش هنوز منتقل نشده است.
قبل از Production چه چیزی را اعتبارسنجی کنیم؟
نتیجهٔ Lab را مستقیم به Production تعمیم ندهید. یک change plan کوتاه بسازید که در آن دامنهٔ تغییر، owner، زمان اجرا، dependencyها، success metric و rollback trigger مشخص باشد. ابتدا روی canary یا درصد کوچکی از workload اجرا کنید و حداقل یک چرخهٔ واقعی restart، credential rotation یا deploy دوم را ببینید؛ بسیاری از خطاها در اولین اجرای سالم ظاهر نمیشوند. رفتار هنگام unavailable شدن dependency خارجی، پر شدن disk، timeout شبکه و ورودی نامعتبر را نیز بررسی کنید. اگر feature امنیتی است، test منفی باید نشان دهد مسیر غیرمجاز واقعاً بسته است؛ اگر feature performance است، benchmark باید با load و dataset نزدیک به واقعیت اجرا شود. در پایان، تصمیم rollout را با evidence ثبت کنید، نه با جملهٔ مبهم «بهنظر خوب است».
نگهداری بلندمدت و بازبینی دورهای
معماری بعد از deploy ثابت نمیماند. نسخهٔ سیستمعامل، dependency، policy سازمان، certificate، endpoint و حجم workload تغییر میکنند. برای همین باید بازبینی دورهای تعریف شود: نسخههای پشتیبانینشده را پیدا کنید، exceptionهای قدیمی را ببندید، alertهای بیارزش را حذف کنید و recovery را دوباره تمرین کنید. اگر configuration در Git نگهداری میشود، drift میان state واقعی و repository را اندازه بگیرید. اگر ابزار SaaS یا سرویس خارجی است، تغییر API، pricing، limit و مدل permission را دنبال کنید. مستندات باید تاریخ review داشته باشند تا تیم بداند کدام فرضها هنوز معتبرند. نگهداری خوب یعنی سیستم بعد از شش ماه هم قابل توضیح و قابل بازیابی باشد، نه اینکه فقط روز اول deploy موفق بوده باشد.
جمعبندی
هدف این مقاله دربارهٔ مدیریت امن Terraform state و کنترل drift در زیرساخت بهعنوان کد ارائهٔ یک دستور جادویی نیست؛ هدف ساختن مدل ذهنی است. وقتی معماری را بفهمید، baseline داشته باشید و تغییر را با evidence کوچک کنید، ابزارها قابل تعویض میشوند اما روش حل مسئله باقی میماند. منبع اصلی این مقاله از HashiCorp Terraform انتخاب شده تا جزئیات فنی قابل پیگیری باشند.
چکلیست سریع
- مسئله را در یک جمله تعریف کن.
- component و مرز اعتماد را مشخص کن.
- baseline را قبل از تغییر ذخیره کن.
- یک test مثبت و یک test منفی بساز.
- تغییر را با canary شروع کن.
- evidence را timestampدار نگه دار.
- rollback را واقعاً تمرین کن.
- نتیجه و exceptionها را در runbook ثبت کن.
یک مثال از رابطه پیکربندی، واقعیت و state
فرض کنید در پیکربندی یک ماشین با نام منطقی web تعریف شده و provider پس از ساخت، شناسه واقعی آن را دریافت کرده است. state رابطه این آدرس منطقی با شیء بیرونی را نگه میدارد. اگر فایل state گم شود، وجود کد به تنهایی به Terraform نمیگوید هر نام متعلق به کدام شیء موجود است. اجرای شتابزده ممکن است برنامه ساخت منابع تازه یا تعارض با منابع قبلی ایجاد کند. در این وضعیت ابتدا نسخه سالم state و موجودی واقعی را پیدا کنید؛ ساخت مجدد را جایگزین بررسی نکنید.
تغییر نام منطقی یک resource نیز الزاماً به معنی تغییر نام همان شیء بیرونی نیست. اگر رابطه قبلی به شکل درست منتقل نشود، برنامه ممکن است حذف آدرس قدیمی و ساخت آدرس جدید را پیشنهاد دهد. برای جابهجایی ساختار کد، ابزارهای انتقال آدرس و قابلیت moved را متناسب با نسخه بررسی کنید. plan باید نشان دهد آیا فقط نگاشت تغییر میکند یا عملیات مخرب هم وجود دارد. این بررسی پیش از تغییر ماژولهای مشترک اهمیت زیادی دارد، زیرا یک تغییر ظاهراً کوچک در نام میتواند به تعداد زیادی جایگزینی منجر شود.
قفل مانع همه نوع تعارض نیست
قفل state از اجرای همزمان عملیات ناسازگار روی همان state در backend پشتیبان جلوگیری میکند، اما جلوی تغییر دستی منابع از کنسول سرویسدهنده را نمیگیرد. دو state جدا نیز ممکن است اشتباهاً یک شیء واحد را مدیریت کنند؛ قفل هر کدام از دیگری خبر ندارد. برای هر منبع یک مالک روشن تعیین کنید. مرز state را بر اساس چرخه تغییر، دسترسی و وابستگی طراحی کنید، نه فقط تعداد خطوط فایل. تقسیم بیش از حد نیز هماهنگی خروجیها و ترتیب استقرار را دشوار میکند.
اگر اجرای CI قطع شد و قفل باقی ماند، ابتدا معلوم کنید فرایند اصلی هنوز فعال است یا خیر. زمان شروع، شناسه اجرا و وضعیت backend را بررسی کنید. باز کردن اجباری قفل بدون اطمینان از توقف نویسنده قبلی میتواند دو نویسنده همزمان بسازد. راهنمای رخداد باید تفاوت «اجرای کند»، «اجرای قطعشده» و «قفل رهاشده» را توضیح دهد. قطع نمایش لاگ در رابط CI الزاماً به معنی توقف عملیات سمت provider نیست.
رازهای داخل خروجیها و فایل برنامه
علامت حساس بودن یک مقدار بیشتر به نحوه نمایش کمک میکند؛ نباید فرض کرد با این علامت داده از state حذف شده است. بسته به resource و provider، ویژگیهای محرمانه میتوانند در state یا فایل plan ذخیره شوند. بنابراین دسترسی به artifact برنامه نیز باید محدود باشد. انتشار plan خام در گزارش عمومی، پیوست تیکت یا لاگ بلندمدت ممکن است اطلاعاتی بیش از انتظار آشکار کند. برای مرور تیمی، حداقل داده لازم را ارائه کنید و اصل فایل را در محل کنترلشده نگه دارید.
بازیابی را با یک کپی آزمایش کنید
نسخهبندی backend به پیدا کردن نسخه قبلی کمک میکند، ولی بازگرداندن آن بدون تطبیق با واقعیت خطرناک است. ممکن است پس از آن نسخه، منابعی ساخته یا حذف شده باشند. ابتدا یک کپی محافظتشده تهیه کنید، تغییرات شناسهها و نسخه state را بررسی و با موجودی provider تطبیق دهید. سپس برنامه تازه را بدون اعمال ببینید. اگر پیشنهاد حذف غیرمنتظره است، عملیات را متوقف کنید و علت نگاشت را بیابید. بازیابی state با بازگرداندن خود زیرساخت یکسان نیست.
برای کنترل drift، یک اجرای زمانبندیشده plan با دسترسی مناسب میتواند اختلاف را آشکار کند؛ اما گزارش اختلاف نباید خودکار به اجرای هر تغییر تبدیل شود. گاهی تغییر اضطراری معتبر باید وارد کد شود و گاهی باید از روی کد اصلاح گردد. تصمیم به مالک منبع، علت تغییر و اثر روی داده وابسته است. ثبت این تصمیم، مهمتر از صرفاً صفر کردن خروجی اختلاف است.