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.
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
- 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
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 failpresent
— mesti ada apa-apa jenis fail (jika tiada fail, fail biasa akan dibuat)file
- fail biasadirectory
- direktorilink
- 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 skemahttp:
(Saya harap jelas apa yang akan berlaku dalam kes ini), dan juga dengan gambar rajahfile:
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 dipasanglatest
- versi terkini dipasangabsent
- 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. Lalaifalse
.
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
- dilancarkanstopped
- 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. Jikafalse
dan parameter restart tidak ditentukan - perkhidmatan dihentikan dan mula dimulakan semula (tetapi systemd menggunakan arahansystemctl restart
). - hasstatus — nyatakan sama ada skrip init perkhidmatan menyokong arahan
status
. Jikafalse
, maka nilai parameter digunakan terkini. Lalaitrue
.
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 wujudabsent
- 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
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 name
untuk 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
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
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
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
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
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:
- Pasang pakej dengan modul ini.
- Mari buat fail konfigurasi untuk modul ini.
- Kami mencipta pautan sym ke konfigurasi untuk php-fpm.
- Kami mencipta pautan sym ke konfigurasi untuk php cli.
Dalam kes sedemikian, reka bentuk seperti $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
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 -
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 manifestofiles
- ia mengandungi failtemplates
- ia mengandungi templatlib
— 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
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 dinamakanfoo::<anything>
, atau hanyafoo
. - 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 manifesinit.pp
; - kelas
nginx::service
diterangkan dalam manifesservice.pp
; - tentukan
nginx::server
diterangkan dalam manifesserver.pp
; - tentukan
nginx::server::location
diterangkan dalam manifesserver/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
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
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
).
Pembolehubah Terbina dalam
Selain fakta, ada juga
- 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
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)[
Tambahan 2: Garis Panduan Pengekodan
- Letakkan semua logik dalam kelas dan definisi.
- Simpan kelas dan definisi dalam modul, bukan dalam manifes yang menerangkan nod.
- Gunakan fakta.
- Jangan buat if berdasarkan nama hos.
- 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.
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