Belajar Puppet - Best Practice
Episode 15 of 23

Belajar Puppet - Best Practice

Terapkan best practice penulisan manifest Puppet yang aman untuk produksi: idempotency, pengelompokan resource, pola roles dan profiles, naming convention, serta pembatasan exec. Jaga kualitas dengan puppet-lint, hiera-data centric, dan dokumentasi.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Pendahuluan

Di episode 14 kalian sudah belajar mencari dan menginstall module dari Puppet Forge serta mengembangkan module sendiri menggunakan PDK. Pada episode ini kita akan membahas aturan main yang membedakan manifest yang asal jalan dengan manifest yang aman dioperasikan di produksi: best practice.

Best practice bukan sekadar gaya penulisan. Manifest yang idempotent, terkelompok rapi, dan bebas dari efek samping exec akan menyelamatkan tim dari incident di jam 2 pagi. Pola roles dan profiles menjadi standar industri, dan alat seperti puppet-lint serta puppet strings menjaga kualitas tetap konsisten di sepanjang waktu.

Pada episode ini kita akan membahas idempotency, pengelompokan resource, pola roles dan profiles, naming convention, pembatasan penggunaan exec, prinsip hiera-data centric, serta dokumentasi otomatis dengan puppet strings.

Prinsip Idempotency

Manifest dikatakan idempotent jika dijalankan berulang kali memberikan hasil yang sama, tanpa efek samping tambahan. Resource Puppet dirancang untuk itu: package, service, file, dan user akan membandingkan state saat ini dengan state yang diinginkan, lalu hanya mengubah yang berbeda.

Manifest idempotent
package { 'nginx':
  ensure => installed,
}
 
service { 'nginx':
  ensure => running,
  enable => true,
}
 
file { '/etc/nginx/nginx.conf':
  ensure  => file,
  source  => 'puppet:///modules/nginx/nginx.conf',
  owner   => 'root',
  group   => 'root',
  mode    => '0644',
  require => Package['nginx'],
  notify  => Service['nginx'],
}

Jalankan puppet apply dua kali berturut-turut; run kedua harus menampilkan status noop atau tidak ada perubahan. Jika ada resource yang terus berubah setiap run, itu indikasi manifest tidak idempotent.

Pengelompokan Resource

Resource sebaiknya dikelompokkan berdasarkan tanggung jawab, bukan dicampur acak dalam satu file. Setiap class yang jelas fokusnya lebih mudah diuji, dipelihara, dan dipakai ulang. Class nginx menangani instalasi dan konfigurasi dasar, sedangkan konfigurasi vhost bisa dipisah ke class tersendiri.

Tip

Saat satu class bertumbuh melampaui satu layar, pecah menjadi class-child. Contoh: nginx::install, nginx::config, dan nginx::service yang di-include dari nginx::init. Ini sekaligus mempermudah pengujian unit per bagian.

Pola Roles dan Profiles

Pola roles dan profiles adalah pemisahan dua lapisan yang paling direkomendasikan komunitas Puppet. Profil membungkus modul menjadi konfigurasi yang bermakna untuk sebuah peran teknis, sedangkan role menggabungkan beberapa profil menjadi satu "identitas" node.

profile/nginx/manifests/server.pp
class profile::nginx::server {
  class { 'nginx': }
  nginx::resource::vhost { 'api.example.com':
    www_root => '/var/www/api',
  }
}
role/manifests/web.pp
class role::web {
  include profile::base
  include profile::nginx::server
  include profile::php::fpm
}

Node di hiera cukup mengassign satu role, misalnya role::web, dan seluruh komposisi diurus oleh role. Profil berisi modul konkret dengan parameter nyata, sedangkan role tidak pernah berisi detail konfigurasi.

Important

Aturan emas pola ini: role hanya meng-include profil, dan profil hanya memakai modul. Jangan meletakkan konfigurasi detail langsung di role, dan jangan meng-include role dari role lain. Kedisiplinan ini menjaga hierarki tetap dangkal dan mudah dipahami.

Naming Convention

Penamaan yang konsisten membuat manifest terbaca tanpa komentar panjang. Beberapa konvensi yang umum dipakai:

ElemenKonvensiContoh
Classmodule dan module::subclassnginx::server
Parametersnake_case deskriptifserver_name, listen_port
Resource titleNama objek nyata di sistemPackage['nginx']
Variabel faktaIkuti Facter$facts['networking']['ip']
Module internalPrefix nama perusahaanperusahaan-profile_nginx

Resource title harus unik dan bermakna, misalnya nama paket atau path file, bukan nama acak seperti rule1.

Membatasi Penggunaan exec

Resource exec adalah pelarian yang sering disalahgunakan. Setiap exec berpotensi mengubah sistem di luar deklaratif Puppet, sehingga harus digunakan seminimal mungkin. Jika terpaksa, selalu berikan guard agar idempotent: creates, unless, atau onlyif.

exec dengan guard unless
exec { 'initialise-db':
  command => '/usr/local/bin/init-db.sh',
  unless  => '/usr/local/bin/check-db-initialised.sh',
  path    => ['/usr/local/bin', '/usr/bin'],
}

Perhatikan bahwa exec hanya berjalan ketika guard unless mengembalikan status non-zero, sehingga pengulangan run tidak menjalankan inisialisasi dua kali.

Caution

Sebelum menulis exec, tanyakan dulu: apakah ada resource bawaan Puppet yang bisa menggantinya? Instalasi paket pakai package, file gunakan file, restart layanan gunakan service dengan notify. exec hanya untuk hal yang benar-benar tidak bisa dideklarasikan.

Code Quality dengan puppet-lint

puppet-lint adalah linter untuk gaya penulisan manifest. Jalankan secara rutin untuk menangkap pelanggaran konvensi sebelum masuk ke review.

Lint semua manifest
puppet-lint manifests/

Laporan seperti quoted_strings_not_needed atau right_to_left_relationship membantu menegakkan konsistensi. Kita bisa mengabaikan aturan tertentu, misalnya arrow_on_right_operand_line, lewat file .puppet-lint.rc dengan --no-arrow_on_right_operand_line-check, tetapi jangan menonaktifkan aturan keamanan secara sembarangan.

Hiera-Data Centric

Manifest sebaiknya sedikit berisi data dan banyak berisi logika. Pisahkan nilai yang berubah antar environment ke Hiera, bukan menanamnya sebagai default class. Dengan begitu, perbedaan staging dan produksi cukup diatur di file hieradata.

hieradata/node/production.yaml
profile::nginx::server::listen_port: 443
profile::nginx::server::server_name: api.example.com
Profil membaca dari Hiera
class profile::nginx::server (
  Integer $listen_port = 80,
  String  $server_name = 'localhost',
) {
  ...
}

Parameter class otomatis diisi dari Hiera selama key hiera sesuai nama parameter, misalnya profile::nginx::server::listen_port. Prinsip ini membuat kode tidak tersebar data yang seharusnya menjadi tanggung jawab tim operasional.

Dokumentasi dengan puppet strings

puppet strings menghasilkan dokumentasi HTML dari komentar dokumen dalam manifest dan kode Ruby. Tulis dokumentasi pada setiap class, defined type, dan parameter penting.

Dokumentasi class dengan puppet strings
# @summary Mengelola instalasi dan konfigurasi Nginx.
#
# @param listen_port Port yang dipakai Nginx untuk listening.
# @param server_name Nama domain virtual host utama.
class profile::nginx::server (
  Integer $listen_port = 80,
  String  $server_name = 'localhost',
) {

Generate dokumentasi dengan puppet strings generate:

Generate dokumentasi module
puppet strings generate --format html

Note

Jangan lupa README module. README yang menjelaskan parameter dan contoh pemakaian membantu anggota tim baru memahami module tanpa harus membaca seluruh kode. Untuk module publik, README yang baik bahkan meningkatkan kepercayaan pengguna di Forge.

Penutup

Pada episode 15 ini kalian sudah memahami bahwa manifest yang baik untuk produksi dibangun di atas idempotency, pengelompokan resource yang jelas, pola roles dan profiles, naming convention yang konsisten, serta penggunaan exec yang sangat dibatasi. Kita juga belajar menjaga kualitas dengan puppet-lint, memisahkan data ke Hiera, dan mendokumentasikan kode dengan puppet strings.

Inti yang harus dibawa pulang:

  • Idempotency menjamin pengulangan run tidak menimbulkan perubahan tak terduga.
  • Roles dan profiles memisahkan komposisi node dari detail konfigurasi modul.
  • Naming convention membuat manifest terbaca tanpa komentar panjang.
  • Exec dipakai seminimal mungkin dan selalu diberi guard seperti unless atau creates.
  • Hiera-data centric dan puppet-lint menjaga kode tetap bersih dan mudah dikelola tim.

Semua pola tersebut berjalan di atas resource bawaan Puppet. Namun terkadang kebutuhan lebih dari sekadar resource standar. Di episode 16 kita akan membahas Belajar Puppet - Custom Resources, Functions & Providers: defined types, custom facts untuk Facter, functions dengan modern functions API, hingga membuat custom provider per platform.

Belajar Puppet - Best Practice | Belajar Puppet