Skip to content

فصل ۷ — پیکربندی نمونه‌های پشته

استفاده از یک پروژهٔ کد پشتهٔ واحد، نگهداری چند نمونهٔ سازگار از زیرساخت را آسان‌تر می‌کند، همان‌طور که در «الگو: پشتهٔ قابل‌استفادهٔ مجدد» در صفحه ۷۲ توضیح داده شد. با این حال، اغلب باید نمونه‌های مختلف یک پشته را سفارشی کنید. مثلاً ممکن است در محیط توسعه، خوشه‌ای با تعداد سرور کمتر از محیط تولید اندازه‌دهی کنید.

اینجا نمونه‌ای از کد پشته است که خوشهٔ میزبانی کانتینر را با حداقل و حداکثر تعداد سرور قابل‌پیکربندی تعریف می‌کند:

container_cluster: web_cluster-${environment}
  min_size: ${cluster_minimum}
  max_size: ${cluster_maximum}

برای هر محیط، مقادیر پارامتر متفاوتی به این کد می‌دهید، همان‌طور که در شکل ۷-۱ نشان داده شده است.

ابزارهای پشته مانند Terraform و CloudFormation چندین روش برای تنظیم مقادیر پارامترهای پیکربندی پشتیبانی می‌کنند. این‌ها معمولاً شامل دادن مقادیر در خط فرمان، خواندن از فایل، و بازیابی آن‌ها توسط کد زیرساخت از یک مخزن کلید-مقدار است.

تیم‌هایی که زیرساخت را مدیریت می‌کنند باید تصمیم بگیرند چگونه از این قابلیت‌ها برای مدیریت و انتقال مقادیر پیکربندی به ابزار پشتهٔ خود استفاده کنند. ضروری است مطمئن شوید مقادیر به‌طور سازگار برای هر محیط تعریف و اعمال می‌شوند.

شکل ۷-۱. استفاده از همان کد با مقادیر پارامتر متفاوت برای هر محیط

اصل طراحی: نگه داشتن پارامترها ساده

یکی از دلایل اصلی تعریف زیرساخت به‌عنوان کد، اطمینان از پیکربندی سازگار سیستم‌هاست، همان‌طور که در «اصل: به حداقل رساندن تنوع» در صفحه ۱۷ توضیح داده شد.

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

بنابراین بهتر است پارامترهای پشته را ساده نگه دارید و به روش‌های ساده از آن‌ها استفاده کنید:

  • انواع پارامتر ساده را ترجیح دهید، مانند رشته، عدد، و شاید فهرست‌ها و نگاشت‌های کلید-مقدار. از انتقال ساختارهای دادهٔ پیچیده‌تر خودداری کنید.
  • تعداد پارامترهایی که می‌توان برای یک پشته تنظیم کرد را به حداقل برسانید. از تعریف پارامترهایی که «شاید» به آن‌ها نیاز داشته باشید خودداری کنید. فقط وقتی نیاز فوری دارید پارامتر اضافه کنید. همیشه می‌توانید بعداً در صورت نیاز پارامتر اضافه کنید.
  • از استفاده از پارامترها به‌عنوان شرط‌هایی که تفاوت‌های قابل‌توجهی در زیرساخت حاصل ایجاد می‌کنند خودداری کنید. مثلاً یک پارامتر بولی (بله/خیر) برای نشان دادن اینکه آیا سرویسی درون پشته تأمین شود، پیچیدگی اضافه می‌کند.

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

استفاده از پارامترهای پشته برای ایجاد شناسه‌های یکتا

اگر چند نمونهٔ پشته از یک پروژه ایجاد کنید (طبق الگوی پشتهٔ قابل‌استفادهٔ مجدد که در «الگو: پشتهٔ قابل‌استفادهٔ مجدد» در صفحه ۷۲ بحث شد)، ممکن است با شکست منابع زیرساختی که شناسهٔ یکتا می‌خواهند مواجه شوید. برای درک منظورم، به شبه‌کد زیر که یک سرور برنامه تعریف می‌کند نگاه کنید:

server:
  id: appserver
  subnet_id: appserver-subnet

پلتفرم ابری فرضی به مقدار id برای یکتا بودن نیاز دارد، بنابراین وقتی دستور پشته را برای ایجاد پشتهٔ دوم اجرا می‌کنم، شکست می‌خورد:

> stack up environment=test --source mystack/src
SUCCESS: stack 'test' created
> stack up environment=staging --source mystack/src
FAILURE: server 'appserver' already exists in another stack

می‌توانم از پارامترها در کد پشته برای جلوگیری از این برخوردها استفاده کنم. کد را تغییر می‌دهم تا پارامتری به نام environment بگیرد و از آن برای اختصاص شناسهٔ یکتای سرور استفاده کنم. همچنین سرور را در هر محیط به زیرشبکهٔ متفاوتی اضافه می‌کنم:

server:
  id: appserver-${environment}
  subnet_id: appserver-subnet-${environment}"

حالا می‌توانم دستور پشتهٔ فرضی را برای ایجاد چند نمونهٔ پشته بدون خطا اجرا کنم.

پارامترهای نمونهٔ پشته

در این فصل از یک پشتهٔ نمونه برای مقایسه و تضاد الگوهای مختلف پیکربندی پشته استفاده می‌کنم. نمونه، یک پروژهٔ پشتهٔ الگو است که خوشهٔ کانتینر را تعریف می‌کند؛ شامل مجموعه‌ای پویا از گره‌های میزبان و برخی ساختارهای شبکه. مثال ۷-۱ ساختار پروژه را نشان می‌دهد.

مثال ۷-۱. ساختار نمونهٔ پروژه برای پشتهٔ الگو که خوشهٔ کانتینر را تعریف می‌کند

├── src/
│   ├── cluster.infra
│   └── networking.infra
└── test/

پشتهٔ خوشه از پارامترهای فهرست‌شده در مثال ۷-۲ برای سه نمونهٔ پشتهٔ مختلف استفاده می‌کند. environment شناسهٔ یکتای هر محیط است که می‌تواند برای نام‌گذاری و ایجاد شناسه‌های یکتا به کار رود. cluster_minimum و cluster_maximum محدودهٔ اندازهٔ خوشهٔ میزبان کانتینر را تعریف می‌کنند. کد زیرساخت در فایل cluster.infra خوشه را روی پلتفرم ابری تعریف می‌کند و بسته به بار، تعداد گره‌های میزبان را مقیاس می‌دهد. هر یک از سه محیط test، staging و production مجموعهٔ متفاوتی از مقادیر را استفاده می‌کند.

مثال ۷-۲. مقادیر پارامتر نمونه برای توصیف الگوها

نمونهٔ پشتهenvironmentcluster_minimumcluster_maximum
cluster_testtest11
cluster_stagingstaging23
cluster_productionproduction26

الگوها برای پیکربندی پشته‌ها

دیدیم چرا باید پشته‌ها را پارامتریزه کرد و کمی دربارهٔ نحوهٔ پیاده‌سازی پارامترها توسط ابزارها. حالا الگوها و ضدالگوهایی برای مدیریت پارامترها و انتقال آن‌ها به ابزار توصیف می‌کنم:

  • پارامترهای دستی پشته — اجرای ابزار پشته و تایپ مقادیر پارامتر در خط فرمان.
  • پارامترهای اسکریپتی — سخت‌کد کردن مقادیر پارامتر برای هر نمونه در اسکریپتی که ابزار پشته را اجرا می‌کند.
  • فایل‌های پیکربندی پشته — اعلام مقادیر پارامتر برای هر نمونه در فایل‌های پیکربندی که در پروژهٔ کد پشته نگه‌داری می‌شوند.
  • پشتهٔ پوششی (wrapper stack) — ایجاد پروژهٔ پشتهٔ زیرساخت جداگانه برای هر نمونه و وارد کردن ماژول مشترک با کد پشته.
  • پارامترهای پشته در خط لوله — تعریف مقادیر پارامتر در پیکربندی مرحلهٔ خط لوله برای هر نمونه.
  • الگوی ثبت پارامتر پشته — ذخیرهٔ مقادیر پارامتر در مکان مرکزی.

ضدالگو: پارامترهای دستی پشته

طبیعی‌ترین رویکرد برای دادن مقادیر به یک نمونهٔ پشته، تایپ دستی مقادیر در خط فرمان است، همان‌طور که در مثال ۷-۳ نشان داده شده.

مثال ۷-۳. نمونهٔ تایپ دستی پارامترهای خط فرمان

> stack up environment=production --source mystck/src
FAILURE: No such directory 'mystck/src'
> stack up environment=production --source mystack/src
SUCCESS: new stack 'production' created
> stack destroy environment=production --source mystack/src
SUCCESS: stack 'production' destroyed
> stack up environment=production --source mystack/src
SUCCESS: existing stack 'production' modified

انگیزه

تایپ مقادیر در خط فرمان بسیار ساده است و هنگام یادگیری استفاده از ابزار مفید است. همچنین برای آزمایش، تایپ پارامترها در خط فرمان مفید است.

تبعات

تایپ مقدار در خط فرمان مستعد خطاست. به‌خاطر آوردن اینکه چه مقادیری باید تایپ شوند هم دشوار است. برای زیرساختی که اهمیت دارد، احتمالاً نمی‌خواهید ریسک خراب کردن چیزی مهم با اشتباه تایپ کردن دستور هنگام بهبود یا رفع اشکال را بپذیرید. وقتی چند نفر روی یک پشتهٔ زیرساخت کار می‌کنند، مثل یک تیم، نمی‌توانید انتظار داشته باشید همه مقادیر صحیح را برای هر نمونه به‌خاطر بسپارند.

پارامترهای دستی پشته برای اعمال خودکار کد زیرساخت به محیط‌ها، مثل CI یا CD، مناسب نیستند.

پیاده‌سازی

برای پارامترهای نمونه (مثال ۷-۲)، مقادیر را طبق نحو مورد انتظار ابزار خاص در خط فرمان بدهید. با ابزار پشتهٔ فرضی من، دستور به این شکل است:

stack up \
    environment=test \
    cluster_minimum=1 \
    cluster_maximum=1 \
    ssl_cert_passphrase="correct horse battery staple"

هر کسی که دستور را اجرا می‌کند باید رازها — مانند گذرواژه‌ها و کلیدها — را برای محیط مربوط بداند و در خط فرمان بدهد. تیم شما باید از ابزار مدیریت گذرواژهٔ تیمی برای ذخیره و اشتراک امن آن‌ها بین اعضای تیم استفاده کند و هنگام خروج افراد از تیم، رازها را بچرخاند.¹

الگوهای مرتبط

الگوی پارامترهای اسکریپتی (به «الگو: پارامترهای اسکریپتی» در صفحه ۸۴ مراجعه کنید) دستوری که تایپ می‌کردید را می‌گیرد و در اسکریپت می‌گذارد. الگوی پارامترهای پشته در خط لوله (به «الگو: پارامترهای پشته در خط لوله» در صفحه ۹۳ مراجعه کنید) همین کار را می‌کند اما آن‌ها را در پیکربندی خط لوله به‌جای اسکریپت می‌گذارد.

الگو: متغیرهای محیطی پشته

الگوی متغیرهای محیطی پشته شامل تنظیم مقادیر پارامتر به‌عنوان متغیرهای محیطی برای استفادهٔ ابزار پشته است. این الگو اغلب با الگوی دیگری ترکیب می‌شود تا متغیرهای محیطی تنظیم شوند.

متغیرهای محیطی از قبل تنظیم می‌شوند، همان‌طور که در مثال ۷-۴ نشان داده شده (برای جزئیات بیشتر به «پیاده‌سازی» در صفحه ۸۳ مراجعه کنید).

مثال ۷-۴. تنظیم متغیرهای محیطی

export STACK_ENVIRONMENT=test
export STACK_CLUSTER_MINIMUM=1
export STACK_CLUSTER_MAXIMUM=1
export STACK_SSL_CERT_PASSPHRASE="correct horse battery staple"

گزینه‌های پیاده‌سازی متفاوت است، اما ساده‌ترین این است که کد پشته مستقیماً به آن‌ها ارجاع دهد، همان‌طور که در مثال ۷-۵ نشان داده شده.

مثال ۷-۵. کد پشته با استفاده از متغیرهای محیطی

container_cluster: web_cluster-${ENV("STACK_ENVIRONMENT")}
  min_size: ${ENV("STACK_CLUSTER_MINIMUM")}
  max_size: ${ENV("STACK_CLUSTER_MAXIMUM")}

انگیزه

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

کاربرد

اگر از قبل از متغیرهای محیطی در سیستم خود استفاده می‌کنید و مکانیزم‌های مناسبی برای مدیریت آن‌ها دارید، ممکن است استفاده از آن‌ها برای پارامترهای پشته راحت باشد.

تبعات

برای گرفتن مقادیر برای تنظیم، باید از الگوی دیگری در این فصل استفاده کنید. این بخش‌های اضافی اضافه می‌کند و ردیابی مقادیر پیکربندی برای هر نمونهٔ پشته و تغییر مقادیر را دشوارتر می‌کند.

استفادهٔ مستقیم از متغیرهای محیطی در کد پشته، همان‌طور که در مثال ۷-۵ است، به‌نظر می‌رسد کد پشته را بیش از حد به محیط اجرا گره می‌زند.

تنظیم رازها در متغیرهای محیطی ممکن است آن‌ها را در معرض فرآیندهای دیگری که روی همان سیستم اجرا می‌شوند قرار دهد.

پیاده‌سازی

باز هم باید متغیرهای محیطی را برای استفاده تنظیم کنید، یعنی الگوی دیگری از این فصل را انتخاب کنید. مثلاً اگر انتظار دارید افراد متغیرهای محیطی را در محیط محلی خود تنظیم کنند تا کد پشته را اعمال کنند، از ضدالگوی پارامترهای دستی پشته استفاده می‌کنید (به «ضدالگو: پارامترهای دستی پشته» در صفحه ۸۱ مراجعه کنید). می‌توانید آن‌ها را در اسکریپتی که ابزار پشته را اجرا می‌کند تنظیم کنید (الگوی پارامترهای اسکریپتی، همان‌طور که در «الگو: پارامترهای اسکریپتی» در صفحه ۸۴ بحث شد)، یا ابزار خط لوله آن‌ها را تنظیم کند (به «الگو: پارامترهای پشته در خط لوله» در صفحه ۹۳ مراجعه کنید).

رویکرد دیگر قرار دادن مقادیر در اسکریپتی است که افراد یا نمونه‌ها در محیط محلی خود وارد می‌کنند. این تغییری از الگوی فایل‌های پیکربندی پشته است (به «الگو: فایل‌های پیکربندی پشته» در صفحه ۸۷ مراجعه کنید). اسکریپت تنظیم متغیرها دقیقاً مانند مثال ۷-۴ خواهد بود و هر دستوری که ابزار پشته را اجرا می‌کند آن را در محیط وارد می‌کند:

source ./environments/staging.env
stack up --source ./src

به‌طور جایگزین، می‌توانید مقادیر محیطی را در نمونهٔ محاسباتی که ابزار پشته را اجرا می‌کند بسازید. مثلاً اگر گرهٔ عامل CD جداگانه‌ای برای اجرای ابزار پشته و ساخت و به‌روزرسانی پشته‌ها در هر محیط تأمین کنید، کد ساخت گره می‌تواند مقادیر مناسب را به‌عنوان متغیرهای محیطی تنظیم کند. آن متغیرهای محیطی برای هر دستوری که روی گره اجرا می‌شود، از جمله ابزار پشته، در دسترس خواهند بود.

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

طرف دیگر پیاده‌سازی این الگو، نحوهٔ گرفتن مقادیر محیطی توسط ابزار پشته است. مثال ۷-۵ نشان داد که کد پشته چگونه می‌تواند مستقیماً متغیرهای محیطی را بخواند.

اما می‌توانید به‌جای آن از اسکریپت ارکستراسیون پشته استفاده کنید (به «استفاده از اسکریپت‌ها برای پوشش ابزارهای زیرساخت» در صفحه ۳۳۵ مراجعه کنید) تا متغیرهای محیطی را بخواند و به ابزار پشته در خط فرمان بدهد. کد در اسکریپت ارکستراسیون به این شکل خواهد بود:

stack up \
  environment=${STACK_ENVIRONMENT} \
  cluster_minimum=${STACK_CLUSTER_MINIMUM} \
  cluster_maximum=${STACK_CLUSTER_MAXIMUM} \
  ssl_cert_passphrase="${STACK_SSL_CERT_PASSPHRASE}"

این رویکرد کد پشته شما را از محیطی که در آن اجرا می‌شود جدا می‌کند.

الگوهای مرتبط

هر یک از الگوهای دیگر این فصل را می‌توان با این الگو برای تنظیم مقادیر محیطی ترکیب کرد.


¹ نمونه‌هایی از ابزارهایی که تیم‌ها می‌توانند برای اشتراک امن گذرواژه استفاده کنند شامل GPG، KeePass، 1Password، Keeper و LastPass است.

الگو: پارامترهای اسکریپتی

پارامترهای اسکریپتی شامل سخت‌کد کردن مقادیر پارامتر در اسکریپتی است که ابزار پشته را اجرا می‌کند. می‌توانید اسکریپت جداگانه برای هر محیط بنویسید یا یک اسکریپت واحد که مقادیر همهٔ محیط‌های شما را شامل شود:

if ${ENV} == "test"
  stack up cluster_maximum=1 env="test"
elsif ${ENV} == "staging"
  stack up cluster_maximum=3 env="staging"
elsif ${ENV} == "production"
  stack up cluster_maximum=5 env="production"
end

انگیزه

اسکریپت‌ها راه ساده‌ای برای ثبت مقادیر هر نمونه هستند و مشکلات ضدالگوی پارامترهای دستی پشته را برطرف می‌کنند (به «ضدالگو: پارامترهای دستی پشته» در صفحه ۸۱ مراجعه کنید). می‌توانید مطمئن باشید مقادیر برای هر محیط به‌طور سازگار استفاده می‌شوند. با commit کردن اسکریپت در کنترل نسخه، مطمئن می‌شوید تغییرات مقادیر پیکربندی را ردیابی می‌کنید.

کاربرد

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

چون سخت‌کد کردن رازها در اسکریپت‌ها اشتباه است، این الگو برای رازها مناسب نیست. این به معنای آن نیست که نباید از این الگو استفاده کنید، فقط باید الگوی جداگانه‌ای برای رازها پیاده کنید (به «مدیریت رازها به‌عنوان پارامتر» در صفحه ۱۰۲ برای پیشنهادها مراجعه کنید).

تبعات

رایج است که دستورات اجرای ابزار پشته با گذشت زمان پیچیده شوند. اسکریپت‌های تأمین می‌توانند به موجودات آشفته تبدیل شوند. «استفاده از اسکریپت‌ها برای پوشش ابزارهای زیرساخت» در صفحه ۳۳۵ نحوهٔ استفاده از این اسکریپت‌ها و دام‌ها و توصیه‌ها برای نگه‌داشتن آن‌ها قابل‌نگهداری را شرح می‌دهد. باید اسکریپت‌های تأمین را تست کنید چون می‌توانند منبع مشکلات سیستم‌هایی باشند که تأمین می‌کنند.

پیاده‌سازی

دو پیاده‌سازی رایج برای این الگو وجود دارد. یکی اسکریپت واحدی است که محیط را به‌عنوان آرگومان خط فرمان می‌گیرد و مقادیر پارامتر سخت‌کدشده برای هر محیط دارد. مثال ۷-۶ نمونهٔ ساده‌ای از این است.

مثال ۷-۶. نمونهٔ اسکریپتی که پارامترهای چند محیط را شامل می‌شود

#!/bin/sh

case $1 in
test)
   CLUSTER_MINIMUM=1
   CLUSTER_MAXIMUM=1
   ;;
staging)
   CLUSTER_MINIMUM=2
   CLUSTER_MAXIMUM=3
   ;;
production)
   CLUSTER_MINIMUM=2
   CLUSTER_MAXIMUM=6
   ;;
*)
   echo "Unknown environment $1"
   exit 1
   ;;
esac

stack up \
    environment=$1 \
    cluster_minimum=${CLUSTER_MINIMUM} \
    cluster_maximum=${CLUSTER_MAXIMUM}

پیاده‌سازی دیگر اسکریپت جداگانه برای هر نمونهٔ پشته است، همان‌طور که در مثال ۷-۷ نشان داده شده.

مثال ۷-۷. ساختار نمونهٔ پروژه با اسکریپت برای هر محیط

our-infra-stack/
  ├── bin/
  │   ├── test.sh
  │   ├── staging.sh
  │   └── production.sh
  ├── src/
  └── test/

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

اسکریپت یا اسکریپت‌های تأمین را در کنترل منبع commit کنید. قرار دادن آن در همان پروژه‌ای که پشته را تأمین می‌کند تضمین می‌کند با کد پشته همگام بماند. مثلاً اگر پارامتر جدید اضافه کنید، آن را به کد منبع زیرساخت و همچنین به اسکریپت تأمین اضافه می‌کنید. همیشه می‌دانید کدام نسخه از اسکریپت را برای نسخهٔ مشخصی از کد پشته اجرا کنید.

«استفاده از اسکریپت‌ها برای پوشش ابزارهای زیرساخت» در صفحه ۳۳۵ استفاده از اسکریپت‌ها برای اجرای ابزارهای پشته را با جزئیات بیشتر بحث می‌کند.

همان‌طور که گفته شد، نباید رازها را در اسکریپت‌ها سخت‌کد کنید، پس برای آن‌ها باید الگوی متفاوتی استفاده کنید. می‌توانید از اسکریپت برای پشتیبانی از آن الگو استفاده کنید. در مثال ۷-۸، ابزار خط فرمان راز را از مدیر رازها می‌گیرد، طبق الگوی ثبت پارامتر (به «الگو: ثبت پارامتر پشته» در صفحه ۹۶ مراجعه کنید).

مثال ۷-۸. گرفتن کلید از مدیر رازها در اسکریپت

...
# (Set environment specific values as in other examples)
...

SSL_CERT_PASSPHRASE=$(some-tool get-secret id="/ssl_cert_passphrase/${ENV}")

stack up \
    environment=${ENV} \
    cluster_minimum=${CLUSTER_MINIMUM} \
    cluster_maximum=${CLUSTER_MAXIMUM} \
    ssl_cert_passphrase="${SSL_CERT_PASSPHRASE}"

دستور some-tool به مدیر رازها متصل می‌شود و راز مربوط به محیط را با شناسهٔ /ssl_cert_passphrase/${ENV} بازیابی می‌کند. این مثال فرض می‌کند نشست مجاز استفاده از مدیر رازها را دارد. توسعه‌دهندهٔ زیرساخت ممکن است قبل از اجرای این اسکریپت با ابزار نشست را شروع کند. یا نمونهٔ محاسباتی که اسکریپت را اجرا می‌کند ممکن است مجاز بازیابی رازها با مجوزدهی بدون راز (secretless authorization) باشد (همان‌طور که در «مجوزدهی بدون راز» در صفحه ۱۰۳ توضیح می‌دهم).

الگوهای مرتبط

اسکریپت‌های تأمین ابزار خط فرمان را برای شما اجرا می‌کنند، پس راهی برای فراتر رفتن از ضدالگوی پارامترهای دستی پشته هستند (به «ضدالگو: پارامترهای دستی پشته» در صفحه ۸۱ مراجعه کنید). الگوی فایل‌های پیکربندی پشته مقادیر پارامتر را از اسکریپت به فایل‌های جداگانه منتقل می‌کند.

الگو: فایل‌های پیکربندی پشته

فایل‌های پیکربندی پشته مقادیر پارامتر هر نمونه را در فایل جداگانه‌ای مدیریت می‌کنند که با کد پشته در کنترل نسخه نگه‌داری می‌شود، مانند مثال ۷-۹.

مثال ۷-۹. پروژهٔ نمونه با فایل پارامتر برای هر محیط

├── src/
│   ├── cluster.infra
│   ├── host_servers.infra
│   └── networking.infra
├── environments/
│   ├── test.properties
│   ├── staging.properties
│   └── production.properties
└── test/

انگیزه

ایجاد فایل‌های پیکربندی برای نمونه‌های یک پشته ساده و قابل‌فهم است. چون فایل در مخزن کد منبع commit می‌شود، آسان است:

  • ببینید چه مقادیری برای هر محیط استفاده می‌شود («حداکثر اندازهٔ خوشه برای تولید چقدر است؟»)
  • تاریخچه را برای اشکال‌زدایی ردیابی کنید («حداکثر اندازهٔ خوشه کی تغییر کرد؟»)
  • تغییرات را ممیزی کنید («چه کسی حداکثر اندازهٔ خوشه را تغییر داد؟»)

فایل‌های پیکربندی پشته جداسازی پیکربندی از کد پشته را اعمال می‌کنند.

کاربرد

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

تبعات

وقتی می‌خواهید نمونهٔ پشتهٔ جدید ایجاد کنید، باید فایل پیکربندی جدید به پروژهٔ پشته اضافه کنید. این مانع ایجاد خودکار محیط‌های جدید در لحظه می‌شود. در «الگو: پشتهٔ تست زودگذر» در صفحه ۱۴۳، رویکردی برای مدیریت محیط‌های تست توصیف می‌کنم که به ایجاد خودکار محیط‌ها متکی است. می‌توانید با ایجاد فایل پیکربندی برای محیط زودگذر در صورت نیاز این را دور بزنید.

فایل‌های پارامتر می‌توانند برای تغییر پیکربندی محیط‌های پایین‌دست در خط لولهٔ تحویل تغییر از نوعی که در «خط‌ لوله‌های تحویل زیرساخت» در صفحه ۱۱۹ توصیف شد، اصطکاک اضافه کنند. هر تغییر در کد پروژهٔ پشته باید از هر مرحلهٔ خط لوله عبور کند قبل از اعمال به تولید. تکمیل این فرآیند ممکن است زمان ببرد و وقتی تغییر پیکربندی فقط به تولید اعمال می‌شود، ارزشی اضافه نمی‌کند.

تعریف مقادیر پارامتر می‌تواند منبع پیچیدگی قابل‌توجهی در اسکریپت‌های تأمین باشد. بیشتر در «استفاده از اسکریپت‌ها برای پوشش ابزارهای زیرساخت» در صفحه ۳۳۵ دربارهٔ این صحبت می‌کنم، اما به‌عنوان اشاره، در نظر بگیرید تیم‌ها اغلب می‌خواهند مقادیر پیش‌فرض برای پروژه‌های پشته و برای محیط‌ها تعریف کنند و سپس به منطقی برای ترکیب آن‌ها به مقادیر نمونهٔ مشخصی از پشتهٔ مشخص در محیط متفاوت نیاز دارند. مدل‌های ارث‌بری برای مقادیر پارامتر می‌توانند آشفته و گیج‌کننده شوند.

فایل‌های پیکربندی در کنترل منبع نباید رازها را شامل شوند. پس برای رازها یا باید الگوی اضافی از این فصل انتخاب کنید یا فایل پیکربندی راز جداگانه‌ای خارج از کنترل منبع پیاده کنید.

پیاده‌سازی

مقادیر پارامتر پشته را در فایل جداگانه برای هر محیط تعریف می‌کنید، همان‌طور که قبلاً در مثال ۷-۹ نشان داده شد.

محتوای فایل پارامتر می‌تواند به این شکل باشد:

env = staging
cluster_minimum = 2
cluster_maximum = 3

مسیر فایل پارامتر مربوطه را هنگام اجرای دستور پشته بدهید:

stack up --source ./src --config ./environments/staging.properties

اگر سیستم از چند پشته تشکیل شده، مدیریت پیکربندی در همهٔ محیط‌ها می‌تواند آشفته شود. دو روش رایج برای چیدمان فایل‌های پارامتر در این موارد وجود دارد. یکی قرار دادن فایل‌های پیکربندی همهٔ محیط‌ها با کد هر پشته:

├── cluster_stack/
│   ├── src/
│   │   ├── cluster.infra
│   │   ├── host_servers.infra
│   │   └── networking.infra
│   └── environments/
│       ├── test.properties
│       ├── staging.properties
│       └── production.properties

└── appserver_stack/
    ├── src/
    │   ├── server.infra
    │   └── networking.infra
    └── environments/
        ├── test.properties
        ├── staging.properties
        └── production.properties

دیگری متمرکز کردن پیکربندی همهٔ پشته‌ها در یک مکان:

├── cluster_stack/
│   ├── cluster.infra
│   ├── host_servers.infra
│   └── networking.infra

├── appserver_stack/
│   ├── server.infra
│   └── networking.infra

└── environments/
    ├── test/
    │ ├── cluster.properties
    │ └── appserver.properties
    ├── staging/
    │ ├── cluster.properties
    │ └── appserver.properties
    └── production/
        ├── cluster.properties
        └── appserver.properties

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

اگر می‌خواهید از فایل‌های پیکربندی برای دادن رازها استفاده کنید، به‌جای الگوی جداگانه برای رازها، باید آن فایل‌ها را خارج از کد پروژهٔ commit‌شده در کنترل منبع مدیریت کنید.

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

stack up --source ./src \
  --config ./environments/staging.properties \
  --config ../.secrets/staging.properties

در این مثال، دو آرگومان --config به ابزار پشته می‌دهید و از هر دو مقادیر پارامتر را می‌خواند. پوشه‌ای به نام .secrets خارج از پوشهٔ پروژه دارید، پس در کنترل منبع نیست.

وقتی ابزار پشته به‌طور خودکار از نمونهٔ محاسباتی مثل عامل خط لولهٔ CD اجرا می‌شود، انجام این کار دشوارتر است. می‌توانید فایل‌های property راز مشابهی روی این نمونه‌های محاسباتی تأمین کنید، اما این می‌تواند رازها را در معرض فرآیندهای دیگری که روی همان عامل اجرا می‌شوند قرار دهد. همچنین باید رازها را به فرآیندی که نمونهٔ محاسباتی عامل را می‌سازد بدهید، پس هنوز مشکل بوت‌استرپ دارید.

الگوهای مرتبط

قرار دادن مقادیر پیکربندی در فایل‌ها اسکریپت‌های تأمین توصیف‌شده در «الگو: پارامترهای اسکریپتی» در صفحه ۸۴ را ساده می‌کند. می‌توانید برخی محدودیت‌های فایل‌های پیکربندی محیط را با استفاده از الگوی ثبت پارامتر پشته دور بزنید (به «الگو: ثبت پارامتر پشته» در صفحه ۹۶ مراجعه کنید). این کار مقادیر پارامتر را از کد پروژهٔ پشته به مکان مرکزی منتقل می‌کند و امکان گردش‌کارهای متفاوت برای کد و پیکربندی را می‌دهد.

الگو: پشتهٔ پوششی (Wrapper Stack)

پشتهٔ پوششی از پروژهٔ پشتهٔ زیرساخت برای هر نمونه به‌عنوان پوششی برای وارد کردن مؤلفهٔ کد پشته استفاده می‌کند (به فصل ۱۶ مراجعه کنید). هر پروژهٔ پوششی مقادیر پارامتر یک نمونه از پشته را تعریف می‌کند. سپس مؤلفه‌ای مشترک بین همهٔ نمونه‌های پشته را وارد می‌کند (به شکل ۷-۲ مراجعه کنید).

شکل ۷-۲. پشتهٔ پوششی از پروژهٔ پشتهٔ زیرساخت برای هر نمونه به‌عنوان پوششی برای وارد کردن ماژول پشته استفاده می‌کند

انگیزه

پشتهٔ پوششی از قابلیت ماژول ابزار پشته یا پشتیبانی کتابخانه برای استفادهٔ مجدد از کد مشترک بین نمونه‌های پشته بهره می‌برد. می‌توانید از قابلیت نسخه‌بندی ماژول، مدیریت وابستگی و مخزن artifact ابزار برای پیاده‌سازی خط لولهٔ تحویل تغییر استفاده کنید (به «خط‌ لوله‌های تحویل زیرساخت» در صفحه ۱۱۹ مراجعه کنید). تا زمان نگارش این کتاب، اکثر ابزارهای پشتهٔ زیرساخت قالب بسته‌بندی پروژه‌ای ندارند که بتوانید برای خط لوله‌های کد پشته استفاده کنید. پس باید فرآیند بسته‌بندی پشتهٔ سفارشی خود را بسازید. می‌توانید با استفاده از پشتهٔ پوششی و نسخه‌بندی و ارتقای کد پشته به‌عنوان ماژول این را دور بزنید.

با پشته‌های پوششی می‌توانید منطق تأمین و پیکربندی پشته‌ها را به همان زبانی که زیرساخت را تعریف می‌کنید بنویسید، به‌جای زبان جداگانه‌ای که با اسکریپت تأمین استفاده می‌کردید (به «الگو: پارامترهای اسکریپتی» در صفحه ۸۴ مراجعه کنید).

تبعات

مؤلفه‌ها لایهٔ پیچیدگی اضافی بین پشته و کد موجود در مؤلفه ایجاد می‌کنند. حالا دو سطح دارید: پروژهٔ پشته که پروژه‌های پوششی را شامل می‌شود، و مؤلفه‌ای که کد پشته را دارد.

چون پروژهٔ کد جداگانه برای هر نمونهٔ پشته دارید، ممکن است افراد وسوسه شوند منطق سفارشی برای هر نمونه اضافه کنند. کد سفارشی نمونه پایگاه کد شما را ناسازگار و سخت‌نگهداری می‌کند.

چون مقادیر پارامتر در پروژه‌های پوششی مدیریت‌شده در کنترل منبع تعریف می‌شوند، نمی‌توانید از این الگو برای مدیریت رازها استفاده کنید. پس باید الگوی دیگری از این فصل برای دادن رازها به پشته‌ها اضافه کنید.

پیاده‌سازی

هر نمونهٔ پشته پروژهٔ پشتهٔ زیرساخت جداگانه‌ای دارد. مثلاً برای هر محیط پروژهٔ Terraform جداگانه‌ای دارید. می‌توانید این را مانند محیط کپی-پیست پیاده کنید (به «ضدالگو: محیط‌های کپی-پیست» در صفحه ۷۰ مراجعه کنید)، با هر محیط در مخزن جداگانه.

به‌طور جایگزین، هر پروژهٔ محیط می‌تواند پوشه‌ای در یک مخزن واحد باشد:

my_stack/
   ├── test/
   │   └── stack.infra
   ├── staging/
   │   └── stack.infra
   └── production/
       └── stack.infra

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

مثال زیر پشتهٔ پوششی است که ماژولی به نام container_cluster_module را وارد می‌کند، نسخهٔ ماژول و پارامترهای پیکربندی برای انتقال به آن را مشخص می‌کند:

module:
  name: container_cluster_module
  version: 1.23
  parameters:
    env: test
    cluster_minimum: 1
    cluster_maximum: 1

کد پشتهٔ پوششی برای محیط‌های staging و production مشابه است، به‌جز مقادیر پارامتر و شاید نسخهٔ ماژولی که استفاده می‌کنند.

ساختار پروژه برای ماژول می‌تواند به این شکل باشد:

├── container_cluster_module/
│   ├── cluster.infra
│   └── networking.infra
└── test/

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

Terragrunt ابزار ارکستراسیون پشته است که الگوی پشتهٔ پوششی را پیاده می‌کند.

الگوهای مرتبط

پشتهٔ پوششی شبیه الگوی پارامترهای اسکریپتی است. تفاوت‌های اصلی این است که از زبان ابزار پشته به‌جای زبان اسکریپت جداگانه استفاده می‌کند و کد زیرساخت در مؤلفهٔ جداگانه‌ای است.

الگو: پارامترهای پشته در خط لوله

با الگوی پارامترهای پشته در خط لوله، مقادیر هر نمونه را در پیکربندی خط لولهٔ تحویل تعریف می‌کنید (به شکل ۷-۳ مراجعه کنید).

شکل ۷-۳. هر مرحله‌ای که کد پشته را اعمال می‌کند، مقادیر پیکربندی مربوط به محیط را منتقل می‌کند

نحوهٔ استفاده از خط لولهٔ تحویل تغییر برای اعمال کد پشتهٔ زیرساخت به محیط‌ها را در «خط‌ لوله‌های تحویل زیرساخت» در صفحه ۱۱۹ توضیح می‌دهم. می‌توانید خط لوله را با ابزاری مثل Jenkins، GoCD یا ConcourseCI پیاده کنید (به «نرم‌افزار و سرویس‌های خط لولهٔ تحویل» در صفحه ۱۲۳ برای اطلاعات بیشتر دربارهٔ این ابزارها مراجعه کنید).

انگیزه

اگر از ابزار خط لوله برای اجرای ابزار پشتهٔ زیرساخت استفاده می‌کنید، مکانیزم ذخیره و انتقال مقادیر پارامتر به ابزار را از پیش دارد. با فرض اینکه ابزار خط لوله خود با کد پیکربندی شده، مقادیر به‌عنوان کد تعریف و در کنترل نسخه ذخیره می‌شوند.

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

کاربرد

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

تبعات

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

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

به‌طور کلی، بهتر است پیکربندی خط لوله برای اعمال پروژهٔ پشته تا حد امکان کوچک و ساده بماند. بیشتر منطق باید در اسکریپتی که خط لوله فراخوانی می‌کند باشد، نه در پیکربندی خط لوله.

سرورهای CI، خط لوله‌ها و رازها

اولین چیزی که بیشتر مهاجمان هنگام دسترسی به شبکهٔ سازمانی دنبال می‌کنند، سرورهای CI و CD است. این‌ها گنجینه‌های شناخته‌شدهٔ گذرواژه‌ها و کلیدهایی هستند که می‌توانند برای آسیب حداکثری به کاربران و مشتریان شما بهره برداری شوند.

بیشتر ابزارهای CI و CD که با آن‌ها کار کرده‌ام مدل امنیتی بسیار قوی ارائه نمی‌دهند. باید فرض کنید هر کسی که به ابزار خط لوله دسترسی دارد یا می‌تواند کدی که ابزار اجرا می‌کند (یعنی احتمالاً هر توسعه‌دهنده‌ای در سازمان شما) را تغییر دهد، به هر رازی که ابزار ذخیره می‌کند دسترسی دارد.

این حتی وقتی ابزار رازها را رمزنگاری می‌کند هم درست است، چون ابزار می‌تواند رازها را رمزگشایی کند. اگر بتوانید ابزار را وادار به اجرای دستوری کنید، معمولاً می‌توانید هر رازی که ذخیره می‌کند را رمزگشایی کنید. باید هر ابزار CI یا CD که استفاده می‌کنید را با دقت تحلیل کنید تا بسنجید چقدر نیازهای امنیتی سازمان شما را پشتیبانی می‌کند.

پیاده‌سازی

پارامترها باید با پیکربندی «به‌عنوان کد» ابزار خط لوله پیاده شوند. مثال ۷-۱۰ پیکربندی مرحلهٔ خط لولهٔ شبه‌کد را نشان می‌دهد.

مثال ۷-۱۰. پیکربندی نمونهٔ مرحلهٔ خط لوله

stage: apply-test-stack
  input_artifacts: container_cluster_stack
  commands:
    unpack ${input_artifacts}
    stack up --source ./src environment=test cluster_minimum=1 cluster_maximum=1
    stack test environment=test

این مثال مقادیر را در خط فرمان می‌دهد. همچنین می‌توانید آن‌ها را به‌عنوان متغیرهای محیطی که کد پشته استفاده می‌کند تنظیم کنید، همان‌طور که در مثال ۷-۱۱ نشان داده شده (همچنین به «الگو: متغیرهای محیطی پشته» در صفحه ۸۲ مراجعه کنید).

مثال ۷-۱۱. پیکربندی مرحلهٔ خط لوله با متغیرهای محیطی

stage: apply-test-stack
  input_artifacts: container_cluster_stack
  environment_vars:
    STACK_ENVIRONMENT=test
    STACK_CLUSTER_MINIMUM=1
    STACK_CLUSTER_MAXIMUM=1
  commands:
    unpack ${input_artifacts}
    stack up --source ./src
    stack test environment=test

در این مثال، ابزار خط لوله آن متغیرهای محیطی را قبل از اجرای دستورات تنظیم می‌کند.

بسیاری از ابزارهای خط لوله قابلیت‌های مدیریت راز دارند که می‌توانید برای انتقال رازها به دستور پشته استفاده کنید. مقادیر راز را به نحوی در ابزار خط لوله تنظیم می‌کنید و سپس می‌توانید در job خط لوله به آن‌ها ارجاع دهید، همان‌طور که در مثال ۷-۱۲ نشان داده شده.

مثال ۷-۱۲. مرحلهٔ خط لولهٔ نمونه با راز

stage: apply-test-stack
  input_artifacts: container_cluster_stack
  commands:
    unpack ${input_artifacts}
    stack up --source ./src environment=test \
        cluster_minimum=1 \
        cluster_maximum=1 \
        ssl_cert_passphrase=${STACK_SSL_CERT_PASSPHRASE}

الگوهای مرتبط

تعریف دستورات و پارامترها برای اعمال کد پشته به هر محیط در پیکربندی خط لوله شبیه الگوی پارامترهای اسکریپتی است. تفاوت در محل اسکریپت‌نویسی است — در پیکربندی خط لوله در مقابل فایل‌های اسکریپت.

الگو: ثبت پارامتر پشته

ثبت پارامتر پشته مقادیر پارامتر نمونه‌های پشته را در مکان مرکزی مدیریت می‌کند، نه با کد پشتهٔ شما. ابزار پشته هنگام اعمال کد پشته به نمونهٔ مشخص، مقادیر مربوطه را بازیابی می‌کند (به شکل ۷-۴ مراجعه کنید).

ثبت‌های پیکربندی و ثبت پارامتر پشته

از اصطلاح ثبت پیکربندی (configuration registry) برای توصیف سرویسی استفاده می‌کنم که مقادیر پیکربندی را ذخیره می‌کند و ممکن است برای اهداف زیادی — از جمله کشف سرویس، یکپارچه‌سازی پشته یا پیکربندی نظارت — به کار رود. بیشتر در «ثبت پیکربندی» در صفحه ۹۹ توضیح می‌دهم.

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

شکل ۷-۴. مقادیر پارامتر نمونهٔ پشته در ثبت مرکزی ذخیره می‌شوند

انگیزه

ذخیرهٔ مقادیر پارامتر در ثبت، پیکربندی را از پیاده‌سازی جدا می‌کند. پارامترهای ثبت می‌توانند توسط ابزارهای مختلف، با زبان‌ها و فناوری‌های مختلف تنظیم، استفاده و مشاهده شوند. این انعطاف‌پذیری گره‌خوردگی بین بخش‌های مختلف سیستم را کاهش می‌دهد. می‌توانید هر ابزاری که از ثبت استفاده می‌کند را بدون تأثیر بر ابزار دیگری که از آن استفاده می‌کند جایگزین کنید.

چون مستقل از ابزار هستند، ثبت‌های پارامتر پشته می‌توانند به‌عنوان منبع حقیقت برای پیکربندی زیرساخت و حتی سیستم عمل کنند و نقش پایگاه دادهٔ مدیریت پیکربندی (CMDB) را بازی کنند. این دادهٔ پیکربندی در زمینه‌های تنظیم‌شده مفید است و تولید گزارش برای ممیزی را آسان می‌کند.

کاربرد

اگر از ثبت پیکربندی برای اهداف دیگر استفاده می‌کنید، منطقی است آن را به‌عنوان ثبت پارامتر پشته هم به کار ببرید. مثلاً ثبت پیکربندی راه مفیدی برای یکپارچه‌سازی چند پشته است (به «کشف وابستگی‌ها بین پشته‌ها» در صفحه ۲۸۷ مراجعه کنید).

تبعات

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

مدیریت مقادیر پارامتر جدا از کد پشته‌ای که از آن استفاده می‌کند trade-off دارد. می‌توانید پیکربندی نمونهٔ پشته را بدون تغییر در پروژهٔ پشته تغییر دهید. اگر یک تیم پروژهٔ پشتهٔ قابل‌استفادهٔ مجدد را نگه‌داری کند، تیم‌های دیگر می‌توانند بدون افزودن یا تغییر فایل‌های پیکربندی در خود پروژهٔ پشته، نمونه‌های پشتهٔ خود را بسازند.

از سوی دیگر، تغییر در بیش از یک مکان — پروژهٔ پشته و ثبت پارامتر — پیچیدگی و فرصت اشتباه اضافه می‌کند.

پیاده‌سازی

راه‌های پیاده‌سازی ثبت پارامتر را در «ثبت پیکربندی» در صفحه ۹۹ بحث می‌کنم. به‌اختصار، ممکن است سرویسی باشد که جفت‌های کلید/مقدار ذخیره می‌کند، یا فایل یا ساختار پوشه‌ای از فایل‌هایی که جفت‌های کلید-مقدار دارند. در هر صورت، معمولاً مقادیر پارامتر را می‌توان در ساختار سلسله‌مراتبی ذخیره کرد تا بر اساس محیط و پشته، و شاید عوامل دیگری مثل برنامه، سرویس، تیم، جغرافیا یا مشتری ذخیره و پیدا کرد.

مقادیر خوشهٔ کانتینر نمونهٔ این فصل می‌تواند مانند مثال ۷-۱۳ باشد.

مثال ۷-۱۳. نمونهٔ ورودی‌های ثبت پیکربندی

└── env/
    ├── test/
    │    └── cluster/
    │         ├── min = 1
    │         └── max = 1
    ├── staging/
    │    └── cluster/
    │         ├── min = 2
    │         └── max = 3
    └── production/
         └── cluster/
              ├── min = 2
              └── max = 6

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

cluster:
  id: container_cluster-${environment}
  minimum: ${get_value("/env/${environment}/cluster/min")}
  maximum: ${get_value("/env/${environment}/cluster/max")}

تابع get_registry_item() در کد پشته مقدار را جستجو می‌کند.

این پیاده‌سازی کد پشته را به ثبت پیکربندی گره می‌زند. برای اجرا و تست کد به ثبت نیاز دارید که ممکن است سنگین باشد. می‌توانید با گرفتن مقادیر از ثبت در اسکریپت که سپس آن‌ها را به‌عنوان پارامترهای عادی به کد پشته می‌دهد این را دور بزنید. این انعطاف‌پذیری برای تنظیم مقادیر پارامتر به روش‌های دیگر را می‌دهد. برای کد پشتهٔ قابل‌استفادهٔ مجدد این به‌ویژه مفید است و به کاربران کد گزینه‌های بیشتری برای پیکربندی نمونه‌های پشته‌شان می‌دهد.

سرویس‌های مدیریت راز (به «منابع ذخیره‌سازی» در صفحه ۲۹ مراجعه کنید) نوع خاصی از ثبت پارامتر هستند. با استفادهٔ درست، تضمین می‌کنند رازها فقط برای افراد و سرویس‌هایی که به آن‌ها نیاز دارند در دسترس باشند، بدون افشای گسترده‌تر. برخی محصولات و سرویس‌های ثبت پیکربندی می‌توانند هم مقادیر راز و هم غیرراز را ذخیره کنند. اما مهم است از ذخیرهٔ رازها در ثبت‌هایی که آن‌ها را محافظت نمی‌کنند خودداری کنید. این کار ثبت را هدف آسان برای مهاجمان می‌کند.

الگوهای مرتبط

احتمالاً باید حداقل یک پارامتر به ابزار پشته بدهید تا نشان دهد از پارامترهای کدام نمونهٔ پشته استفاده کند. می‌توانید از الگوی اسکریپت تأمین پشته یا پارامترهای پشته در خط لوله برای این استفاده کنید.

زنجیره‌کردن الگوهای پیکربندی

بیشتر ابزارها زنجیره‌ای از گزینه‌های پیکربندی با سلسله‌مراتب قابل‌پیش‌بینی اولویت پشتیبانی می‌کنند — مقادیر فایل پیکربندی با متغیرهای محیطی و سپس پارامترهای خط فرمان بازنویسی می‌شوند. بیشتر رژیم‌های پیکربندی پشته سلسله‌مراتب مشابهی را پشتیبانی می‌کنند.

ثبت پیکربندی

سازمان‌های بزرگ‌تر با تیم‌های زیاد که روی سیستم‌های بزرگ‌تر با بخش‌های متحرک زیاد کار می‌کنند، اغلب ثبت پیکربندی را مفید می‌یابند. برای پیکربندی نمونه‌های پشته مفید است، همان‌طور که در «الگو: ثبت پارامتر پشته» در صفحه ۹۶ توصیف کردم. همچنین برای مدیریت وابستگی‌های یکپارچه‌سازی بین نمونه‌های پشته، برنامه‌ها و سرویس‌های دیگر مفید است، همان‌طور که در «کشف وابستگی‌ها بین پشته‌ها» در صفحه ۲۸۷ توضیح می‌دهم.

ثبت می‌تواند منبع مفیدی از اطلاعات دربارهٔ ترکیب و وضعیت زیرساخت شما باشد. می‌توانید از آن برای ساخت ابزار، داشبورد و گزارش، و همچنین نظارت و ممیزی سیستم‌هایتان استفاده کنید.

پس ارزش دارد در نحوهٔ پیاده‌سازی و استفاده از ثبت پیکربندی عمیق‌تر شویم.

پیاده‌سازی ثبت پیکربندی

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

ثبت‌های ابزار اتوماسیون زیرساخت

بسیاری از زنجیره‌های ابزار اتوماسیون زیرساخت سرویس ثبت پیکربندی دارند. این‌ها معمولاً بخشی از سرویس متمرکزی هستند که ممکن است قابلیت‌هایی مثل مدیریت کد منبع، نظارت، داشبورد و ارکستراسیون دستور هم داشته باشد. نمونه‌ها شامل:

  • Chef Infra Server
  • PuppetDB
  • Ansible Tower
  • Salt Mine

ممکن است بتوانید این سرویس‌ها را با ابزارهای خارج از زنجیره‌ای که آن‌ها را ارائه می‌دهد استفاده کنید. بیشتر آن‌ها می‌توانند مقادیر را در معرض قرار دهند، پس می‌توانید اسکریپتی بنویسید که اطلاعاتی دربارهٔ وضعیت فعلی زیرساخت مدیریت‌شده توسط ابزار پیکربندی کشف کند. برخی ثبت‌های ابزار زیرساخت قابل‌گسترش‌اند، پس می‌توانید از آن‌ها برای ذخیرهٔ داده از ابزارهای دیگر استفاده کنید.

با این حال، این وابستگی به هر زنجیره‌ای که سرویس ثبت را ارائه می‌دهد ایجاد می‌کند. سرویس ممکن است یکپارچه‌سازی با ابزارهای شخص ثالث را به‌طور کامل پشتیبانی نکند. ممکن است قرارداد یا APIای ارائه ندهد که سازگاری آینده را تضمین کند.

پس اگر در نظر دارید از مخزن دادهٔ ابزار زیرساخت به‌عنوان ثبت پیکربندی همه‌منظوره استفاده کنید، بسنجید چقدر این مورد استفاده را پشتیبانی می‌کند و چه نوع قفل‌شدنی ایجاد می‌کند.

محصولات ثبت پیکربندی همه‌منظوره

محصولات و پایگاه‌های دادهٔ ثبت پیکربندی و مخزن کلید-مقدار اختصاصی زیادی خارج از زنجیره‌های ابزار اتوماسیون خاص در دسترس است. برخی نمونه‌ها:

  • Zookeeper
  • etcd
  • Consul²
  • doozerd

این‌ها معمولاً با ابزارها، زبان‌ها و سیستم‌های مختلف سازگارند، پس شما را به زنجیرهٔ ابزار خاصی قفل نمی‌کنند.

با این حال، ممکن است کار قابل‌توجهی برای تعریف نحوهٔ ذخیرهٔ داده لازم باشد. کلیدها باید مانند environment/service/application، service/application/environment یا چیز دیگری ساختار یابند؟ ممکن است نیاز به نوشتن و نگه‌داری کد سفارشی برای یکپارچه‌سازی سیستم‌های مختلف با ثبت داشته باشید. و ثبت پیکربندی چیز دیگری برای استقرار و اجرا به تیم شما اضافه می‌کند.

سرویس‌های ثبت پلتفرم

بیشتر پلتفرم‌های ابری سرویس مخزن کلید-مقدار دارند، مانند AWS SSM Parameter Store. بیشتر مزایای محصول ثبت پیکربندی همه‌منظوره را بدون نیاز به نصب و پشتیبانی خودتان می‌دهند. با این حال، شما را به آن ارائه‌دهندهٔ ابری گره می‌زند. در برخی موارد ممکن است خود را در حال استفاده از سرویس ثبت روی یک ابر برای مدیریت زیرساختی که روی ابر دیگری اجرا می‌شود بیابید!

ثبت‌های پیکربندی DIY

به‌جای اجرای سرور ثبت پیکربندی، برخی تیم‌ها ثبت پیکربندی سبک‌وزن سفارشی می‌سازند با ذخیرهٔ فایل‌های پیکربندی در مکان مرکزی یا با استفاده از ذخیره‌سازی توزیع‌شده. معمولاً از سرویس ذخیره‌سازی فایل موجود مثل object store (مثلاً S3 bucket در AWS)، سیستم کنترل نسخه، filesystem شبکه‌ای یا حتی وب‌سرور استفاده می‌کنند.

تغییری از این، بسته‌بندی تنظیمات پیکربندی در بسته‌های سیستمی مانند فایل .deb یا .rpm (برای توزیع‌های لینوکس مبتنی بر Debian یا Red Hat) و push به مخزن داخلی APT یا YUM است. سپس می‌توانید فایل‌های پیکربندی را با ابزار مدیریت بستهٔ استاندارد به سرورهای محلی دانلود کنید.

تغییر دیگر استفاده از سرور پایگاه دادهٔ رابطه‌ای یا سند استاندارد است.

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

² Consul محصول HashiCorp است که Terraform را هم می‌سازد و البته این محصولات خوب با هم کار می‌کنند. اما Consul به‌عنوان ابزار مستقل ساخته و نگه‌داری می‌شود و برای عملکرد Terraform لازم نیست. به همین دلیل آن را محصول ثبت همه‌منظوره می‌شمارم.

ثبت واحد یا چندگانهٔ پیکربندی

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

بسیاری از ابزارها، مثل سرویس‌های نظارت و سیستم‌های پیکربندی سرور، ثبت خود را دارند. اغلب محصولات ثبت و دایرکتوری مختلفی می‌یابید که در وظایف خاص — مانند مدیریت مجوز، کشف سرویس و دایرکتوری کاربر — بسیار خوب‌اند. خم کردن همهٔ این ابزارها به استفاده از یک سیستم جریان مداوم کاری ایجاد می‌کند. هر به‌روزرسانی هر ابزار نیاز به ارزیابی، تست و احتمالاً کار بیشتر برای نگه‌داری یکپارچه‌سازی دارد.

ممکن است بهتر باشد دادهٔ مرتبط را از سرویس‌هایی که ذخیره شده‌اند بکشید. مطمئن شوید می‌دانید کدام سیستم منبع حقیقت برای هر داده یا مورد پیکربندی خاص است. سیستم‌ها و ابزارهایتان را با این درک طراحی کنید.

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

مدیریت رازها به‌عنوان پارامتر

سیستم‌ها به رازهای مختلف نیاز دارند. ابزار پشتهٔ شما ممکن است به گذرواژه یا کلیدی برای استفاده از API پلتفرم و ایجاد و تغییر زیرساخت نیاز داشته باشد. همچنین ممکن است نیاز باشد رازها را در محیط‌ها تأمین کنید، مثلاً اطمینان از اینکه برنامه گذرواژهٔ اتصال به پایگاه داده را دارد.

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

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

رمزنگاری رازها

استثنای قانون هرگز نگذاشتن راز در کد منبع، رمزنگاری آن در کد منبع است؛ git-crypt، blackbox، sops و transcrypt ابزارهایی هستند که رمزنگاری رازها در مخزن را کمک می‌کنند.

کلید رمزگشایی راز نباید در خود مخزن باشد؛ وگرنه برای مهاجمانی که به کد دسترسی پیدا می‌کنند در دسترس است. باید از یکی از رویکردهای دیگر توصیف‌شده در اینجا برای فعال‌سازی رمزگشایی استفاده کنید.

مجوزدهی بدون راز

بسیاری از سرویس‌ها و سیستم‌ها راهی برای مجوزدهی به عمل بدون استفاده از راز ارائه می‌دهند. بیشتر پلتفرم‌های ابری می‌توانند سرویس محاسباتی — مانند ماشین مجازی یا نمونهٔ کانتینر — را برای اقدامات ممتاز مجاز علامت‌گذاری کنند.

مثلاً نمونهٔ AWS EC2 می‌تواند پروفایل IAM داشته باشد که به فرآیندهای روی نمونه حق انجام مجموعه‌ای از دستورات API را می‌دهد. اگر ابزار مدیریت پشته را طوری پیکربندی کنید که روی یکی از این نمونه‌ها اجرا شود، از نیاز به مدیریت رازی که مهاجمان ممکن است بهره برداری کنند اجتناب می‌کنید.

در برخی موارد، مجوزدهی بدون راز می‌تواند از نیاز به تأمین رازها روی زیرساخت هنگام ایجاد آن اجتناب کند. مثلاً سرور برنامه ممکن است به نمونهٔ پایگاه داده دسترسی نیاز داشته باشد. به‌جای تأمین گذرواژه روی سرور برنامه توسط ابزار پیکربندی سرور، سرور پایگاه داده می‌تواند طوری پیکربندی شود که اتصالات از سرور برنامه را مجاز کند، شاید بر اساس آدرس شبکهٔ آن.

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

تزریق راز در زمان اجرا

وقتی نمی‌توانید از استفاده از راز برای پشته یا کد زیرساخت دیگر اجتناب کنید، می‌توانید راه‌های تزریق راز در زمان اجرا را بررسی کنید. معمولاً آن را به‌عنوان پارامتر پشته پیاده می‌کنید که موضوع فصل ۷ است. جزئیات مدیریت رازها به‌عنوان پارامتر را با هر الگو و ضدالگوی این فصل توصیف می‌کنم.

دو موقعیت زمان اجرای متفاوت برای در نظر گرفتن وجود دارد: توسعهٔ محلی و عامل‌های بدون حضور. افرادی که روی کد زیرساخت کار می‌کنند اغلب رازها را در فایل محلی نگه می‌دارند که در کنترل نسخه ذخیره نمی‌شود.³ ابزار پشته می‌تواند مستقیماً آن فایل را بخواند، که به‌ویژه اگر از الگوی فایل‌های پیکربندی پشته استفاده می‌کنید مناسب است (به «الگو: فایل‌های پیکربندی پشته» در صفحه ۸۷ مراجعه کنید). یا فایل می‌تواند اسکریپتی باشد که رازها را در متغیرهای محیطی تنظیم می‌کند، که با الگوی متغیرهای محیطی پشته خوب کار می‌کند (به «الگو: متغیرهای محیطی پشته» در صفحه ۸۲ مراجعه کنید).

این رویکردها روی عامل‌های بدون حضور هم کار می‌کنند، مثل آن‌هایی که برای تست CI یا خط لوله‌های تحویل CD استفاده می‌شوند.⁴ اما باید رازها را روی سرور یا کانتینری که عامل را اجرا می‌کند ذخیره کنید. به‌طور جایگزین، می‌توانید از قابلیت‌های مدیریت راز نرم‌افزار عامل برای دادن رازها به دستور پشته استفاده کنید، مانند الگوی پارامترهای پشته در خط لوله (به «الگو: پارامترهای پشته در خط لوله» در صفحه ۹۳ مراجعه کنید). گزینهٔ دیگر کشیدن رازها از سرویس مدیریت راز (از نوعی که در «منابع ذخیره‌سازی» در صفحه ۲۹ توصیف شد) است که با الگوی ثبت پارامتر پشته هم‌راستا است (به «الگو: ثبت پارامتر پشته» در صفحه ۹۶ مراجعه کنید).

رازهای یکبارمصرف

کار جالبی که با پلتفرم‌های پویا می‌توانید انجام دهید ایجاد راز در لحظه و استفاده فقط بر اساس «نیاز به دانستن» است. در مثال گذرواژهٔ پایگاه داده، کدی که پایگاه داده را تأمین می‌کند خودکار گذرواژه تولید و به کدی که سرور برنامه را تأمین می‌کند می‌دهد. انسان‌ها هرگز نیازی به دیدن راز ندارند، پس هرگز جای دیگری ذخیره نمی‌شود.

می‌توانید کد را برای بازنشانی گذرواژه در صورت نیاز اعمال کنید. اگر سرور برنامه بازسازی شود، می‌توانید کد سرور پایگاه داده را دوباره اجرا کنید تا گذرواژهٔ جدیدی برای آن تولید کند.

سرویس‌های مدیریت راز، مانند HashiCorp Vault، هم می‌توانند گذرواژه تولید و در سیستم‌ها و سرویس‌های دیگر در لحظه تنظیم کنند. سپس می‌توانند گذرواژه را یا هنگام تأمین زیرساخت به ابزار پشته در دسترس قرار دهند، یا مستقیماً به سرویسی که از آن استفاده می‌کند، مثل سرور برنامه. گذرواژه‌های یک‌بارمصرف این رویکرد را به حد افراط می‌برند با ایجاد گذرواژهٔ جدید در هر بار احراز هویت.

جمع‌بندی

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

پروژهٔ پشته باید شکل پشته‌ای را تعریف کند که در همهٔ نمونه‌ها سازگار است. کاملاً قابل‌قبول است دو پروژهٔ پشتهٔ مختلف داشته باشید که ظاهراً مشابه — مثلاً سرورهای برنامه — اما با اشکال متفاوت تعریف می‌کنند.


³ نحوهٔ کار افراد روی کد پشته به‌صورت محلی را با جزئیات بیشتر در «نمونه‌های زیرساخت شخصی» در صفحه ۳۴۷ توضیح می‌دهم.

⁴ نحوهٔ استفاده از این‌ها را در «خط‌ لوله‌های تحویل زیرساخت» در صفحه ۱۱۹ توصیف می‌کنم.