مقدمه ای بر عروسک

Puppet یک سیستم مدیریت پیکربندی است. برای رساندن هاست به حالت دلخواه و حفظ این حالت استفاده می شود.

من الان بیش از پنج سال است که با Puppet کار می کنم. این متن اساساً مجموعه ای ترجمه شده و مرتب شده از نکات کلیدی از اسناد رسمی است که به مبتدیان اجازه می دهد تا به سرعت ماهیت عروسک را درک کنند.

مقدمه ای بر عروسک

اطلاعات اولیه

سیستم عامل Puppet کلاینت-سرور است، اگرچه از عملیات بدون سرور با عملکرد محدود نیز پشتیبانی می کند.

یک مدل عملیات کششی استفاده می شود: به طور پیش فرض، هر نیم ساعت یک بار، مشتریان برای پیکربندی با سرور تماس می گیرند و آن را اعمال می کنند. اگر با Ansible کار کرده اید، آنها از یک مدل فشار متفاوت استفاده می کنند: مدیر فرآیند اعمال پیکربندی را آغاز می کند، خود کلاینت ها چیزی را اعمال نمی کنند.

در طول ارتباطات شبکه، از رمزگذاری دو طرفه TLS استفاده می شود: سرور و مشتری دارای کلیدهای خصوصی و گواهی نامه های مربوطه هستند. به طور معمول سرور برای کلاینت ها گواهی صادر می کند، اما در اصل امکان استفاده از یک CA خارجی وجود دارد.

مقدمه ای بر مانیفست ها

در اصطلاحات عروسکی به سرور عروسکی اتصال گره ها (گره ها). پیکربندی برای گره ها نوشته شده است در مانیفست ها در یک زبان برنامه نویسی خاص - Puppet DSL.

Puppet DSL یک زبان اعلانی است. وضعیت مورد نظر گره را در قالب اعلان منابع فردی توصیف می کند، به عنوان مثال:

  • فایل موجود است و محتوای خاصی دارد.
  • بسته نصب شده است.
  • سرویس شروع شده است.

منابع می توانند به هم مرتبط باشند:

  • وابستگی هایی وجود دارد، آنها بر ترتیب استفاده از منابع تأثیر می گذارند.
    به عنوان مثال، "ابتدا بسته را نصب کنید، سپس فایل پیکربندی را ویرایش کنید، سپس سرویس را شروع کنید."
  • اعلان‌هایی وجود دارد - اگر منبعی تغییر کرده باشد، اعلان‌ها را به منابع مشترک شده ارسال می‌کند.
    به عنوان مثال، اگر فایل پیکربندی تغییر کند، می توانید به طور خودکار سرویس را راه اندازی مجدد کنید.

علاوه بر این، Puppet DSL دارای توابع و متغیرها و همچنین دستورات شرطی و انتخابگرها است. مکانیسم های قالب بندی مختلفی نیز پشتیبانی می شوند - EPP و ERB.

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

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

نحو و سبک کد

در اینجا بخش‌هایی از اسناد رسمی وجود دارد که اگر مثال‌های ارائه‌شده کافی نباشد، به شما در درک نحو کمک می‌کند:

در اینجا نمونه ای از ظاهر مانیفست آمده است:

# Комментарии пишутся, как и много где, после решётки.
#
# Описание конфигурации ноды начинается с ключевого слова node,
# за которым следует селектор ноды — хостнейм (с доменом или без)
# или регулярное выражение для хостнеймов, или ключевое слово default.
#
# После этого в фигурных скобках описывается собственно конфигурация ноды.
#
# Одна и та же нода может попасть под несколько селекторов. Про приоритет
# селекторов написано в статье про синтаксис описания нод.
node 'hostname', 'f.q.d.n', /regexp/ {
  # Конфигурация по сути является перечислением ресурсов и их параметров.
  #
  # У каждого ресурса есть тип и название.
  #
  # Внимание: не может быть двух ресурсов одного типа с одинаковыми названиями!
  #
  # Описание ресурса начинается с его типа. Тип пишется в нижнем регистре.
  # Про разные типы ресурсов написано ниже.
  #
  # После типа в фигурных скобках пишется название ресурса, потом двоеточие,
  # дальше идёт опциональное перечисление параметров ресурса и их значений.
  # Значения параметров указываются через т.н. hash rocket (=>).
  resource { 'title':
    param1 => value1,
    param2 => value2,
    param3 => value3,
  }
}

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

  • تورفتگی های دو فضایی، زبانه ها استفاده نمی شود.
  • بریس های فرفری با یک فاصله از هم جدا می شوند، کولون ها با فاصله از هم جدا نمی شوند.
  • کاما بعد از هر پارامتر، از جمله آخرین. هر پارامتر در یک خط جداگانه قرار دارد. یک استثنا برای مورد بدون پارامتر و یک پارامتر ایجاد شده است: می توانید روی یک خط و بدون کاما بنویسید (یعنی. resource { 'title': } и resource { 'title': param => value }).
  • فلش های روی پارامترها باید در یک سطح باشند.
  • فلش های ارتباط منابع در مقابل آنها نوشته شده است.

محل فایل ها در pappetserver

برای توضیح بیشتر، مفهوم “ریت دایرکتوری” را معرفی می کنم. دایرکتوری ریشه دایرکتوری است که شامل پیکربندی Puppet برای یک گره خاص است.

دایرکتوری ریشه بسته به نسخه Puppet و محیط های مورد استفاده متفاوت است. محیط ها مجموعه های مستقلی از پیکربندی هستند که در دایرکتوری های جداگانه ذخیره می شوند. معمولاً در ترکیب با git استفاده می شود که در این صورت محیط ها از شاخه های git ایجاد می شوند. بر این اساس، هر گره در یک محیط یا محیط دیگر قرار دارد. این را می توان روی خود گره یا در ENC پیکربندی کرد که در مقاله بعدی در مورد آن صحبت خواهم کرد.

  • در نسخه سوم ("Puppet قدیمی") دایرکتوری پایه بود /etc/puppet. استفاده از محیط ها اختیاری است - به عنوان مثال، ما از آنها با Puppet قدیمی استفاده نمی کنیم. اگر از محیط ها استفاده می شود، معمولاً در آنها ذخیره می شوند /etc/puppet/environments، دایرکتوری ریشه دایرکتوری محیط خواهد بود. اگر از محیط ها استفاده نمی شود، دایرکتوری ریشه دایرکتوری پایه خواهد بود.
  • با شروع از نسخه چهارم ("Puppet جدید")، استفاده از محیط ها اجباری شد و دایرکتوری پایه به /etc/puppetlabs/code. بر این اساس، محیط ها در آن ذخیره می شوند /etc/puppetlabs/code/environments، دایرکتوری ریشه دایرکتوری محیط است.

باید یک زیر شاخه در دایرکتوری ریشه وجود داشته باشد manifests، که شامل یک یا چند نمایشگر است که گره ها را توصیف می کند. علاوه بر این، باید یک زیر شاخه وجود داشته باشد modules، که شامل ماژول ها است. ماژول ها را کمی بعد به شما خواهم گفت. علاوه بر این، Puppet قدیمی ممکن است یک زیر شاخه نیز داشته باشد filesکه حاوی فایل های مختلفی است که در گره ها کپی می کنیم. در Puppet جدید تمامی فایل ها در ماژول ها قرار می گیرند.

فایل های مانیفست دارای پسوند هستند .pp.

چند نمونه جنگی

شرح گره و منبع روی آن

روی گره server1.testdomain یک فایل باید ایجاد شود /etc/issue با محتوا Debian GNU/Linux n l. فایل باید متعلق به یک کاربر و گروه باشد root، حقوق دسترسی باید باشد 644.

ما یک مانیفست می نویسیم:

node 'server1.testdomain' {   # блок конфигурации, относящийся к ноде server1.testdomain
    file { '/etc/issue':   # описываем файл /etc/issue
        ensure  => present,   # этот файл должен существовать
        content => 'Debian GNU/Linux n l',   # у него должно быть такое содержимое
        owner   => root,   # пользователь-владелец
        group   => root,   # группа-владелец
        mode    => '0644',   # права на файл. Они заданы в виде строки (в кавычках), потому что иначе число с 0 в начале будет воспринято как записанное в восьмеричной системе, и всё пойдёт не так, как задумано
    }
}

روابط بین منابع روی یک گره

روی گره server2.testdomain nginx باید در حال اجرا باشد و با یک پیکربندی از قبل آماده شده کار کند.

بیایید مشکل را تجزیه کنیم:

  • بسته باید نصب شود nginx.
  • لازم است که فایل های پیکربندی از سرور کپی شوند.
  • سرویس باید در حال اجرا باشد nginx.
  • اگر پیکربندی به روز شود، سرویس باید دوباره راه اندازی شود.

ما یک مانیفست می نویسیم:

node 'server2.testdomain' {   # блок конфигурации, относящийся к ноде server2.testdomain
    package { 'nginx':   # описываем пакет nginx
        ensure => installed,   # он должен быть установлен
    }
  # Прямая стрелка (->) говорит о том, что ресурс ниже должен
  # создаваться после ресурса, описанного выше.
  # Такие зависимости транзитивны.
    -> file { '/etc/nginx':   # описываем файл /etc/nginx
        ensure  => directory,   # это должна быть директория
        source  => 'puppet:///modules/example/nginx-conf',   # её содержимое нужно брать с паппет-сервера по указанному адресу
        recurse => true,   # копировать файлы рекурсивно
        purge   => true,   # нужно удалять лишние файлы (те, которых нет в источнике)
        force   => true,   # удалять лишние директории
    }
  # Волнистая стрелка (~>) говорит о том, что ресурс ниже должен
  # подписаться на изменения ресурса, описанного выше.
  # Волнистая стрелка включает в себя прямую (->).
    ~> service { 'nginx':   # описываем сервис nginx
        ensure => running,   # он должен быть запущен
        enable => true,   # его нужно запускать автоматически при старте системы
    }
  # Когда ресурс типа service получает уведомление,
  # соответствующий сервис перезапускается.
}

برای انجام این کار، تقریباً به مکان فایل زیر در سرور عروسکی نیاز دارید:

/etc/puppetlabs/code/environments/production/ # (это для нового Паппета, для старого корневой директорией будет /etc/puppet)
├── manifests/
│   └── site.pp
└── modules/
    └── example/
        └── files/
            └── nginx-conf/
                ├── nginx.conf
                ├── mime.types
                └── conf.d/
                    └── some.conf

انواع منابع

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

پرونده

فایل ها، دایرکتوری ها، پیوندهای نمادین، محتویات آنها و حقوق دسترسی را مدیریت می کند.

پارامترهای:

  • نام منبع - مسیر فایل (اختیاری)
  • مسیر - مسیر فایل (اگر در نام آن مشخص نشده باشد)
  • اطمینان حاصل شود - نوع فایل:
    • absent - حذف یک فایل
    • present - باید یک فایل از هر نوع وجود داشته باشد (اگر فایلی وجود نداشته باشد، یک فایل معمولی ایجاد می شود)
    • file - فایل معمولی
    • directory - فهرست راهنما
    • link - پیوند نمادین
  • محتوا - محتویات فایل (فقط برای فایل های معمولی مناسب است، نمی توان با آنها استفاده کرد منبع یا هدف)
  • منبع - پیوندی به مسیری که می خواهید محتویات فایل را از آن کپی کنید (نمی توان با آن استفاده کرد محتوا یا هدف). می تواند به عنوان یک URI با یک طرح مشخص شود puppet: (سپس از فایل های سرور عروسکی استفاده می شود)، و با طرح http: (امیدوارم واضح باشد که در این مورد چه اتفاقی خواهد افتاد)، و حتی با نمودار file: یا به عنوان یک مسیر مطلق بدون طرحواره (سپس از فایل FS محلی روی گره استفاده خواهد شد)
  • هدف - جایی که علامت پیوند باید به آن اشاره کند (نمی توان با آن استفاده کرد محتوا یا منبع)
  • مالک - کاربری که باید مالک فایل باشد
  • گروه - گروهی که فایل باید به آن تعلق داشته باشد
  • حالت - مجوزهای فایل (به عنوان یک رشته)
  • پس گرفتن - پردازش دایرکتوری بازگشتی را فعال می کند
  • پالایش - حذف فایل هایی که در Puppet توضیح داده نشده اند را فعال می کند
  • مجبور - حذف دایرکتوری هایی که در Puppet توضیح داده نشده اند را فعال می کند

بسته

بسته ها را نصب و حذف می کند. قادر به رسیدگی به اعلان ها - اگر پارامتر مشخص شده باشد، بسته را دوباره نصب می کند reinstall_on_refresh.

پارامترهای:

  • نام منبع - نام بسته (اختیاری)
  • نام - نام بسته (اگر در نام مشخص نشده باشد)
  • ارائه دهنده - مدیر بسته برای استفاده
  • اطمینان حاصل شود - وضعیت مطلوب بسته:
    • present, installed - هر نسخه نصب شده
    • latest - آخرین نسخه نصب شده
    • absent - حذف شده (apt-get remove)
    • purged - حذف شده به همراه فایل های پیکربندی (apt-get purge)
    • held - نسخه بسته قفل شده است (apt-mark hold)
    • любая другая строка - نسخه مشخص شده نصب شده است
  • reinstall_on_refresh - اگر یک true، پس از دریافت اعلان بسته مجدداً نصب می شود. برای توزیع های مبتنی بر منبع مفید است، جایی که بازسازی بسته ها ممکن است هنگام تغییر پارامترهای ساخت ضروری باشد. پیش فرض false.

سرویس

خدمات را مدیریت می کند. قادر به پردازش اعلان ها - سرویس را دوباره راه اندازی می کند.

پارامترهای:

  • نام منبع - خدمات قابل مدیریت (اختیاری)
  • نام - سرویسی که باید مدیریت شود (اگر در نام آن مشخص نشده باشد)
  • اطمینان حاصل شود - وضعیت مطلوب سرویس:
    • running - راه اندازی شد
    • stopped - متوقف شد
  • قادر ساختن - توانایی شروع سرویس را کنترل می کند:
    • true - اتوران فعال است (systemctl enable)
    • mask - مبدل (systemctl mask)
    • false - اتوران غیرفعال است (systemctl disable)
  • شروع دوباره - دستور راه اندازی مجدد سرویس
  • وضعیت - فرمان برای بررسی وضعیت سرویس
  • has restart - نشان می دهد که آیا سرویس initscript از راه اندازی مجدد پشتیبانی می کند یا خیر. اگر false و پارامتر مشخص شده است شروع دوباره - مقدار این پارامتر استفاده می شود. اگر false و پارامتر شروع دوباره مشخص نشده است - سرویس متوقف شده و شروع به راه اندازی مجدد می کند (اما systemd از دستور استفاده می کند systemctl restart).
  • وضعیت - نشان می دهد که آیا سرویس initscript از دستور پشتیبانی می کند یا خیر status. اگر false، سپس از مقدار پارامتر استفاده می شود وضعیت. پیش فرض true.

exec

دستورات خارجی را اجرا می کند. اگر پارامترها را مشخص نکنید ایجاد, فقط اگر, مگر یا تازه، هر بار که Puppet اجرا می شود، دستور اجرا می شود. قادر به پردازش اعلان ها - یک فرمان را اجرا می کند.

پارامترهای:

  • نام منبع - دستوری که باید اجرا شود (اختیاری)
  • فرمان - دستوری که باید اجرا شود (اگر در نام آن مشخص نشده باشد)
  • مسیر - مسیرهایی که در آنها می توان فایل اجرایی را جستجو کرد
  • فقط اگر - اگر دستور مشخص شده در این پارامتر با یک کد بازگشتی صفر تکمیل شود، دستور اصلی اجرا خواهد شد.
  • مگر - اگر دستور مشخص شده در این پارامتر با یک کد بازگشتی غیر صفر تکمیل شود، دستور اصلی اجرا خواهد شد.
  • ایجاد - اگر فایل مشخص شده در این پارامتر وجود نداشته باشد، دستور اصلی اجرا می شود
  • تازه - اگر یک true، سپس فرمان فقط زمانی اجرا می شود که این exec اعلان از منابع دیگر دریافت کند
  • cwd - دایرکتوری که از آن دستور اجرا می شود
  • کاربر - کاربری که فرمان را از او اجرا کنید
  • ارائه دهنده - نحوه اجرای دستور:
    • پوزيكس - یک فرآیند فرزند به سادگی ایجاد می شود، حتماً مشخص کنید مسیر
    • صدف - فرمان در پوسته راه اندازی می شود /bin/sh، ممکن است مشخص نباشد مسیر، می توانید از globbing، لوله ها و سایر ویژگی های پوسته استفاده کنید. معمولاً در صورت وجود کاراکترهای خاص به طور خودکار شناسایی می شود (|, ;, &&, || و غیره).

cron را

cronjob ها را کنترل می کند.

پارامترهای:

  • نام منبع - فقط نوعی شناسه
  • اطمینان حاصل شود - ایالت کرونجوب:
    • present - ایجاد کنید اگر وجود ندارد
    • absent - در صورت وجود حذف کنید
  • فرمان - چه دستوری اجرا شود
  • محیط - در کدام محیط باید دستور اجرا شود (لیست متغیرهای محیط و مقادیر آنها از طریق =)
  • کاربر - از کدام کاربری دستور را اجرا کنید
  • دقیقه, ساعت, روز هفته, ماه, ماه روز - زمان اجرای cron. اگر هر یک از این ویژگی ها مشخص نشده باشد، مقدار آن در crontab خواهد بود *.

در Puppet 6.0 cron را انگار از جعبه حذف شد در puppetserver، بنابراین هیچ سندی در سایت عمومی وجود ندارد. اما او در جعبه است در Puppet-agent، بنابراین نیازی به نصب جداگانه آن نیست. می توانید مستندات مربوط به آن را مشاهده کنید در مستندات نسخه پنجم عروسکیا در GitHub.

در مورد منابع به طور کلی

الزامات منحصر به فرد بودن منابع

رایج ترین اشتباهی که با آن مواجه می شویم این است اعلامیه تکراری. این خطا زمانی رخ می دهد که دو یا چند منبع از یک نوع با نام یکسان در دایرکتوری ظاهر شوند.

لذا باز هم خواهم نوشت: مانیفست برای همان گره نباید حاوی منابعی از همان نوع با عنوان یکسان باشد!

گاهی اوقات نیاز به نصب بسته هایی با نام یکسان، اما با مدیریت بسته های مختلف وجود دارد. در این مورد، شما باید از پارامتر استفاده کنید nameبرای جلوگیری از خطا:

package { 'ruby-mysql':
  ensure   => installed,
  name     => 'mysql',
  provider => 'gem',
}
package { 'python-mysql':
  ensure   => installed,
  name     => 'mysql',
  provider => 'pip',
}

سایر انواع منابع گزینه های مشابهی برای کمک به جلوگیری از تکرار - دارند name у سرویس, command у exec، و غیره.

فراپارامترها

هر نوع منبع، بدون توجه به ماهیت آن، پارامترهای خاصی دارد.

لیست کامل متا پارامترها در مستندات عروسکی.

فهرست کوتاه:

  • نیاز - این پارامتر نشان می دهد که این منبع به کدام منابع بستگی دارد.
  • قبل از - این پارامتر مشخص می کند که کدام منابع به این منبع بستگی دارد.
  • مشترک — این پارامتر مشخص می کند که این منبع اعلان ها را از چه منابعی دریافت می کند.
  • مطلع ساختن — این پارامتر مشخص می کند که کدام منابع اعلان ها را از این منبع دریافت می کنند.

همه فراپارامترهای فهرست شده یک پیوند منبع یا آرایه ای از پیوندها را در براکت می پذیرند.

پیوند به منابع

پیوند منبع صرفاً ذکر منبع است. آنها عمدتاً برای نشان دادن وابستگی ها استفاده می شوند. ارجاع به منبعی که وجود ندارد باعث خطای کامپایل می شود.

نحو پیوند به این صورت است: نوع منبع با یک حرف بزرگ (اگر نام نوع حاوی دو دونقطه باشد، هر قسمت از نام بین دو نقطه با حروف بزرگ نوشته می شود)، سپس نام منبع در براکت مربع (مورد نام). تغییر نمی کند!). هیچ فاصله ای نباید وجود داشته باشد، براکت ها بلافاصله بعد از نام نوع نوشته می شوند.

به عنوان مثال:

file { '/file1': ensure => present }
file { '/file2':
  ensure => directory,
  before => File['/file1'],
}
file { '/file3': ensure => absent }
File['/file1'] -> File['/file3']

وابستگی ها و اعلان ها

مستندات اینجا

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

برخلاف وابستگی ها، اعلان ها انتقالی نیستند. قوانین زیر برای اعلان ها اعمال می شود:

  • اگر منبع اعلان دریافت کند، به روز می شود. اقدامات به روز رسانی به نوع منبع - بستگی دارد exec دستور را اجرا می کند، سرویس سرویس را دوباره راه اندازی می کند، بسته بسته را دوباره نصب می کند اگر منبع یک اقدام به روز رسانی تعریف نشده باشد، هیچ اتفاقی نمی افتد.
  • در طول یک اجرای Puppet، منبع بیش از یک بار به روز نمی شود. این امکان پذیر است زیرا اعلان ها شامل وابستگی هستند و نمودار وابستگی شامل چرخه نیست.
  • اگر Puppet وضعیت یک منبع را تغییر دهد، منبع اعلان‌هایی را به تمام منابعی که در آن مشترک شده‌اند ارسال می‌کند.
  • اگر منبعی به‌روزرسانی شود، اعلان‌هایی را به همه منابعی که در آن مشترک هستند ارسال می‌کند.

کنترل پارامترهای نامشخص

به عنوان یک قاعده، اگر برخی از پارامترهای منبع دارای مقدار پیش فرض نباشد و این پارامتر در مانیفست مشخص نشده باشد، Puppet این ویژگی را برای منبع مربوطه در گره تغییر نخواهد داد. به عنوان مثال، اگر یک منبع از نوع پرونده پارامتر مشخص نشده است owner، سپس Puppet صاحب فایل مربوطه را تغییر نخواهد داد.

مقدمه ای بر کلاس ها، متغیرها و تعاریف

فرض کنید چندین گره داریم که قسمت مشابهی از پیکربندی دارند، اما تفاوت‌هایی نیز وجود دارد - در غیر این صورت می‌توانیم همه آن‌ها را در یک بلوک توصیف کنیم. node {}. البته، شما می توانید به سادگی قسمت های یکسان پیکربندی را کپی کنید، اما به طور کلی این یک راه حل بد است - پیکربندی رشد می کند، و اگر قسمت کلی پیکربندی را تغییر دهید، باید همان مورد را در بسیاری از مکان ها ویرایش کنید. در عین حال، اشتباه کردن آسان است، و به طور کلی، اصل DRY (خودت را تکرار نکن) به دلیلی اختراع شد.

برای حل این مشکل چنین طراحی وجود دارد کلاس.

کلاس ها

کلاس یک بلوک با نام از کد poppet است. برای استفاده مجدد از کد به کلاس ها نیاز است.

ابتدا کلاس باید توضیح داده شود. خود توضیحات هیچ منبعی را در هیچ کجا اضافه نمی کند. کلاس در مانیفست ها توضیح داده شده است:

# Описание класса начинается с ключевого слова class и его названия.
# Дальше идёт тело класса в фигурных скобках.
class example_class {
    ...
}

بعد از این می توان از کلاس استفاده کرد:

# первый вариант использования — в стиле ресурса с типом class
class { 'example_class': }
# второй вариант использования — с помощью функции include
include example_class
# про отличие этих двух вариантов будет рассказано дальше

مثالی از کار قبلی - اجازه دهید نصب و پیکربندی nginx را به یک کلاس منتقل کنیم:

class nginx_example {
    package { 'nginx':
        ensure => installed,
    }
    -> file { '/etc/nginx':
        ensure => directory,
        source => 'puppet:///modules/example/nginx-conf',
        recure => true,
        purge  => true,
        force  => true,
    }
    ~> service { 'nginx':
        ensure => running,
        enable => true,
    }
}

node 'server2.testdomain' {
    include nginx_example
}

متغیرها

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

می شه انجامش داد با استفاده از متغیرها.

توجه: متغیرها در Puppet تغییر ناپذیر هستند!

علاوه بر این، یک متغیر تنها پس از اعلام قابل دسترسی است، در غیر این صورت مقدار متغیر خواهد بود undef.

مثالی از کار با متغیرها:

# создание переменных
$variable = 'value'
$var2 = 1
$var3 = true
$var4 = undef
# использование переменных
$var5 = $var6
file { '/tmp/text': content => $variable }
# интерполяция переменных — раскрытие значения переменных в строках. Работает только в двойных кавычках!
$var6 = "Variable with name variable has value ${variable}"

عروسک دارد فضاهای نام، و متغیرها، بر این اساس، دارند منطقه دید: متغیری با نام یکسان را می توان در فضاهای نام مختلف تعریف کرد. هنگام حل مقدار یک متغیر، متغیر در فضای نام فعلی، سپس در فضای نام محصور و غیره جستجو می شود.

نمونه های فضای نام:

  • global - متغیرهای خارج از توضیحات کلاس یا گره به آنجا می روند.
  • فضای نام گره در توضیحات گره؛
  • فضای نام کلاس در توضیحات کلاس.

برای جلوگیری از ابهام در هنگام دسترسی به یک متغیر، می توانید فضای نام را در نام متغیر مشخص کنید:

# переменная без пространства имён
$var
# переменная в глобальном пространстве имён
$::var
# переменная в пространстве имён класса
$classname::var
$::classname::var

بیایید قبول کنیم که مسیر پیکربندی nginx در متغیر نهفته است $nginx_conf_source. سپس کلاس به شکل زیر خواهد بود:

class nginx_example {
    package { 'nginx':
        ensure => installed,
    }
    -> file { '/etc/nginx':
        ensure => directory,
        source => $nginx_conf_source,   # здесь используем переменную вместо фиксированной строки
        recure => true,
        purge  => true,
        force  => true,
    }
    ~> service { 'nginx':
        ensure => running,
        enable => true,
    }
}

node 'server2.testdomain' {
    $nginx_conf_source = 'puppet:///modules/example/nginx-conf'
    include nginx_example
}

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

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

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

بیایید کلاس را از مثال بالا پارامتر کنیم و دو پارامتر اضافه کنیم: اولی، مورد نیاز، مسیر پیکربندی است، و دومی، اختیاری، نام بسته با nginx است (مثلاً در دبیان، بسته هایی وجود دارد. nginx, nginx-light, nginx-full).

# переменные описываются сразу после имени класса в круглых скобках
class nginx_example (
  $conf_source,
  $package_name = 'nginx-light', # параметр со значением по умолчанию
) {
  package { $package_name:
    ensure => installed,
  }
  -> file { '/etc/nginx':
    ensure  => directory,
    source  => $conf_source,
    recurse => true,
    purge   => true,
    force   => true,
  }
  ~> service { 'nginx':
    ensure => running,
    enable => true,
  }
}

node 'server2.testdomain' {
  # если мы хотим задать параметры класса, функция include не подойдёт* — нужно использовать resource-style declaration
  # *на самом деле подойдёт, но про это расскажу в следующей серии. Ключевое слово "Hiera".
  class { 'nginx_example':
    conf_source => 'puppet:///modules/example/nginx-conf',   # задаём параметры класса точно так же, как параметры для других ресурсов
  }
}

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

نوع بلافاصله قبل از نام پارامتر نوشته می شود:

class example (
  String $param1,
  Integer $param2,
  Array $param3,
  Hash $param4,
  Hash[String, String] $param5,
) {
  ...
}

کلاس‌ها: شامل نام کلاس در مقابل کلاس{'classname':}

هر کلاس یک منبع از نوع است کلاس. مانند هر نوع منبع دیگری، نمی توان دو نمونه از یک کلاس در یک گره وجود داشته باشد.

اگر سعی کنید یک کلاس را دو بار با استفاده از یک گره اضافه کنید class { 'classname':} (بدون تفاوت، با پارامترهای متفاوت یا یکسان)، یک خطای کامپایل وجود خواهد داشت. اما اگر از یک کلاس در سبک منبع استفاده می کنید، می توانید بلافاصله تمام پارامترهای آن را در مانیفست تنظیم کنید.

با این حال، اگر استفاده کنید include، سپس کلاس را می توان به تعداد دفعات مورد نظر اضافه کرد. حقیقت این هست که include یک تابع idempotent است که بررسی می کند آیا یک کلاس به دایرکتوری اضافه شده است یا خیر. اگر کلاس در دایرکتوری نباشد، آن را اضافه می کند و اگر از قبل وجود داشته باشد، کاری انجام نمی دهد. اما در صورت استفاده include شما نمی توانید پارامترهای کلاس را در طول اعلان کلاس تنظیم کنید - همه پارامترهای مورد نیاز باید در یک منبع داده خارجی - Hiera یا ENC تنظیم شوند. در مقاله بعدی در مورد آنها صحبت خواهیم کرد.

تعریف می کند

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

به عنوان مثال، برای نصب ماژول PHP، در Avito موارد زیر را انجام می دهیم:

  1. بسته را با این ماژول نصب کنید.
  2. بیایید یک فایل پیکربندی برای این ماژول ایجاد کنیم.
  3. ما یک سیم لینک به پیکربندی برای php-fpm ایجاد می کنیم.
  4. برای php cli یک سیم لینک به پیکربندی ایجاد می کنیم.

در چنین مواردی طرحی مانند تعريف كردن (تعریف، نوع تعریف شده، نوع منبع تعریف شده). A Define شبیه به یک کلاس است، اما تفاوت هایی وجود دارد: اول، هر Define یک نوع منبع است، نه یک منبع. ثانیاً، هر تعریف دارای یک پارامتر ضمنی است $title، جایی که نام منبع زمانی که اعلام می شود می رود. همانطور که در مورد کلاس ها، ابتدا باید یک تعریف توضیح داده شود، سپس می توان از آن استفاده کرد.

یک مثال ساده با یک ماژول برای PHP:

define php74::module (
  $php_module_name = $title,
  $php_package_name = "php7.4-${title}",
  $version = 'installed',
  $priority = '20',
  $data = "extension=${title}.son",
  $php_module_path = '/etc/php/7.4/mods-available',
) {
  package { $php_package_name:
    ensure          => $version,
    install_options => ['-o', 'DPkg::NoTriggers=true'],  # триггеры дебиановских php-пакетов сами создают симлинки и перезапускают сервис php-fpm - нам это не нужно, так как и симлинками, и сервисом мы управляем с помощью Puppet
  }
  -> file { "${php_module_path}/${php_module_name}.ini":
    ensure  => $ensure,
    content => $data,
  }
  file { "/etc/php/7.4/cli/conf.d/${priority}-${php_module_name}.ini":
    ensure  => link,
    target  => "${php_module_path}/${php_module_name}.ini",
  }
  file { "/etc/php/7.4/fpm/conf.d/${priority}-${php_module_name}.ini":
    ensure  => link,
    target  => "${php_module_path}/${php_module_name}.ini",
  }
}

node server3.testdomain {
  php74::module { 'sqlite3': }
  php74::module { 'amqp': php_package_name => 'php-amqp' }
  php74::module { 'msgpack': priority => '10' }
}

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

محافظت از خود در برابر این امر آسان است: همه منابع داخل تعریف باید بسته به این نام دارای نام باشند $title. یک جایگزین، اضافه کردن منابع بدون توان است؛ در ساده ترین حالت، کافی است منابع مشترک برای همه نمونه های تعریف را به یک کلاس جداگانه منتقل کنید و این کلاس را در تعریف - تابع قرار دهید. include ناتوان

راه های دیگری نیز برای دستیابی به ناتوانی در هنگام افزودن منابع وجود دارد، یعنی استفاده از توابع defined и ensure_resources، اما در قسمت بعدی در مورد آن به شما خواهم گفت.

وابستگی ها و اعلان ها برای کلاس ها و تعاریف

کلاس ها و تعاریف قوانین زیر را به مدیریت وابستگی ها و اعلان ها اضافه می کنند:

  • وابستگی به یک کلاس/define وابستگی هایی را به تمام منابع کلاس/define اضافه می کند.
  • یک وابستگی کلاس/تعریف، وابستگی هایی را به همه منابع کلاس/تعریف اضافه می کند.
  • اطلاعیه class/define همه منابع کلاس/define را مطلع می کند.
  • اشتراک class/define مشترک تمام منابع کلاس/define است.

عبارات شرطی و انتخابگرها

مستندات اینجا

if

همه چیز در اینجا ساده است:

if ВЫРАЖЕНИЕ1 {
  ...
} elsif ВЫРАЖЕНИЕ2 {
  ...
} else {
  ...
}

مگر

مگر اینکه یک if در معکوس باشد: اگر عبارت نادرست باشد، بلوک کد اجرا می شود.

unless ВЫРАЖЕНИЕ {
  ...
}

مورد

اینجا هم هیچ چیز پیچیده ای نیست. می توانید از مقادیر منظم (رشته ها، اعداد و غیره)، عبارات منظم و انواع داده ها به عنوان مقادیر استفاده کنید.

case ВЫРАЖЕНИЕ {
  ЗНАЧЕНИЕ1: { ... }
  ЗНАЧЕНИЕ2, ЗНАЧЕНИЕ3: { ... }
  default: { ... }
}

انتخابگرها

انتخابگر یک ساختار زبانی مشابه است case، اما به جای اجرای یک بلوک کد، مقداری را برمی گرداند.

$var = $othervar ? { 'val1' => 1, 'val2' => 2, default => 3 }

ماژول ها

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

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

ماژول ها - اینها مجموعه ای از کلاس ها، تعاریف و سایر موجودیت های Puppet هستند که در یک فهرست جداگانه قرار می گیرند. به عبارت دیگر، یک ماژول یک قطعه مستقل از منطق عروسکی است. به عنوان مثال، ممکن است یک ماژول برای کار با nginx وجود داشته باشد، و شامل آنچه و تنها چیزی است که برای کار با nginx نیاز است، یا ممکن است یک ماژول برای کار با PHP و غیره باشد.

ماژول ها نسخه بندی شده اند و وابستگی ماژول ها به یکدیگر نیز پشتیبانی می شوند. یک مخزن باز از ماژول ها وجود دارد - عروسک خیمه شب بازی.

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

ساختار فایل در یک ماژول

ریشه ماژول ممکن است شامل دایرکتوری های زیر با نام های توصیفی باشد:

  • manifests - حاوی مانیفست است
  • files - حاوی فایل هایی است
  • templates - حاوی الگوهایی است
  • lib - حاوی کد روبی است

این لیست کاملی از فهرست ها و فایل ها نیست، اما فعلا برای این مقاله کافی است.

نام منابع و نام فایل های موجود در ماژول

مستندات اینجا

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

قوانین ساده هستند:

  • تمام منابع یک ماژول باید در فضای نام ماژول باشد. اگر ماژول فراخوانی شود foo، سپس تمام منابع موجود در آن باید نامگذاری شوند foo::<anything>، یا فقط foo.
  • منبع با نام ماژول باید در فایل باشد init.pp.
  • برای سایر منابع، طرح نامگذاری فایل به شرح زیر است:
    • پیشوند با نام ماژول کنار گذاشته می شود
    • همه دو نقطه، در صورت وجود، با اسلش جایگزین می شوند
    • پسوند اضافه شده است .pp

من با یک مثال نشان خواهم داد. فرض کنید من در حال نوشتن یک ماژول هستم nginx. این شامل منابع زیر است:

  • کلاس nginx در مانیفست شرح داده شده است init.pp;
  • کلاس nginx::service در مانیفست شرح داده شده است service.pp;
  • تعريف كردن nginx::server در مانیفست شرح داده شده است server.pp;
  • تعريف كردن nginx::server::location در مانیفست شرح داده شده است server/location.pp.

قالب

مطمئناً شما خودتان می دانید که چه قالب هایی هستند؛ من آنها را در اینجا به تفصیل شرح نمی دهم. اما من آن را در هر صورت ترک می کنم پیوند به ویکی پدیا.

نحوه استفاده از الگوها: با استفاده از یک تابع می توان معنای یک الگو را گسترش داد template، که مسیر قالب ارسال می شود. برای منابع از نوع پرونده همراه با پارامتر استفاده می شود content. به عنوان مثال، مانند این:

file { '/tmp/example': content => template('modulename/templatename.erb')

مشاهده مسیر <modulename>/<filename> دلالت بر فایل دارد <rootdir>/modules/<modulename>/templates/<filename>.

علاوه بر این ، یک تابع وجود دارد inline_template - متن الگو را به عنوان ورودی دریافت می کند، نه نام فایل.

در قالب ها، می توانید از تمام متغیرهای Puppet در محدوده فعلی استفاده کنید.

Puppet از قالب ها در فرمت ERB و EPP پشتیبانی می کند:

مختصری در مورد ERB

ساختارهای کنترلی:

  • <%= ВЫРАЖЕНИЕ %> - مقدار عبارت را وارد کنید
  • <% ВЫРАЖЕНИЕ %> - محاسبه مقدار یک عبارت (بدون درج آن). عبارات شرطی (if) و حلقه ها (هر کدام) معمولاً به اینجا می روند.
  • <%# КОММЕНТАРИЙ %>

عبارات در ERB به زبان Ruby نوشته می شوند (ERB در واقع Embedded Ruby است).

برای دسترسی به متغیرها از مانیفست، باید اضافه کنید @ به نام متغیر برای حذف یک خط شکست که بعد از یک ساختار کنترل ظاهر می شود، باید از یک تگ بسته استفاده کنید -%>.

نمونه ای از استفاده از قالب

فرض کنید من در حال نوشتن یک ماژول برای کنترل ZooKeeper هستم. کلاسی که مسئول ایجاد پیکربندی است چیزی شبیه به این است:

class zookeeper::configure (
  Array[String] $nodes,
  Integer $port_client,
  Integer $port_quorum,
  Integer $port_leader,
  Hash[String, Any] $properties,
  String $datadir,
) {
  file { '/etc/zookeeper/conf/zoo.cfg':
    ensure  => present,
    content => template('zookeeper/zoo.cfg.erb'),
  }
}

و قالب مربوطه zoo.cfg.erb - بنابراین:

<% if @nodes.length > 0 -%>
<% @nodes.each do |node, id| -%>
server.<%= id %>=<%= node %>:<%= @port_leader %>:<%= @port_quorum %>;<%= @port_client %>
<% end -%>
<% end -%>

dataDir=<%= @datadir %>

<% @properties.each do |k, v| -%>
<%= k %>=<%= v %>
<% end -%>

حقایق و متغیرهای داخلی

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

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

نمونه ای از کار با حقایق:

notify { "Running OS ${facts['os']['name']} version ${facts['os']['release']['full']}": }
# ресурс типа notify просто выводит сообщение в лог

به طور رسمی، یک واقعیت دارای یک نام (رشته) و یک مقدار است (انواع مختلفی در دسترس هستند: رشته ها، آرایه ها، فرهنگ لغت). بخور مجموعه ای از حقایق داخلی. تو می توانی مال خودت را هم بنویسی. گردآورندگان واقعیت شرح داده شده است مانند توابع در روبییا به عنوان فایل های اجرایی. حقایق را نیز می توان در فرم ارائه کرد فایل های متنی با داده روی گره ها

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

حقایق در قالب فایل های اجرایی

چنین حقایقی در ماژول های دایرکتوری قرار می گیرند facts.d. البته فایل ها باید قابل اجرا باشند. هنگام اجرا، آنها باید اطلاعات را به خروجی استاندارد در قالب YAML یا key=value خروجی دهند.

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

#!/bin/sh
echo "testfact=success"
#!/bin/sh
echo '{"testyamlfact":"success"}'

حقایق روبی

چنین حقایقی در ماژول های دایرکتوری قرار می گیرند lib/facter.

# всё начинается с вызова функции Facter.add с именем факта и блоком кода
Facter.add('ladvd') do
# в блоках confine описываются условия применимости факта — код внутри блока должен вернуть true, иначе значение факта не вычисляется и не возвращается
  confine do
    Facter::Core::Execution.which('ladvdc') # проверим, что в PATH есть такой исполняемый файл
  end
  confine do
    File.socket?('/var/run/ladvd.sock') # проверим, что есть такой UNIX-domain socket
  end
# в блоке setcode происходит собственно вычисление значения факта
  setcode do
    hash = {}
    if (out = Facter::Core::Execution.execute('ladvdc -b'))
      out.split.each do |l|
        line = l.split('=')
        next if line.length != 2
        name, value = line
        hash[name.strip.downcase.tr(' ', '_')] = value.strip.chomp(''').reverse.chomp(''').reverse
      end
    end
    hash  # значение последнего выражения в блоке setcode является значением факта
  end
end

حقایق متنی

چنین حقایقی بر روی گره های دایرکتوری قرار می گیرند /etc/facter/facts.d در عروسک قدیمی یا /etc/puppetlabs/facts.d در عروسک جدید

examplefact=examplevalue
---
examplefact2: examplevalue2
anotherfact: anothervalue

رسیدن به حقایق

دو راه برای نزدیک شدن به حقایق وجود دارد:

  • از طریق فرهنگ لغت $facts: $facts['fqdn'];
  • استفاده از نام واقعیت به عنوان نام متغیر: $fqdn.

بهتر است از دیکشنری استفاده کنید $facts، یا حتی بهتر، فضای نام جهانی را نشان دهید ($::facts).

در اینجا بخش مربوطه از مستندات است.

متغیرهای داخلی

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

  • حقایق قابل اعتماد - متغیرهایی که از گواهی مشتری گرفته می شوند (از آنجایی که گواهی معمولاً در یک سرور poppet صادر می شود، عامل نمی تواند گواهینامه خود را بگیرد و تغییر دهد، بنابراین متغیرها "معتمد" هستند): نام گواهی، نام میزبان و دامنه، پسوندهای گواهی.
  • حقایق سرور - متغیرهای مربوط به اطلاعات مربوط به سرور - نسخه، نام، آدرس IP سرور، محیط.
  • حقایق عامل - متغیرهایی که مستقیماً توسط عامل عروسکی اضافه می‌شوند و نه توسط فاکتور - نام گواهی، نسخه عامل، نسخه عروسکی.
  • متغیرهای استاد - متغیرهای Pappetmaster (sic!). تقریباً همان است که در حقایق سرور، به علاوه مقادیر پارامترهای پیکربندی موجود است.
  • متغیرهای کامپایلر - متغیرهای کامپایلر که در هر محدوده متفاوت هستند: نام ماژول فعلی و نام ماژولی که در آن به شی فعلی دسترسی داشته است. برای مثال می توان از آنها برای بررسی اینکه کلاس های خصوصی شما مستقیماً از ماژول های دیگر استفاده نمی شود استفاده کرد.

اضافه 1: چگونه همه اینها را اجرا و اشکال زدایی کنیم؟

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

یک عامل برای اجرای Puppet کافی است، اما در بیشتر موارد به سرور نیز نیاز خواهید داشت.

نماینده

حداقل از نسخه XNUMX، بسته های عامل عروسکی از مخزن رسمی Puppetlabs شامل تمام وابستگی ها (یاقوت و سنگهای مربوطه) است، بنابراین هیچ مشکلی در نصب وجود ندارد (من در مورد توزیع های مبتنی بر دبیان صحبت می کنم - ما از توزیع های مبتنی بر RPM استفاده نمی کنیم).

در ساده ترین حالت، برای استفاده از پیکربندی عروسکی، کافی است عامل را در حالت بدون سرور راه اندازی کنید: به شرطی که کد عروسکی در گره کپی شود، راه اندازی شود. puppet apply <путь к манифесту>:

atikhonov@atikhonov ~/puppet-test $ cat helloworld.pp 
node default {
    notify { 'Hello world!': }
}
atikhonov@atikhonov ~/puppet-test $ puppet apply helloworld.pp 
Notice: Compiled catalog for atikhonov.localdomain in environment production in 0.01 seconds
Notice: Hello world!
Notice: /Stage[main]/Main/Node[default]/Notify[Hello world!]/message: defined 'message' as 'Hello world!'
Notice: Applied catalog in 0.01 seconds

البته بهتر است سرور را راه اندازی کنید و عوامل را روی گره ها در حالت شبح اجرا کنید - سپس هر نیم ساعت یک بار پیکربندی دانلود شده از سرور را اعمال می کنند.

می توانید مدل فشار کار را تقلید کنید - به گره مورد علاقه خود بروید و شروع کنید sudo puppet agent -t... کلید -t (--test) در واقع شامل چندین گزینه است که می توان آنها را به صورت جداگانه فعال کرد. این گزینه ها شامل موارد زیر است:

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

عامل دارای حالت عملیاتی بدون تغییر است - زمانی که مطمئن نیستید پیکربندی صحیح را نوشته اید و می خواهید بررسی کنید که عامل دقیقاً چه چیزی را در حین کار تغییر می دهد، می توانید از آن استفاده کنید. این حالت توسط پارامتر فعال می شود --noop در خط فرمان: sudo puppet agent -t --noop.

علاوه بر این، می توانید گزارش اشکال زدایی کار را فعال کنید - در آن، عروسک در مورد تمام اقداماتی که انجام می دهد می نویسد: در مورد منبعی که در حال حاضر در حال پردازش است، در مورد پارامترهای این منبع، در مورد برنامه هایی که راه اندازی می کند. البته این یک پارامتر است --debug.

سرور

من در این مقاله راه اندازی کامل Pappetserver و استقرار کد روی آن را در نظر نخواهم گرفت؛ فقط می گویم که خارج از جعبه یک نسخه کاملاً کاربردی از سرور وجود دارد که برای کار با تعداد کمی از سرور نیازی به پیکربندی اضافی ندارد. گره (مثلاً تا صد). تعداد بیشتری از گره ها نیاز به تنظیم دارند - به طور پیش فرض، سرور عروسکی بیش از چهار کارگر راه اندازی نمی کند، برای عملکرد بیشتر باید تعداد آنها را افزایش دهید و فراموش نکنید که محدودیت های حافظه را افزایش دهید، در غیر این صورت سرور اکثر اوقات زباله ها را جمع آوری می کند.

استقرار کد - اگر به سرعت و آسانی به آن نیاز دارید، سپس (در r10k)[https://github.com/puppetlabs/r10k]، برای نصب های کوچک باید کاملاً کافی باشد.

ضمیمه 2: دستورالعمل های کدگذاری

  1. تمام منطق را در کلاس ها و تعاریف قرار دهید.
  2. کلاس ها و تعاریف را در ماژول ها نگه دارید، نه در مانیفست هایی که گره ها را توصیف می کنند.
  3. از حقایق استفاده کنید
  4. اگرها را بر اساس نام میزبان نسازید.
  5. به راحتی می توانید پارامترهایی را برای کلاس ها و تعاریف اضافه کنید - این بهتر از منطق ضمنی پنهان در بدنه کلاس / تعریف است.

در مقاله بعدی توضیح خواهم داد که چرا این کار را توصیه می کنم.

نتیجه

اجازه دهید با مقدمه تمام کنیم. در مقاله بعدی درباره Hiera، ENC و PuppetDB به شما خواهم گفت.

فقط کاربران ثبت نام شده می توانند در نظرسنجی شرکت کنند. ورود، لطفا.

در واقع، مطالب بسیار بیشتری وجود دارد - من می توانم مقالاتی در مورد موضوعات زیر بنویسم، به آنچه علاقه مند به خواندن در مورد آن هستید رأی دهید:

  • ٪۱۰۰سازه‌های عروسکی پیشرفته - برخی چیزهای سطح بعدی: حلقه‌ها، نقشه‌برداری و سایر عبارات لامبدا، جمع‌آورنده‌های منابع، منابع صادر شده و ارتباطات بین میزبان از طریق Puppet، برچسب‌ها، ارائه‌دهندگان، انواع داده‌های انتزاعی.13
  • ٪۱۰۰«من ادمین مادرم هستم» یا اینکه چگونه ما در آویتو با چندین سرور پاپت نسخه‌های مختلف دوست شدیم، و اصولاً قسمت مربوط به مدیریت سرور پاپت.
  • ٪۱۰۰نحوه نوشتن کد عروسکی: ابزار دقیق، مستندسازی، تست، CI/CD.18

22 کاربر رای دادند. 9 کاربر رای ممتنع دادند.

منبع: www.habr.com