Puppet ile Altyapı Yönetimi
Bu yazıda Puppet ile altyapınızı yönetirken kullanabileceğiniz gelişmiş Puppet özelliklerinden bahsedilecektir. Öncesinde Puppet ortamınızı kurmuş olmanız gerekmektedir. Eğer halen kurmadıysanız kurulum ile ilgili daha önce yayınlanan yazıya göz atabilirsiniz.
Bir önceki yazıda Puppet ile kullanılan fact’ler, manifest’ler ve modüllerden bahsedilmiş, master sunucu ve agent sunucularda Puppet çalıştırmak için izlenmesi gereken adımlar anlatılmıştır. Eklenen bir kod sonrası agent tarafında nasıl denenmesi gerektiği açıklanmıştır. Bu yazıya başlamadan önce halen okumadıysanız ilgili yazıyı okumanız faydalı olacaktır.
İçindekiler
Puppet Terminolojisi
Kaynaklar (Resources)
Herhangi bir Puppet kodu genel anlamda kaynak bildirimlerinden oluşmaktadır. Dolayısıyla kaynaklar Puppet kodlarının temel elemanlarından biridir. Bir Puppet kaynağı, sistemin durumu ile ilgili bilgiler içermektedir. Bu bilgiler bir kullanıcının veya dosyanın oluşturulması veya bir paketin kurulması gibi tanımlardan ibarettir. Kaynak bildirimleri aşağıdaki gibi önce kaynağın tipinin ve isminin belirtildiği, daha sonra gerekli dizilişe uygun özelliklerin sıralandığı bir yapıya sahiptir.
1 2 3 4 |
resource_type { 'resource_name' attribute => value ... } |
Kullanıcı kaynak tipine örnek bir kaynak bildirimi aşağıda yer almaktadır.
1 2 3 4 5 6 7 |
user { 'huseyin': ensure => present, uid => '1000', gid => '1000', shell => '/bin/bash', home => '/home/huseyin' } |
Puppet ile kullanabileceğiniz tüm kaynak türleri aşağıdaki komut ile listelenebilmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
puppet resource --types root@puppet-master:~# puppet resource --types a2mod anchor augeas computer cron exec file file_line filebucket group host interface k5login macauthorization mailalias maillist mcx mount nagios_command nagios_contact nagios_contactgroup nagios_host nagios_hostdependency nagios_hostescalation nagios_hostextinfo nagios_hostgroup nagios_service nagios_servicedependency nagios_serviceescalation nagios_serviceextinfo nagios_servicegroup nagios_timeperiod notify package resources router schedule scheduled_task selboolean selmodule service ssh_authorized_key sshkey stage tidy user vlan whit yumrepo zfs zone zpool |
Bu kaynak türlerini daha önceki yazılarda bahsedildiği gibi hazır modüller ekleyerek çoğaltmak mümkündür.
Manifest Dosyaları
.pp uzantılı Puppet programları “manifest” olarak isimlendirilmektedir. site.pp manifest dosyası hariç tüm manifest’ler bir modül altında yer almaktadır. site.pp ise Puppet altyapısında bulunan sunuculara uygulanacak şablonları içeren, ister tüm sunucular için geçerli olan ve ister sunucu bazında tanım yapılabilen bir formattadır. Puppet agent tarafında periyodik olarak çalıştığında veya merkezi olarak tetiklendiğinde site.pp dosyası içerisinden kendisini ilgilendiren kaynak bildirimlerini alarak istemci tarafında gerekli işlemleri yapmaktadır. Örnek site.pp dosyası aşağıda yer almaktadır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
… #tum sunucular icin gecerli olan blok #sunucu ismi belirtilmedigi surece tum sunucular icin gecerlidir node default { file {'/tmp/example-ip': ensure => present, mode => 0644, content => "Bulundugunuz sunucunun adi : $hostname \nSunucu IP Adresi: ${ipaddress_eth0}.\n", } … #sunucu bazinda ornek (puppet-client sunucusu icin) node 'puppet-client' { class { 'apache': } # use apache module apache::vhost { 'example.com': # define vhost resource port => '80', docroot => '/var/www/html' } #ns-1 ve ns-2 sunucusu için nameserver isimli modulu ekler node 'ns1', ‘ns-2’ { include nameserver } ... |
Sınıflar (Classes)
Puppet sınıfları modüller içerisinde yer alan ve herhangi bir yerden çağırılabilen kod bloklarıdır. Böylece kodun yeniden kullanılması ve manifest’lerin daha kolay okunması sağlanmaktadır. Açıkça kod içerisinden çağırılmadığı sürece çalışmazlar. Bir grup sunucu için tanımlanacak bir işlemi tek tek sunucu isimleri ile manifest dosyasına yazmak yerine bir modül oluşturarak altındaki bir sınıfa gerekli kod yazılarak site.pp dosyasında her sunucu için bu modül altındaki sınıfın kullanılması sağlanabilmektedir. Böylece hem kod tekrar edilmemiş olmakta hem de daha okunabilir hale gelmektedir. Örneğin huseyin modülü altındaki cotuk sınıfının belirlenen sunucu grubu için çalıştırmak üzere cotuk sinifi ilgili modül altında aşağıdaki gibi tanımlanarak site.pp dosyasında belirlenen sunuculara atanması sağlanabilmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
sudo vi /etc/puppet/modules/huseyin/manifests/cotuk.pp class cotuk { file { "server.cfg": require => File["/etc/mcollective/facts.yaml"], path => '/etc/mcollective/server.cfg', ensure => file, owner => "root", group => "root", mode => 0640, content => template('mcfacts/server.cfg.erb'), } } |
cotuk sınıfını puppet-client, ns1 ve ns2 isimli sunuclara atamak için de site.pp dosyasına aşağıdaki ekleme yapılmalıdır.
1 2 3 4 5 6 7 |
sudo vi /etc/puppet/manifests/site.pp ... node 'puppet-client' , 'ns1', 'ns2' { include huseyin::cotuk } … |
Buradaki tanım her sunucu için tek tek yapılabileceği gibi yukarıdaki örnekte olduğu gibi sunucu isimleri virgülle ayrılmak şartıyla birden fazla sunucu için de yapılabilmektedir.
Modüller
Modüller Puppet ile kullanılabilen manifest ve verilerden (fact’ler, dosyalar, şablonlar gibi) oluşan belirlenmiş bir dosya yapısına sahip bileşenlerdir. Puppet kodunun organize edilmesi için önemli rol oynayan modüller sayesinde kod çok sayıda manifest’e bölünerek kullanımı ve anlaşılması kolay bir hale gelmektedir.
Modüller belli bir dosya yapısına sahip olup her dosyanın ilgili hiyerarşik konumda bulunması gerekmektedir. Her modül /etc/puppet/modules dizininde yer almaktadır. Aşağıda Puppet modülleri tarafından kullanılan dosya yapısı verilmiştir.
- <MODÜL İSMİ>
- manifests
- files
- templates
- lib
- facts.d
- examples
- spec
Kendi modüllerinizi oluşturup kullanabileceğiniz gibi Puppet Forge sitesinden indirip doğrudan kullanabileceğiniz kullanıma hazır çok sayıda modül bulunmaktadır. Daha önceki yazıda “apache” modülünün indirilmesi ve kullanımı açıklanmıştır.
Örnek bir modül dizin hiyerarşisi aşağıda verilmiştir.
- huseyin – hiyerarşide en üstte yer alan bu dizin modül ismi ile aynı ismi taşımalıdır.
- manifests/ – huseyin modülünde yer alan tüm manifest’leri barındıran dizindir.
- init.pp – Rezerv edilmiş bir isme sahip bu manifest içinde modül ismi ile aynı olan bir sınıf tanımı bulunmalıdır.
- cotuk.pp – init dışında tanımlanan sınıflar bu şekilde sınıf ismine sahip dosya ismi ile oluşturulmaktadır. cotuk sınıfına erişim için huseyin::cotuk kullanılmalıdır.
- tanimlanmis_tip.pp – Modül altında tanımlanan tipler manifest klasörü altında yeni bir dosya içerisinde tanımlanabilmektedir. Burada tanımlanan tip’e huseyin::tanimlanmis_tip ile erişilebilmektedir.
- implementation/ – Örnek olarak oluşturulan bu dizinin ismi altında yer alan sınıflara erişimi etkilemektedir.
- foo.pp – huseyin::implementation::foo isimli bir sınıf içermelidir.
- bar.pp – huseyin::implementation::bar isimli bir sınıf içermelidir.
- files/ – Yönetilen sunucular tarafından indirilmek ve kullanılmak üzere statik içeriğe sahip dosyaların tutulduğu dizindir.
- settings.conf – Örnek olarak verilen bu dosyaya erişmek için puppet:///modules/huseyin/settings.conf adresi kullanılmalıdır. Dosyanın içeriklerine ayrıca “file” fonksiyonu ile örneğin content => file(‘huseyin/settings.conf’) şeklinde erişilebilmektedir.
- libs/ – Özel tanımlanan fact’ler, kaynak türleri ve plugin’ler bu dizinde tutulmaktadır. Buradaki dosyalara hem puppet-master sunucusu hem de yönetilen sunucular erişmektedir.
- facts.d/ – Ruby tabanlı fact’lere alternatif olan external fact’leri barındıran dizindir. Detaylar için ilgili sayfa incelenebilir.
- templates/ – Modülde bulunan manifest’lerin kullanabileceği şablonları içeren dizindir. Şablonlar içerisinde statik içerik yanında istemciye (yönetilen sunucuya) özel şekilde değişkenler veya fact’ler ile oluşturulan dinamik içerik de yer almaktadır. Detaylar için ilgili sayfa incelenebilir. Puppet (epp) ve Ruby (erb) olmak üzere iki şekilde yazılabilmektedir. Puppet versiyonu Puppet sürümlerine bağlı olmakla birlikte Ruby versiyonu her sürümde çalışabilmektedir.
- component.erb – Herhangi bir manifest bu şablona template(‘huseyin/component.erb’) ile erişerek işleyebilmektedir.
- component.epp – Herhangi bir manifest bu şablona template(‘huseyin/component.epp’) ile erişerek işleyebilmektedir.
- examples/ – Modüle ait sınıflara ve tiplere nasıl erişelebileceğini ve kullanımını gösteren örneklerin bulunduğu dizindir.
- init.pp
- baska_ornek.pp – Kullanım örnekleri yer alabilir.
- spec/ – lib dizininde bulunan plugin’ler için spec testlerinin yer aldığı dizindir.
- manifests/ – huseyin modülünde yer alan tüm manifest’leri barındıran dizindir.
Yeni Modül Oluşturma
Puppet içerisinde modül isimleri sadece küçük harflerden, rakamlardan ve alt tire “_” karakterlerinden oluşabilmekte, aynı zamanda arada “-” kullanılarak iki bölüm halinde tanımlanmaktadır. Küçük harfle başlaması gereken modül isimleri [a-z][a-z0-9_]* örüntüsüne sahip olmalıdır. Yeni bir modül oluşturmak için önerilen kullanım şekli modül ismi için “kullanıcı_adı-modul_ismi” şeklindedir. “ubuntu” kullanıcısı ile “ornek” modülünü oluşturmak için aşağıdaki komut kullanılmalıdır. Sorulan sorular uygun şekilde cevaplanmalıdır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
sudo puppet module generate ubuntu-ornek We need to create a metadata.json file for this module. Please answer the following questions; if the question is not applicable to this module, feel free to leave it blank. Puppet uses Semantic Versioning (semver.org) to version modules. What version is this module? [0.1.0] --> Who wrote this module? [ubuntu] --> What license does this module code fall under? [Apache 2.0] --> How would you describe this module in a single sentence? --> Where is this module's source code repository? --> Where can others go to learn more about this module? --> Where can others go to file issues about this module? --> ---------------------------------------- { "name": "ubuntu-ornek", "version": "0.1.0", "author": "ubuntu", "summary": null, "license": "Apache 2.0", "source": "", "project_page": null, "issues_url": null, "dependencies": [ {"name":"puppetlabs-stdlib","version_requirement":">= 1.0.0"} ] } ---------------------------------------- About to generate this metadata; continue? [n/Y] --> Notice: Generating module at /etc/puppet/modules/ubuntu-ornek... Notice: Populating templates... Finished; module generated in ubuntu-ornek. ubuntu-ornek/spec ubuntu-ornek/spec/spec_helper.rb ubuntu-ornek/spec/classes ubuntu-ornek/spec/classes/init_spec.rb ubuntu-ornek/manifests ubuntu-ornek/manifests/init.pp ubuntu-ornek/Rakefile ubuntu-ornek/metadata.json ubuntu-ornek/README.md ubuntu-ornek/tests ubuntu-ornek/tests/init.pp ubuntu-ornek/Gemfile |
Ardından /etc/puppet/modules/ubuntu-ornek dizini altında oluşturulan modüle ait varsayılan ornek sınıfı manifests dizini altındaki init.pp dosyasında tanımlanmış olacaktır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
cat ubuntu-ornek/manifests/init.pp # == Class: ornek # # Full description of class ornek here. # # === Parameters # # Document parameters here. # # [*sample_parameter*] # Explanation of what this parameter affects and what it defaults to. # e.g. "Specify one or more upstream ntp servers as an array." # # === Variables # # Here you should define a list of variables that this module would require. # # [*sample_variable*] # Explanation of how this variable affects the funtion of this class and if # it has a default. e.g. "The parameter enc_ntp_servers must be set by the # External Node Classifier as a comma separated list of hostnames." (Note, # global variables should be avoided in favor of class parameters as # of Puppet 2.6.) # # === Examples # # class { 'ornek': # servers => [ 'pool.ntp.org', 'ntp.local.company.com' ], # } # # === Authors # # Author Name <[email protected]> # # === Copyright # # Copyright 2016 Your name here, unless otherwise noted. # class ornek { } |
Bu sınıf üzerinde istenilen değişiklikler yapılabildiği gibi yeni sınıflar, tipler, şablonlar tanımlanabilmekte ve daha önce bahsedildiği gibi her birine gerekli şekilde erişim sağlanabilmektedir.
init.pp dosyası ilgili modül altında ilk çalıştırılan dosya olup modülün altındaki diğer manifestlere, şablonlara ve her türlü kaynağa çağrıların tanımlandığı bileşendir. Çağırılacak kaynaklar birbiri ile ilişkilendirilmediği durumlarda rastgele sırada çalışacaktır. Bu yüzden hangi sıra ile çağırılmak isteniyorsa bu doğrultuda kaynakların birbiri ile ilişkilendirilmesi gerekmektedir. Bu amaçla aşağıdaki örnekte olduğu gibi “->” operatörü yardımıyla işlenecek sınıfların sırası tanımlanabilmektedir. Bir satırdaki sınıfın işlenmesi bitmeden diğer satıra geçilmemektedir.
1 2 3 4 5 6 7 |
class test { class { 'test::driver_update': } -> class { 'test::liberty_upgrade': } -> class { 'test::nova': } -> class { 'test::neutron': } -> class { 'test::last_upgrade': } } |
Benzer şekilde kaynakların hangi sırada işleneceğini belirtmenin yolu ilgili manifest içerisinde kaynak tanımlarında “require” tanımını kullanmaktır. Eğer bir kaynak işlenmeden önce diğer kaynağın tamamlanmasına ihtiyaç duyuyorsa bu tanımı kullanmak uygun olmaktadır. Aşağıdaki örnekte önce dosya ilgili istemciye gönderilmekte, sıkıştırılmış dosya açılmakta, yükleme sırasında ihtiyaç duyulan kernel header paketi yüklenmekte, ardından sürücü dosyaları yüklenmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
root@puppet-master:~# cat /etc/puppet/modules/test/manifests/driver_update.pp class test::driver_update { #Ilk olarak driver dosyasi file { "ixgbe_driver": path => '/root/ixgbe-4.1.5.tar.gz', ensure => file, owner => "root", group => "0", mode => 0755, source => "puppet:///modules/test/ixgbe-4.1.5.tar.gz", } file { "extract_tarball": require => File["ixgbe_driver"], path => '/root/backup/driver_extract.sh', ensure => file, owner => "root", group => "0", mode => 0755, source => "puppet:///modules/test/driver_extract.sh", } # Driver extract exec { "driver_extract": require => File["extract_tarball"], path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", command => "/root/backup/driver_extract.sh" } package { "linux-headers-$facts['kernelrelease']": ensure => "latest", require => Exec["driver_extract"] } #10G driver install exec { "driver_install": require => Package["linux-headers-$facts['kernelrelease']"], timeout => 900, provider => shell, environment => "DEBIAN_FRONTEND=noninteractive", path => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", command => "mkdir -p /root/upgrade; \ cd /root/ixgbe-4.1.5/src; \ make install > /root/upgrade/driver_install.out.txt " } } |
Şablonlar
Modüller içerisinde istemciye özel değişkenleri kullanabilmek amacıyla faydalanılan Puppet bileşenleridir. Her istemcide bir kaynak oluşturmak istendiğinde ve bu kaynak içerisinde istemciye özel IP adresi, sunucu ismi gibi değişkenler bulunduğunda şablonlardan faydalanılmaktadır. Bu durumda bir şablon tanımlayıp içerisinde istemciye özel ve istemcide bulunan facter tarafından kullanılan tüm değişkenlerin kullanılabilmesi mümkün olmaktadır. Kullanıcı tarafından eklenen değişkenler de şablon içerisinden çağırılabilmektedir. Daha önce bahsedildiği gibi şablonlar embedded puppet (EPP) ve embedded ruby (ERB) olmak üzere iki farklı formatta kullanılabilmektedir. Aşağıda ruby formatında bir şablon örneği ve değişkenlerin kullanım şekli yer almaktadır.
1 2 3 4 5 6 7 8 |
root@puppet-master:~# cat /etc/puppet/modules/apache/templates/listen.erb <%# Listen should always be one of: - <port> - <ipv4>:<port> - [<ipv6]:<port> -%> Listen <%= @ipadress_eth0%>:<%@listen_addr_port %> |
Örnekte görüldüğü gibi değişkenler <% ve %> etiketleri arasında kullanılmakta ve hangi istemci üzerinde çalışıyorsa o istemciye ait değerleri kullanmaktadır. Örneğin 10.61.2.117 ip adresine sahip puppet-client isimli istemcide ilgili dosya içeriği aşağıdaki gibi oluşmaktadır.
1 2 3 4 5 6 7 |
root@puppet-client:/etc/apache2# cat ports.conf # ************************************ # Listen & NameVirtualHost resources in module puppetlabs-apache # Managed by Puppet # ************************************ Listen 10.61.2.117:80 |
Bu yazıda kısaca Puppet ile istemci bazında tanım yapma, kendi sınıf, modül ve şablonlarınızı oluşturma aracılığı ile altyapı yönetiminden bahsedilmiştir. Yazı serisinin devamında merkezi istemci yönetimi, mcollective ve foreman gibi araçlardan bahsedilecektir.