Pengenalan kepada Boneka

Boneka ialah sistem pengurusan konfigurasi. Ia digunakan untuk membawa hos ke keadaan yang dikehendaki dan mengekalkan keadaan ini.

Saya telah bekerja dengan Puppet selama lebih lima tahun sekarang. Teks ini pada asasnya ialah kompilasi isi penting yang diterjemahkan dan disusun semula daripada dokumentasi rasmi, yang akan membolehkan pemula memahami dengan cepat intipati Boneka.

Pengenalan kepada Boneka

Maklumat asas

Sistem pengendalian Puppet ialah pelayan-klien, walaupun ia juga menyokong operasi tanpa pelayan dengan fungsi terhad.

Model tarik operasi digunakan: secara lalai, sekali setiap setengah jam, pelanggan menghubungi pelayan untuk konfigurasi dan menggunakannya. Jika anda telah bekerja dengan Ansible, maka mereka menggunakan model tolak yang berbeza: pentadbir memulakan proses menggunakan konfigurasi, pelanggan sendiri tidak akan menggunakan apa-apa.

Semasa komunikasi rangkaian, penyulitan TLS dua hala digunakan: pelayan dan pelanggan mempunyai kunci peribadi mereka sendiri dan sijil yang sepadan. Biasanya pelayan mengeluarkan sijil untuk pelanggan, tetapi pada dasarnya adalah mungkin untuk menggunakan CA luaran.

Pengenalan kepada manifesto

Dalam istilah Boneka kepada pelayan boneka menyambung nod (nod). Konfigurasi untuk nod ditulis dalam manifesto dalam bahasa pengaturcaraan khas - DSL Boneka.

DSL Boneka ialah bahasa deklaratif. Ia menerangkan keadaan nod yang dikehendaki dalam bentuk pengisytiharan sumber individu, sebagai contoh:

  • Fail itu wujud dan ia mempunyai kandungan khusus.
  • Pakej dipasang.
  • Perkhidmatan telah bermula.

Sumber boleh saling berkaitan:

  • Terdapat kebergantungan, ia mempengaruhi susunan sumber digunakan.
    Sebagai contoh, "pasang pakej dahulu, kemudian edit fail konfigurasi, kemudian mulakan perkhidmatan."
  • Terdapat pemberitahuan - jika sumber telah berubah, ia menghantar pemberitahuan kepada sumber yang melanggannya.
    Contohnya, jika fail konfigurasi berubah, anda boleh memulakan semula perkhidmatan secara automatik.

Selain itu, DSL Boneka mempunyai fungsi dan pembolehubah, serta pernyataan dan pemilih bersyarat. Pelbagai mekanisme templat turut disokong - EPP dan ERB.

Boneka ditulis dalam Ruby, jadi banyak binaan dan istilah diambil dari sana. Ruby membolehkan anda mengembangkan Boneka - menambah logik kompleks, jenis sumber baharu, fungsi.

Semasa Puppet sedang berjalan, manifes untuk setiap nod tertentu pada pelayan disusun ke dalam direktori. Direktori ialah senarai sumber dan hubungannya selepas mengira nilai fungsi, pembolehubah dan pengembangan pernyataan bersyarat.

Sintaks dan gaya kod

Berikut ialah bahagian dokumentasi rasmi yang akan membantu anda memahami sintaks jika contoh yang diberikan tidak mencukupi:

Berikut ialah contoh rupa manifes:

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

Lekukan dan pemisah baris bukan bahagian yang diperlukan dalam manifes, tetapi ada yang disyorkan panduan gaya. Ringkasan:

  • Inden dua ruang, tab tidak digunakan.
  • Pendakap kerinting dipisahkan oleh ruang;
  • Koma selepas setiap parameter, termasuk yang terakhir. Setiap parameter berada pada baris yang berasingan. Pengecualian dibuat untuk kes tanpa parameter dan satu parameter: anda boleh menulis pada satu baris dan tanpa koma (iaitu. resource { 'title': } и resource { 'title': param => value }).
  • Anak panah pada parameter harus berada pada tahap yang sama.
  • Anak panah hubungan sumber ditulis di hadapan mereka.

Lokasi fail pada pappetserver

Untuk penjelasan lanjut, saya akan memperkenalkan konsep "direktori akar". Direktori akar ialah direktori yang mengandungi konfigurasi Boneka untuk nod tertentu.

Direktori akar berbeza-beza bergantung pada versi Boneka dan persekitaran yang digunakan. Persekitaran ialah set konfigurasi bebas yang disimpan dalam direktori berasingan. Biasanya digunakan dalam kombinasi dengan git, di mana persekitaran dicipta daripada cawangan git. Sehubungan itu, setiap nod terletak dalam satu persekitaran atau yang lain. Ini boleh dikonfigurasikan pada nod itu sendiri, atau dalam ENC, yang akan saya bincangkan dalam artikel seterusnya.

  • Dalam versi ketiga ("Boneka lama") direktori asas ialah /etc/puppet. Penggunaan persekitaran adalah pilihan - contohnya, kami tidak menggunakannya dengan Boneka lama. Jika persekitaran digunakan, ia biasanya disimpan dalam /etc/puppet/environments, direktori akar akan menjadi direktori persekitaran. Jika persekitaran tidak digunakan, direktori akar akan menjadi direktori asas.
  • Bermula dari versi keempat ("Boneka baharu"), penggunaan persekitaran menjadi wajib dan direktori asas telah dialihkan ke /etc/puppetlabs/code. Sehubungan itu, persekitaran disimpan dalam /etc/puppetlabs/code/environments, direktori akar ialah direktori persekitaran.

Mesti ada subdirektori dalam direktori akar manifests, yang mengandungi satu atau lebih manifes yang menerangkan nod. Di samping itu, perlu ada subdirektori modules, yang mengandungi modul. Saya akan memberitahu anda apa modul itu sedikit kemudian. Selain itu, Boneka lama juga mungkin mempunyai subdirektori files, yang mengandungi pelbagai fail yang kami salin ke nod. Dalam Boneka baharu, semua fail diletakkan dalam modul.

Fail manifes mempunyai sambungan .pp.

Beberapa contoh pertempuran

Penerangan tentang nod dan sumber di atasnya

Pada nod server1.testdomain fail mesti dibuat /etc/issue dengan kandungan Debian GNU/Linux n l. Fail mesti dimiliki oleh pengguna dan kumpulan root, hak akses mestilah 644.

Kami menulis manifesto:

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 в начале будет воспринято как записанное в восьмеричной системе, и всё пойдёт не так, как задумано
    }
}

Hubungan antara sumber pada nod

Pada nod server2.testdomain nginx mesti berjalan, bekerja dengan konfigurasi yang disediakan sebelum ini.

Mari kita menguraikan masalah:

  • Pakej perlu dipasang nginx.
  • Fail konfigurasi perlu disalin daripada pelayan.
  • Perkhidmatan perlu dijalankan nginx.
  • Jika konfigurasi dikemas kini, perkhidmatan mesti dimulakan semula.

Kami menulis manifesto:

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 получает уведомление,
  # соответствующий сервис перезапускается.
}

Untuk ini berfungsi, anda memerlukan lebih kurang lokasi fail berikut pada pelayan boneka:

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

Jenis Sumber

Senarai lengkap jenis sumber yang disokong boleh didapati di sini dalam dokumentasi, di sini saya akan menerangkan lima jenis asas, yang dalam amalan saya cukup untuk menyelesaikan kebanyakan masalah.

fail

Mengurus fail, direktori, symlink, kandungannya dan hak akses.

Parameter:

  • nama sumber — laluan ke fail (pilihan)
  • jalan — laluan ke fail (jika ia tidak dinyatakan dalam nama)
  • memastikan - jenis fail:
    • absent - memadam fail
    • present — mesti ada apa-apa jenis fail (jika tiada fail, fail biasa akan dibuat)
    • file - fail biasa
    • directory - direktori
    • link - symlink
  • kandungan — kandungan fail (hanya sesuai untuk fail biasa, tidak boleh digunakan bersama dengan sumber atau sasaran)
  • sumber — pautan ke laluan dari mana anda ingin menyalin kandungan fail (tidak boleh digunakan bersama-sama dengan kandungan atau sasaran). Boleh ditentukan sebagai sama ada URI dengan skema puppet: (kemudian fail dari pelayan boneka akan digunakan), dan dengan skema http: (Saya harap jelas apa yang akan berlaku dalam kes ini), dan juga dengan gambar rajah file: atau sebagai laluan mutlak tanpa skema (maka fail dari FS tempatan pada nod akan digunakan)
  • sasaran — di mana symlink harus menunjuk (tidak boleh digunakan bersama dengan kandungan atau sumber)
  • pemilik — pengguna yang sepatutnya memiliki fail
  • kumpulan — kumpulan yang sepatutnya dimiliki oleh fail itu
  • mod - kebenaran fail (sebagai rentetan)
  • berulang - membolehkan pemprosesan direktori rekursif
  • membersihkan - membolehkan pemadaman fail yang tidak diterangkan dalam Puppet
  • kekuatan - membolehkan pemadaman direktori yang tidak diterangkan dalam Puppet

pakej

Memasang dan mengalih keluar pakej. Mampu mengendalikan pemberitahuan - memasang semula pakej jika parameter ditentukan reinstall_on_refresh.

Parameter:

  • nama sumber - nama pakej (pilihan)
  • nama — nama pakej (jika tidak dinyatakan dalam nama)
  • pembekal — pengurus pakej untuk digunakan
  • memastikan — keadaan pakej yang dikehendaki:
    • present, installed - mana-mana versi dipasang
    • latest - versi terkini dipasang
    • absent - dipadam (apt-get remove)
    • purged — dipadam bersama fail konfigurasi (apt-get purge)
    • held - versi pakej dikunci (apt-mark hold)
    • любая другая строка — versi yang ditentukan dipasang
  • reinstall_on_refresh - sekiranya true, kemudian selepas menerima pemberitahuan pakej akan dipasang semula. Berguna untuk pengedaran berasaskan sumber, di mana pakej pembinaan semula mungkin diperlukan apabila menukar parameter binaan. Lalai false.

perkhidmatan

Menguruskan perkhidmatan. Dapat memproses pemberitahuan - memulakan semula perkhidmatan.

Parameter:

  • nama sumber — perkhidmatan untuk diuruskan (pilihan)
  • nama — perkhidmatan yang perlu diuruskan (jika tidak dinyatakan dalam nama)
  • memastikan — keadaan perkhidmatan yang dikehendaki:
    • running - dilancarkan
    • stopped - berhenti
  • membolehkan — mengawal keupayaan untuk memulakan perkhidmatan:
    • true — autorun didayakan (systemctl enable)
    • mask - menyamar (systemctl mask)
    • false — autorun dilumpuhkan (systemctl disable)
  • restart - arahan untuk memulakan semula perkhidmatan
  • terkini — perintah untuk menyemak status perkhidmatan
  • telah memulakan semula — nyatakan sama ada skrip init perkhidmatan menyokong dimulakan semula. Jika false dan parameter ditentukan restart — nilai parameter ini digunakan. Jika false dan parameter restart tidak ditentukan - perkhidmatan dihentikan dan mula dimulakan semula (tetapi systemd menggunakan arahan systemctl restart).
  • hasstatus — nyatakan sama ada skrip init perkhidmatan menyokong arahan status. Jika false, maka nilai parameter digunakan terkini. Lalai true.

exec

Menjalankan arahan luaran. Jika anda tidak menyatakan parameter mewujudkan, hanya jika, melainkan jika atau segar semula, arahan akan dijalankan setiap kali Puppet dijalankan. Mampu memproses pemberitahuan - menjalankan arahan.

Parameter:

  • nama sumber — perintah untuk dilaksanakan (pilihan)
  • arahan — arahan yang akan dilaksanakan (jika ia tidak dinyatakan dalam nama)
  • jalan — laluan untuk mencari fail boleh laku
  • hanya jika — jika arahan yang dinyatakan dalam parameter ini dilengkapkan dengan kod pulangan sifar, arahan utama akan dilaksanakan
  • melainkan jika — jika arahan yang dinyatakan dalam parameter ini dilengkapkan dengan kod pulangan bukan sifar, arahan utama akan dilaksanakan
  • mewujudkan — jika fail yang dinyatakan dalam parameter ini tidak wujud, arahan utama akan dilaksanakan
  • segar semula - sekiranya true, maka arahan hanya akan dijalankan apabila eksekutif ini menerima pemberitahuan daripada sumber lain
  • cwd — direktori dari mana untuk menjalankan arahan
  • pengguna — pengguna dari siapa untuk menjalankan arahan
  • pembekal - cara menjalankan arahan:
    • posix — proses kanak-kanak hanya dibuat, pastikan anda nyatakan jalan
    • shell - arahan dilancarkan dalam shell /bin/sh, mungkin tidak dinyatakan jalan, anda boleh menggunakan globbing, paip dan ciri cangkerang lain. Biasanya dikesan secara automatik jika terdapat sebarang aksara khas (|, ;, &&, || dan lain-lain).

cron

Mengawal cronjob.

Parameter:

  • nama sumber - hanya beberapa jenis pengecam
  • memastikan - keadaan crownjob:
    • present - cipta jika tidak wujud
    • absent - padam jika wujud
  • arahan - arahan apa yang hendak dijalankan
  • persekitaran — di persekitaran mana untuk menjalankan arahan (senarai pembolehubah persekitaran dan nilainya melalui =)
  • pengguna — daripada pengguna mana untuk menjalankan arahan
  • minit, jam, hari kerja, bulan, hari bulan — bila hendak menjalankan cron. Jika mana-mana atribut ini tidak dinyatakan, nilainya dalam crontab adalah *.

Dalam Puppet 6.0 cron seolah-olah dikeluarkan dari kotak dalam puppetserver, jadi tiada dokumentasi di tapak umum. Tetapi dia berada di dalam kotak dalam ejen boneka, jadi tidak perlu memasangnya secara berasingan. Anda boleh melihat dokumentasi untuknya dalam dokumentasi untuk versi kelima PuppetAtau pada GitHub.

Mengenai sumber secara umum

Keperluan untuk keunikan sumber

Kesilapan yang biasa kita hadapi ialah Perisytiharan pendua. Ralat ini berlaku apabila dua atau lebih sumber daripada jenis yang sama dengan nama yang sama muncul dalam direktori.

Oleh itu, saya akan menulis sekali lagi: manifes untuk nod yang sama tidak boleh mengandungi sumber daripada jenis yang sama dengan tajuk yang sama!

Kadangkala terdapat keperluan untuk memasang pakej dengan nama yang sama, tetapi dengan pengurus pakej yang berbeza. Dalam kes ini, anda perlu menggunakan parameter nameuntuk mengelakkan ralat:

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

Jenis sumber lain mempunyai pilihan yang sama untuk membantu mengelakkan pertindihan − name у perkhidmatan, command у exec, dan sebagainya.

Metaparameter

Setiap jenis sumber mempunyai beberapa parameter khas, tanpa mengira sifatnya.

Senarai penuh parameter meta dalam dokumentasi Boneka.

Senarai pendek:

  • memerlukan — parameter ini menunjukkan sumber yang bergantung kepada sumber ini.
  • sebelum - Parameter ini menentukan sumber mana yang bergantung pada sumber ini.
  • melanggan — parameter ini menentukan dari mana sumber sumber ini menerima pemberitahuan.
  • memberitahu — Parameter ini menentukan sumber yang menerima pemberitahuan daripada sumber ini.

Semua metaparameter yang disenaraikan menerima sama ada pautan sumber tunggal atau tatasusunan pautan dalam kurungan segi empat sama.

Pautan kepada sumber

Pautan sumber hanyalah sebutan tentang sumber tersebut. Ia digunakan terutamanya untuk menunjukkan kebergantungan. Merujuk sumber yang tidak wujud akan menyebabkan ralat penyusunan.

Sintaks pautan adalah seperti berikut: jenis sumber dengan huruf besar (jika nama jenis mengandungi dua titik dua, maka setiap bahagian nama antara titik bertindih huruf besar), kemudian nama sumber dalam kurungan persegi (kes nama tidak berubah!). Seharusnya tiada ruang; kurungan segi empat sama ditulis selepas nama jenis.

Contoh:

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

Ketergantungan dan pemberitahuan

Dokumentasi di sini.

Seperti yang dinyatakan sebelum ini, kebergantungan mudah antara sumber adalah transitif. Dengan cara ini, berhati-hati apabila menambah kebergantungan - anda boleh membuat kebergantungan kitaran, yang akan menyebabkan ralat kompilasi.

Tidak seperti kebergantungan, pemberitahuan tidak transitif. Peraturan berikut digunakan untuk pemberitahuan:

  • Jika sumber menerima pemberitahuan, ia dikemas kini. Tindakan kemas kini bergantung pada jenis sumber − exec menjalankan perintah, perkhidmatan memulakan semula perkhidmatan, pakej memasang semula pakej. Jika sumber tidak mempunyai tindakan kemas kini yang ditentukan, maka tiada apa yang berlaku.
  • Semasa satu tayangan Puppet, sumber dikemas kini tidak lebih daripada sekali. Ini mungkin kerana pemberitahuan termasuk kebergantungan dan graf kebergantungan tidak mengandungi kitaran.
  • Jika Boneka mengubah keadaan sumber, sumber tersebut menghantar pemberitahuan kepada semua sumber yang melanggannya.
  • Jika sumber dikemas kini, ia menghantar pemberitahuan kepada semua sumber yang melanggannya.

Mengendalikan parameter yang tidak ditentukan

Sebagai peraturan, jika beberapa parameter sumber tidak mempunyai nilai lalai dan parameter ini tidak dinyatakan dalam manifes, maka Puppet tidak akan mengubah sifat ini untuk sumber yang sepadan pada nod. Sebagai contoh, jika sumber jenis fail parameter tidak dinyatakan owner, maka Puppet tidak akan menukar pemilik fail yang sepadan.

Pengenalan kepada kelas, pembolehubah dan definisi

Katakan kita mempunyai beberapa nod yang mempunyai bahagian konfigurasi yang sama, tetapi terdapat juga perbezaan - jika tidak, kita boleh menerangkan semuanya dalam satu blok node {}. Sudah tentu, anda hanya boleh menyalin bahagian konfigurasi yang sama, tetapi secara umum ini adalah penyelesaian yang buruk - konfigurasi berkembang, dan jika anda menukar bahagian umum konfigurasi, anda perlu mengedit perkara yang sama di banyak tempat. Pada masa yang sama, mudah untuk membuat kesilapan, dan secara umum, prinsip KERING (jangan ulangi diri sendiri) dicipta atas sebab tertentu.

Untuk menyelesaikan masalah ini terdapat reka bentuk seperti kelas.

Kelas

Kelas ialah blok bernama kod poppet. Kelas diperlukan untuk menggunakan semula kod.

Mula-mula kelas perlu diterangkan. Perihalan itu sendiri tidak menambah sebarang sumber di mana-mana sahaja. Kelas diterangkan dalam manifes:

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

Selepas ini kelas boleh digunakan:

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

Contoh daripada tugas sebelumnya - mari kita alihkan pemasangan dan konfigurasi nginx ke dalam kelas:

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
}

Pembolehubah

Kelas dari contoh sebelumnya tidak fleksibel sama sekali kerana ia sentiasa membawa konfigurasi nginx yang sama. Mari kita buat laluan ke pembolehubah konfigurasi, kemudian kelas ini boleh digunakan untuk memasang nginx dengan sebarang konfigurasi.

Ia boleh dilakukan menggunakan pembolehubah.

Perhatian: pembolehubah dalam Boneka tidak boleh diubah!

Di samping itu, pembolehubah hanya boleh diakses selepas ia diisytiharkan, jika tidak, nilai pembolehubah akan menjadi undef.

Contoh bekerja dengan pembolehubah:

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

Boneka mempunyai ruang nama, dan pembolehubah, sewajarnya, mempunyai kawasan penglihatan: Pembolehubah dengan nama yang sama boleh ditakrifkan dalam ruang nama yang berbeza. Apabila menyelesaikan nilai pembolehubah, pembolehubah dicari dalam ruang nama semasa, kemudian dalam ruang nama yang dilampirkan, dan seterusnya.

Contoh ruang nama:

  • global - pembolehubah di luar kelas atau penerangan nod pergi ke sana;
  • ruang nama nod dalam perihalan nod;
  • ruang nama kelas dalam penerangan kelas.

Untuk mengelakkan kekaburan semasa mengakses pembolehubah, anda boleh menentukan ruang nama dalam nama pembolehubah:

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

Mari kita bersetuju bahawa laluan ke konfigurasi nginx terletak pada pembolehubah $nginx_conf_source. Kemudian kelas akan kelihatan seperti ini:

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
}

Walau bagaimanapun, contoh yang diberikan adalah buruk kerana terdapat beberapa "pengetahuan rahsia" yang di suatu tempat di dalam kelas pembolehubah dengan nama ini dan sedemikian digunakan. Adalah lebih tepat untuk menjadikan pengetahuan ini umum - kelas boleh mempunyai parameter.

Parameter kelas ialah pembolehubah dalam ruang nama kelas, ia ditentukan dalam pengepala kelas dan boleh digunakan seperti pembolehubah biasa dalam badan kelas. Nilai parameter ditentukan apabila menggunakan kelas dalam manifes.

Parameter boleh ditetapkan kepada nilai lalai. Jika parameter tidak mempunyai nilai lalai dan nilai tidak ditetapkan apabila digunakan, ia akan menyebabkan ralat penyusunan.

Mari parameterkan kelas daripada contoh di atas dan tambahkan dua parameter: yang pertama, diperlukan, ialah laluan ke konfigurasi, dan yang kedua, pilihan, ialah nama pakej dengan nginx (dalam Debian, sebagai contoh, terdapat pakej 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',   # задаём параметры класса точно так же, как параметры для других ресурсов
  }
}

Dalam Puppet, pembolehubah ditaip. makan banyak jenis data. Jenis data biasanya digunakan untuk mengesahkan nilai parameter yang dihantar ke kelas dan definisi. Jika parameter yang diluluskan tidak sepadan dengan jenis yang ditentukan, ralat kompilasi akan berlaku.

Jenis ditulis sejurus sebelum nama parameter:

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

Kelas: sertakan nama kelas vs kelas{'classname':}

Setiap kelas adalah jenis sumber kelas. Seperti mana-mana jenis sumber lain, tidak boleh ada dua kejadian kelas yang sama pada nod yang sama.

Jika anda cuba menambah kelas pada nod yang sama dua kali menggunakan class { 'classname':} (tiada perbezaan, dengan parameter yang berbeza atau sama), akan terdapat ralat penyusunan. Tetapi jika anda menggunakan kelas dalam gaya sumber, anda boleh dengan serta-merta menetapkan semua parameternya dalam manifes.

Namun, jika anda menggunakan include, maka kelas boleh ditambah seberapa banyak kali yang dikehendaki. Hakikatnya ialah include ialah fungsi idempoten yang menyemak sama ada kelas telah ditambahkan pada direktori. Jika kelas itu tiada dalam direktori, ia menambahnya, dan jika ia sudah wujud, ia tidak melakukan apa-apa. Tetapi dalam kes menggunakan include Anda tidak boleh menetapkan parameter kelas semasa pengisytiharan kelas - semua parameter yang diperlukan mesti ditetapkan dalam sumber data luaran - Hiera atau ENC. Kami akan bercakap tentang mereka dalam artikel seterusnya.

Mentakrifkan

Seperti yang dikatakan dalam blok sebelumnya, kelas yang sama tidak boleh hadir pada nod lebih daripada sekali. Walau bagaimanapun, dalam beberapa kes anda perlu boleh menggunakan blok kod yang sama dengan parameter berbeza pada nod yang sama. Dalam erti kata lain, terdapat keperluan untuk jenis sumbernya sendiri.

Sebagai contoh, untuk memasang modul PHP, kami melakukan perkara berikut dalam Avito:

  1. Pasang pakej dengan modul ini.
  2. Mari buat fail konfigurasi untuk modul ini.
  3. Kami mencipta pautan sym ke konfigurasi untuk php-fpm.
  4. Kami mencipta pautan sym ke konfigurasi untuk php cli.

Dalam kes sedemikian, reka bentuk seperti tentukan (takrif, jenis yang ditentukan, jenis sumber yang ditentukan). Define adalah serupa dengan kelas, tetapi terdapat perbezaan: pertama, setiap Define ialah jenis sumber, bukan sumber; kedua, setiap definisi mempunyai parameter tersirat $title, di mana nama sumber pergi apabila ia diisytiharkan. Sama seperti dalam kes kelas, definisi mesti diterangkan terlebih dahulu, selepas itu ia boleh digunakan.

Contoh ringkas dengan modul untuk 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' }
}

Cara paling mudah untuk menangkap ralat pengisytiharan Duplikat adalah dalam Tentukan. Ini berlaku jika definisi mempunyai sumber dengan nama tetap, dan terdapat dua atau lebih contoh definisi ini pada beberapa nod.

Sangat mudah untuk melindungi diri anda daripada ini: semua sumber dalam definisi mesti mempunyai nama bergantung pada $title. Alternatif ialah penambahan sumber idempoten dalam kes yang paling mudah, ia cukup untuk memindahkan sumber yang biasa kepada semua contoh definisi ke dalam kelas yang berasingan dan memasukkan kelas ini dalam definisi - fungsi; include idempoten.

Terdapat cara lain untuk mencapai idempotensi apabila menambah sumber, iaitu menggunakan fungsi defined и ensure_resources, tetapi saya akan memberitahu anda mengenainya dalam episod seterusnya.

Ketergantungan dan pemberitahuan untuk kelas dan definisi

Kelas dan takrifan menambah peraturan berikut untuk mengendalikan kebergantungan dan pemberitahuan:

  • kebergantungan pada kelas/define menambah kebergantungan pada semua sumber kelas/define;
  • kelas/takrifkan kebergantungan menambah kebergantungan kepada semua kelas/takrifkan sumber;
  • pemberitahuan kelas/takrifkan memberitahu semua sumber kelas/takrifkan;
  • langganan kelas/takrifkan melanggan semua sumber kelas/takrifkan.

Pernyataan dan pemilih bersyarat

Dokumentasi di sini.

if

Ia mudah di sini:

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

melainkan jika

melainkan jika adalah sebaliknya: blok kod akan dilaksanakan jika ungkapan itu palsu.

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

kes

Tidak ada yang rumit di sini juga. Anda boleh menggunakan nilai biasa (rentetan, nombor, dll.), ungkapan biasa, dan jenis data sebagai nilai.

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

Pemilih

Pemilih ialah binaan bahasa yang serupa dengan case, tetapi bukannya melaksanakan blok kod, ia mengembalikan nilai.

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

Modul

Apabila konfigurasi kecil, ia boleh disimpan dengan mudah dalam satu manifes. Tetapi lebih banyak konfigurasi yang kami huraikan, lebih banyak kelas dan nod terdapat dalam manifes, ia berkembang, dan ia menjadi menyusahkan untuk digunakan.

Di samping itu, terdapat masalah penggunaan semula kod - apabila semua kod berada dalam satu manifes, sukar untuk berkongsi kod ini dengan orang lain. Untuk menyelesaikan dua masalah ini, Puppet mempunyai entiti yang dipanggil modul.

Modul - ini adalah set kelas, definisi dan entiti Boneka lain yang diletakkan dalam direktori berasingan. Dalam erti kata lain, modul ialah bahagian logik Boneka yang bebas. Sebagai contoh, mungkin terdapat modul untuk bekerja dengan nginx, dan ia akan mengandungi apa dan hanya apa yang diperlukan untuk berfungsi dengan nginx, atau mungkin terdapat modul untuk bekerja dengan PHP, dan sebagainya.

Modul adalah versi, dan kebergantungan modul antara satu sama lain juga disokong. Terdapat repositori modul terbuka - Tempa Boneka.

Pada pelayan boneka, modul terletak dalam subdirektori modul direktori akar. Di dalam setiap modul terdapat skema direktori standard - manifes, fail, templat, lib, dan sebagainya.

Struktur fail dalam modul

Akar modul mungkin mengandungi direktori berikut dengan nama deskriptif:

  • manifests - ia mengandungi manifesto
  • files - ia mengandungi fail
  • templates - ia mengandungi templat
  • lib — ia mengandungi kod Ruby

Ini bukan senarai lengkap direktori dan fail, tetapi cukup untuk artikel ini buat masa ini.

Nama sumber dan nama fail dalam modul

Dokumentasi di sini.

Sumber (kelas, definisi) dalam modul tidak boleh dinamakan apa sahaja yang anda suka. Di samping itu, terdapat hubungan langsung antara nama sumber dan nama fail di mana Puppet akan mencari penerangan tentang sumber tersebut. Jika anda melanggar peraturan penamaan, maka Puppet tidak akan menemui penerangan sumber, dan anda akan mendapat ralat kompilasi.

Peraturannya mudah:

  • Semua sumber dalam modul mesti berada dalam ruang nama modul. Jika modul dipanggil foo, maka semua sumber di dalamnya hendaklah dinamakan foo::<anything>, atau hanya foo.
  • Sumber dengan nama modul mesti ada dalam fail init.pp.
  • Untuk sumber lain, skema penamaan fail adalah seperti berikut:
    • awalan dengan nama modul dibuang
    • semua titik dua bertindih, jika ada, digantikan dengan garis miring
    • sambungan ditambah .pp

Saya akan menunjukkan dengan contoh. Katakan saya sedang menulis modul nginx. Ia mengandungi sumber berikut:

  • kelas nginx diterangkan dalam manifes init.pp;
  • kelas nginx::service diterangkan dalam manifes service.pp;
  • tentukan nginx::server diterangkan dalam manifes server.pp;
  • tentukan nginx::server::location diterangkan dalam manifes server/location.pp.

Templat

Pasti anda sendiri tahu apa itu templat saya tidak akan menerangkannya secara terperinci di sini. Tetapi saya akan meninggalkannya untuk berjaga-jaga pautan ke Wikipedia.

Cara menggunakan templat: Maksud templat boleh dikembangkan menggunakan fungsi template, yang diluluskan laluan ke templat. Untuk sumber seperti fail digunakan bersama-sama dengan parameter content. Sebagai contoh, seperti ini:

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

Lihat laluan <modulename>/<filename> menyiratkan fail <rootdir>/modules/<modulename>/templates/<filename>.

Di samping itu, terdapat fungsi inline_template — ia menerima teks templat sebagai input, bukan nama fail.

Dalam templat, anda boleh menggunakan semua pembolehubah Boneka dalam skop semasa.

Boneka menyokong templat dalam format ERB dan EPP:

Secara ringkas tentang ERB

Struktur kawalan:

  • <%= ВЫРАЖЕНИЕ %> — masukkan nilai ungkapan
  • <% ВЫРАЖЕНИЕ %> — mengira nilai ungkapan (tanpa memasukkannya). Pernyataan bersyarat (jika) dan gelung (setiap satu) biasanya pergi ke sini.
  • <%# КОММЕНТАРИЙ %>

Ungkapan dalam ERB ditulis dalam Ruby (ERB sebenarnya Embedded Ruby).

Untuk mengakses pembolehubah daripada manifes, anda perlu menambah @ kepada nama pembolehubah. Untuk mengalih keluar pemisah baris yang muncul selepas binaan kawalan, anda perlu menggunakan teg penutup -%>.

Contoh penggunaan templat

Katakan saya sedang menulis modul untuk mengawal ZooKeeper. Kelas yang bertanggungjawab untuk mencipta konfigurasi kelihatan seperti ini:

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'),
  }
}

Dan templat yang sepadan zoo.cfg.erb - Jadi:

<% 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 -%>

Fakta dan Pembolehubah Terbina dalam

Selalunya bahagian khusus konfigurasi bergantung pada apa yang sedang berlaku pada nod. Sebagai contoh, bergantung pada keluaran Debian, anda perlu memasang satu atau satu lagi versi pakej. Anda boleh memantau semua ini secara manual, menulis semula manifes jika nod berubah. Tetapi ini bukan pendekatan yang serius;

Untuk mendapatkan maklumat tentang nod, Puppet mempunyai mekanisme yang dipanggil fakta. Fakta - ini ialah maklumat tentang nod, tersedia dalam manifes dalam bentuk pembolehubah biasa dalam ruang nama global. Contohnya, nama hos, versi sistem pengendalian, seni bina pemproses, senarai pengguna, senarai antara muka rangkaian dan alamat mereka, dan banyak lagi. Fakta tersedia dalam manifes dan templat sebagai pembolehubah biasa.

Contoh bekerja dengan fakta:

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

Secara formal, fakta mempunyai nama (rentetan) dan nilai (pelbagai jenis tersedia: rentetan, tatasusunan, kamus). makan set fakta terbina dalam. Anda juga boleh menulis sendiri. Pengumpul fakta diterangkan seperti fungsi dalam Ruby, atau bagaimana fail boleh laku. Fakta juga boleh dikemukakan dalam bentuk fail teks dengan data pada nod.

Semasa operasi, ejen boneka mula-mula menyalin semua pengumpul fakta yang tersedia dari pelayan pap ke nod, selepas itu ia melancarkannya dan menghantar fakta yang dikumpul ke pelayan; Selepas ini, pelayan mula menyusun katalog.

Fakta dalam bentuk fail boleh laku

Fakta sedemikian diletakkan dalam modul dalam direktori facts.d. Sudah tentu, fail mesti boleh dilaksanakan. Apabila dijalankan, mereka mesti mengeluarkan maklumat kepada output standard sama ada dalam format YAML atau key=value.

Jangan lupa bahawa fakta digunakan untuk semua nod yang dikawal oleh pelayan poppet yang modul anda digunakan. Oleh itu, dalam skrip, berhati-hati untuk menyemak bahawa sistem mempunyai semua program dan fail yang diperlukan untuk fakta anda berfungsi.

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

Fakta Ruby

Fakta sedemikian diletakkan dalam modul dalam direktori 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

Fakta teks

Fakta sedemikian diletakkan pada nod dalam direktori /etc/facter/facts.d dalam Boneka lama atau /etc/puppetlabs/facts.d dalam Boneka baharu.

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

Mendapat Fakta

Terdapat dua cara untuk mendekati fakta:

  • melalui kamus $facts: $facts['fqdn'];
  • menggunakan nama fakta sebagai nama pembolehubah: $fqdn.

Lebih baik menggunakan kamus $facts, atau lebih baik lagi, nyatakan ruang nama global ($::facts).

Berikut ialah bahagian dokumentasi yang berkaitan.

Pembolehubah Terbina dalam

Selain fakta, ada juga beberapa pembolehubah, tersedia dalam ruang nama global.

  • fakta yang dipercayai — pembolehubah yang diambil daripada sijil pelanggan (memandangkan sijil biasanya dikeluarkan pada pelayan poppet, ejen tidak boleh mengambil dan menukar sijilnya sahaja, jadi pembolehubah adalah “dipercayai”): nama sijil, nama hos dan domain, sambungan daripada sijil.
  • fakta pelayan —pembolehubah yang berkaitan dengan maklumat tentang pelayan—versi, nama, alamat IP pelayan, persekitaran.
  • fakta ejen — pembolehubah ditambah terus oleh ejen boneka, dan bukan mengikut faktor — nama sijil, versi ejen, versi boneka.
  • pembolehubah induk - Pembolehubah Pappetmaster (sic!). Ia lebih kurang sama seperti dalam fakta pelayan, serta nilai parameter konfigurasi tersedia.
  • pembolehubah penyusun — pembolehubah pengkompil yang berbeza dalam setiap skop: nama modul semasa dan nama modul di mana objek semasa diakses. Ia boleh digunakan, sebagai contoh, untuk menyemak bahawa kelas peribadi anda tidak digunakan secara langsung daripada modul lain.

Tambahan 1: bagaimana untuk menjalankan dan nyahpepijat semua ini?

Artikel itu mengandungi banyak contoh kod boneka, tetapi tidak memberitahu kami sama sekali cara menjalankan kod ini. Nah, saya sedang membetulkan diri saya.

Ejen sudah cukup untuk menjalankan Puppet, tetapi untuk kebanyakan kes anda juga memerlukan pelayan.

Agen

Sekurang-kurangnya sejak versi 5, pakej ejen boneka daripada repositori rasmi Puppetlabs mengandungi semua kebergantungan (delima dan permata yang sepadan), jadi tiada masalah pemasangan (saya bercakap tentang pengedaran berasaskan Debian - kami tidak menggunakan pengedaran berasaskan RPM).

Dalam kes paling mudah, untuk menggunakan konfigurasi boneka, cukup untuk melancarkan ejen dalam mod tanpa pelayan: dengan syarat kod boneka disalin ke nod, lancarkan 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

Sudah tentu, lebih baik untuk menyediakan pelayan dan menjalankan ejen pada nod dalam mod daemon - kemudian sekali setiap setengah jam mereka akan menggunakan konfigurasi yang dimuat turun dari pelayan.

Anda boleh meniru model kerja push - pergi ke nod yang anda minati dan mulakan sudo puppet agent -t. kunci -t (--test) sebenarnya termasuk beberapa pilihan yang boleh didayakan secara individu. Pilihan ini termasuk yang berikut:

  • jangan jalankan dalam mod daemon (secara lalai ejen bermula dalam mod daemon);
  • tutup selepas menggunakan katalog (secara lalai, ejen akan terus bekerja dan menggunakan konfigurasi sekali setiap setengah jam);
  • tulis log kerja terperinci;
  • tunjukkan perubahan dalam fail.

Ejen mempunyai mod pengendalian tanpa perubahan - anda boleh menggunakannya apabila anda tidak pasti bahawa anda telah menulis konfigurasi yang betul dan ingin menyemak apa sebenarnya ejen akan berubah semasa operasi. Mod ini didayakan oleh parameter --noop pada baris arahan: sudo puppet agent -t --noop.

Di samping itu, anda boleh mendayakan log penyahpepijatan kerja - di dalamnya, boneka menulis tentang semua tindakan yang dilakukannya: tentang sumber yang sedang diproses, tentang parameter sumber ini, tentang program yang dilancarkannya. Sudah tentu ini adalah parameter --debug.

pelayan

Saya tidak akan mempertimbangkan persediaan penuh pappetserver dan menggunakan kod padanya dalam artikel ini saya hanya akan mengatakan bahawa di luar kotak terdapat versi pelayan yang berfungsi sepenuhnya yang tidak memerlukan konfigurasi tambahan untuk berfungsi dengan sebilangan kecil pelayan; nod (katakan, sehingga seratus). Bilangan nod yang lebih besar akan memerlukan penalaan - secara lalai, pelayan boneka melancarkan tidak lebih daripada empat pekerja, untuk prestasi yang lebih baik anda perlu meningkatkan bilangan mereka dan jangan lupa untuk meningkatkan had memori, jika tidak pelayan akan mengumpul sampah pada kebanyakan masa.

Arahan kod - jika anda memerlukannya dengan cepat dan mudah, kemudian lihat (pada r10k)[https://github.com/puppetlabs/r10k], untuk pemasangan kecil ia sepatutnya cukup.

Tambahan 2: Garis Panduan Pengekodan

  1. Letakkan semua logik dalam kelas dan definisi.
  2. Simpan kelas dan definisi dalam modul, bukan dalam manifes yang menerangkan nod.
  3. Gunakan fakta.
  4. Jangan buat if berdasarkan nama hos.
  5. Jangan ragu untuk menambah parameter untuk kelas dan definisi - ini lebih baik daripada logik tersirat yang tersembunyi dalam badan kelas/takrifkan.

Saya akan menerangkan sebab saya mengesyorkan melakukan ini dalam artikel seterusnya.

Kesimpulan

Mari kita selesaikan dengan pengenalan. Dalam artikel seterusnya saya akan memberitahu anda tentang Hiera, ENC dan PuppetDB.

Hanya pengguna berdaftar boleh mengambil bahagian dalam tinjauan. Log masuk, Sama-sama.

Malah, terdapat lebih banyak bahan - Saya boleh menulis artikel mengenai topik berikut, mengundi perkara yang anda berminat untuk membaca tentang:

  • 59,1% Binaan boneka lanjutan - beberapa najis peringkat seterusnya: gelung, pemetaan dan ungkapan lambda lain, pengumpul sumber, sumber yang dieksport dan komunikasi antara hos melalui Boneka, teg, pembekal, jenis data abstrak.13
  • 31,8% “Saya pentadbir ibu saya” atau cara kami dalam Avito berkawan dengan beberapa pelayan poppet versi berbeza, dan, pada dasarnya, bahagian tentang mentadbir pelayan poppet.7
  • 81,8% Cara kami menulis kod boneka: instrumentasi, dokumentasi, ujian, CI/CD.18

22 pengguna telah mengundi. 9 pengguna berpantang.

Sumber: www.habr.com