Puppet beginner guide (korean)

Puppet 초보자를 위한 설명서입니다.

"시스템관리자를 위한 Puppet3" 자료를 기초로 만들었습니다.


퍼펫 소개

형상관리 : 형상 관리 자동화. 패키지나 파일 같은 자원에 대한 설정을 기술한 명세서를 메니페스트라고 부름

퍼펫이 하는 일 : 현재의 설정과 매니페스트 비교하여 필요한 액션만 수행. 광범위한 플랫폼과 운영체제 지원.

퍼펫의 장점

  • 매니페스트를 한 번만 작성하면 여러 장치에 중복 작업 없이 적용 가능
  • 모든 서버가 매니페스트를 기준으로 서로 동기화 가능
  • 매니페스트를 문서로 사용 가능
  • 다양한 운영체제, 플랫폼, 명령어 문법 등에 유연
  • 매니페스트는 코드이기 때문에 버전 및 다른 코드 관리 방식이 적용 가능

확장성

퍼펫의 언어 : 선언적인 프로그래밍 언어.

퍼펫 시작

테스팅 환경 준비하기

원하는 리눅스 배포판을 설치한 컴퓨터를 준비한다. 가상머신, Vagrant, 물리적 서버 상관없다. 여기에서는 주로 CentOS 5/CentOS 6 를 기준으로 설명한다.

적절하게 hostname 을 설정한다. (필요하면 /etc/hosts에 등록)

Puppet 설치

Puppet 최신버전은 3.7이다. 2014.11.27 현재 EPEL에 있는 Puppet 은 2.7 이다. "시스템관리자를 위한 Puppet3 자료"에서는 Puppet 3 를 기준으로 설명을 하고 있지만 이 문서에서는 Puppet 2.7 를 기준으로 설명한다.

Puppet 은 CentOS5, CentOS6 에 기본 들어있지 않으며 EPEL 에 있는 패키지 또는 Puppet 에서 제공하는 rpm을 이용하여 설치할 수 있다.

  • EPEL 를 이용하여 설치. CentOS에서 epel 의 yum repo를 이용하려면 epel-release rpm 을 설치하면 되며 이 rpm은 CentOS Extras 레포지토리에 이미 포함이 되어 있으므로 간단히 설치를 할 수 있다.

  • 참고로 CentOS6 에서는 epel-release rpm 을 설치하고 yum 을 실행하면 "Error : Cannot retrieve metalink for repositroy: epel. Please verify its path and try again." 에러가 난다. CentOS5로 CentOS6 으로 넘어가면서 /etc/yum.repos.d/epel.repo 파일의 mirrorlist 가 http에서 https로 바뀐 것과 연관이 있는데 일단 https로 되어 있는 부분을 http로 변경하면 사용은 가능하다. 이게 좋은 방법인지는?

  • puppet rpm 뿐만 아니라 연관된 rpm을 함께 설치한다.

    # cat /etc/redhat-release
    CentOS release 6.3 (Final)
    # yum install epel-release
    # yum install puppet
    ....
    ====================================================================================================================
     Package                          Arch                   Version                         Repository            Size
    ====================================================================================================================
    Installing:
     puppet                           noarch                 2.7.25-2.el6                    epel                 1.1 M
    Installing for dependencies:
     augeas-libs                      x86_64                 1.0.0-7.el6                     base                 313 k
     compat-readline5                 x86_64                 5.2-17.1.el6                    base                 130 k
     dmidecode                        x86_64                 1:2.12-5.el6_5                  base                  73 k
     facter                           x86_64                 1.6.18-7.el6                    epel                  62 k
     libselinux-ruby                  x86_64                 2.0.94-5.8.el6                  base                 100 k
     pciutils                         x86_64                 3.1.10-4.el6                    base                  85 k
     ruby                             x86_64                 1.8.7.374-2.el6                 base                 538 k
     ruby-augeas                      x86_64                 0.4.1-1.el6                     epel                  21 k
     ruby-libs                        x86_64                 1.8.7.374-2.el6                 base                 1.7 M
     ruby-shadow                      x86_64                 1.4.1-13.el6                    epel                  11 k
     virt-what                        x86_64                 1.11-1.2.el6                    base                  24 k
    Updating for dependencies:
     libselinux                       x86_64                 2.0.94-5.8.el6                  base                 108 k
     libselinux-devel                 x86_64                 2.0.94-5.8.el6                  base                 137 k
     libselinux-utils                 x86_64                 2.0.94-5.8.el6                  base                  82 k
     pciutils-libs                    x86_64                 3.1.10-4.el6                    base                  34 k
    ....
    Is this ok [y/N]:
  • Puppetlabs 에서 제공한 패키지를 이용하여 설치하는 경우에는 https://docs.puppetlabs.com/guides/install_puppet/install_el.html 문서를 참고한다.

매니페스트 작성하기

처음 작성하는 manifests

manifests 구조화

  • nodes.pp 생성
  • 노드 선언
  • manifests 파일을 만들어 실습해 보기.

    • site.pp 파일에 file 속성을 이용해서 생성을 하고 puppet apply 명령을 이용 실행을 해봄.

    • 그러고 나서 manifests 디렉토리 밑에 site.pp, nodes.pp 로 구조화를 함.

    • 테스팅을 위해서 github에 샘플 puppet manifests 를 만들었음. git clone https://github.com/taejoonmoon/puppet-training.git

  • site.pp 가 메인 매니케스트 파일임. 아주 작은 site.pp 를 만들고 nodes.pp 처럼 다른 매니페스트 파일을 불러오도록 만든다.

    [vagrant@vagrant-centos64 ~]$ mkdir puppet-training
    [vagrant@vagrant-centos64 ~]$ cd puppet-training/  (or git clone https://github.com/taejoonmoon/puppet-training.git)
    [vagrant@vagrant-centos64 puppet-training]$ tree
    .
    |-- README.md
    `-- manifests
        |-- nodes.pp
        `-- site.pp
    1 directory, 3 files
    [vagrant@vagrant-centos64 puppet-training]$ cat manifests/site.pp 
    import 'nodes.pp'
    [vagrant@vagrant-centos64 puppet-training]$ cat manifests/nodes.pp 
    node 'vagrant-centos64.vagrantup.com' {
        file { '/tmp/hello':
            content => "Hello, world\n",
        }
    }
    [vagrant@vagrant-centos64 puppet-training]$ puppet apply manifests/site.pp 
    notice: /Stage[main]//Node[vagrant-centos64.vagrantup.com]/File[/tmp/hello]/ensure: defined content as '{md5}a7966bf58e23583c9a5a4059383ff850'
    notice: Finished catalog run in 0.04 seconds
    [vagrant@vagrant-centos64 puppet-training]$ cat /tmp/hello 
    Hello, world

패키지, 파일, 서비스

패키지

$ vim apache.pp
  package { 'httpd':
    ensure => installed,
  }
$ sudo puppet apply apache.pp
  • 특정 버전 설치 : ensure => 'httpd-2.2.15-39.el6.centos.x86_64'
  • 패키지 삭제 : ensure => absent

  • 패키지 업데이트 : ensure => latest

모듈

  • 퍼핏 매니페스트를 모듈로 관리하면 해석과 유비 보수가 매우 용이함. 퍼핏 모듈은 연관된 패키지들을 그룹으로 관리함.
  • 모듈을 사용할 때에는 puppet 에게 모듈 위치를 알려주어야 함. (modulepath)
$ cd puppet-training
$ mkdir -p modules/apache
$ cd modules/apache
$ mkdir files manifests
$ tree ~/puppet-training
.
|-- README.md
|-- manifests
|   |-- nodes.pp
|   `-- site.pp
`-- modules
    `-- apache
        |-- files
        `-- manifests
            `-- init.pp

$ cat modules/apache/manifests/init.pp 
class apache {
    package { 'httpd':
        ensure  => installed,
    }
}

$ cat manifests/nodes.pp 
node 'vagrant-centos64.vagrantup.com' {
    include apache
}
$ sudo puppet apply /home/vagrant/puppet-training/manifests/site.pp --modulepath=/home/vagrant/puppet-training/modules
  • 자주 사용하는 puppet apply 명령어 생성
$ sudo vim /usr/local/bin/papply
$ sudo chmod a+x /usr/local/bin/papply 
$ cat /usr/local/bin/papply
#!/bin/bash
sudo puppet apply /home/vagrant/puppet-training/manifests/site.pp --modulepath=/home/vagrant/puppet-training/modules $*
$ papply


서비스

  • apache/manifests/init.pp 수정
  service { 'httpd':
    ensure  => running,
    require => Package['httpd'],
  }
$ papply
  • require 속성 : 자원들 간의 연관성을 정의. Package 에서 P가 대문자임. 이는 puppet 에세 대괄호 뒤에 오는 이름을 가진 패키지 자원의 인스턴스를 이용한다는 것을 알려줌.
  • enable 속성 : 부팅 할 때 서비스 시작 여부 제어
  • 상태 확인이 어려운 서비스의 경우 hasstatus, pattern 등의  속성 등을 이용할 수 있음. 또는 status 속성을 이용하아여 직접 명령어를 지정해 줄 수 있음.
  • start, stop, restart 등도 다른 명령어로 지정이 가능함.

파일

  • apache/manifests/init.pp 수정

    $ vim apache/manifests/init.pp
      file { '/etc/httpd/conf.d/default.conf':
        source => 'puppet:///modules/apache/default.conf',
        notify => Service['httpd'],
      }
    
      file { '/var/www/html/index.html':
        source => 'puppet:///modules/apache/index.html',
      }
    $ cat apache/files/default.conf 
    <VirtualHost *:80>
        DocumentRoot /var/www/html
        ServerName dummy-host.example.com
    </VirtualHost>
    $ cat apache/files/index.html 
    welcome to puppet!
    $ papply
    $ curl localhost
  • source 지정 : puppet:///modules 에서 ///  세개가 들어감. files 는 생략해야 함.
  • notify : 다른 자원 호출.

GIT 으로 Puppet 관리하기

git vs puppet master 장단점

git 사용시 장점


사용자 관리

user & ssh_authorized_key

    # user test
    user { 'art':
        ensure  => present,
        comment => 'my art',
        home => '/home/art',
        managehome => true,
    }
    ssh_authorized_key { 'art_ssh':
        user => 'art',
        type => 'rsa',
        key => 'AAAAB3NzaC1yc2EA.....sYguH8xtSS/34I2NQ==',
    }
  • User : 계정 상세하려면 ensure 를 absent 로 변경
  • 새로운 ssh 키를 생성하기 위해서는 ssh-keygen 명령어를 사용.

exec, cron, file, templates

exec, cron

  # exec test
  exec { 'Run my arbitray command':
    command => '/bin/echo I ran this command on `/bin/date` > /tmp/command.output.txt',
    creates => '/tmp/command.output.txt',
    #unless  => '/usr/bin/test -f /tmp/command.output.txt',
    #onlyif  => '/usr/bin/test -f /tmp/command.output.txt',
    #path => ['bin','/usr/bin'],
  }
  exec { 'command-1':
    command => '/bin/touch /tmp/step1 && /bin/echo Step 1',
    #creates => '/tmp/step1',
    unless  => '/usr/bin/test -f /tmp/step1',
  }
  exec { 'command-2':
    command => '/bin/echo Step 2',
    require => Exec['command-1'],
  }
  # cron test
  cron { 'test cron':
    command => 'touch /tmp/testcron',
    hour    => '04',
    minute  => '00',
  }

템플릿

템플릿 함수 : 약간만 다른 여러 파일을 가지고 있거나, 동적으로 변하는 정보를 포함한 파일이 있을 때 템플릿을 사용할 수 있음.

  • <%= %> 설명
  • Puppet 에서 변수는 $ 를 사용하지만 템플릿에서는 @ 를 이용함. (템플릿이 퍼핏이 아린 루비로 쓰여져 있기 때문임)
  • facter 를 이용하여 각종 시스템값을 이용할 수 있음.
$ cat apache/manifests/init.pp
  # template test
  $vhost_port = "8080"
  $site_name = 'example.com'
  file { '/etc/httpd/conf.d/example.com.conf':
    content => template('apache/vhost.conf.erb'),
    notify => Service['httpd'],
  }
$ cat apache/templates/vhost.conf.erb 
Listen <%= @vhost_port %>
<VirtualHost *:<%= @vhost_port %>>
    DocumentRoot /var/www/html
    ServerName <%= @site_name %>
</VirtualHost>
# <%= @ipaddress %>
# <%= @fqdn %>
# <%= @memorysize %>
# <%= @operatingsystem %>

$ facter  | less
architecture => x86_64
augeasversion => 1.0.0
domain => vagrantup.com
facterversion => 1.6.18
fqdn => vagrant-centos64.vagrantup.com
hardwareisa => x86_64
hardwaremodel => x86_64
hostname => vagrant-centos64
id => vagrant
....

definition 과 class

배열

  # array test
  package { ['lynx','mc','traceroute']:
    ensure => installed,
  }


정의(definition)

  • 다른 유형의 자원들을 그룹화 할 때 define 사용.
  • 매개변수를 줄 수 있음. 매개변수를 줄 때는 기본값을 지정하여 사용할 수 있음.
$ cat modules/base/manifests/script_job.pp 
# define test
define base::script_job ( $hour = '00' ) {
        include base
        file { "/usr/local/bin/${name}":
            source => "puppet:///modules/base/${name}",
            mode => '0755',
        }
        cron { "Run ${name}":
            command => "/usr/local/bin/${name}",
            hour => $hour,
            minute => '00',
            user => 'vagrant',
        }
}

$ cat manifests/nodes.pp 
node 'vagrant-centos64.vagrantup.com' {
    include base
  base::script_job { 'backup_database1':
    hour => '05',
  }
}


클래스(class)

  • 특정 서비스를 구현하는 퍼펫 자원을 그룹화 하기 위해서 사용
  • 클래스도 definition 과 마찬가지로 몇 개의 매개변수를 지정할 수 있음. 또한 매개변수는 기본값을 가질 수 있음.
    • 매개변수를 잘 이용하면 중복된 코드를 만들지 않고 코드의 재활용성을 높일 수 있음.

      class appserver($domain,$databse) {
       ....
      }
      
      class hadoop($role = 'node') {
      }
  • 클래스는 모듈로 구성하는 것이 좋음. 각 클래스는 modules/MODULE_NAME/manifests 디렉토리에 저장해야 하고 하나의 클래스를 포함하는 각 파일은 클래스의 이름을 따서 파일 이름을 생성해야 함. (예외는 init.pp)
  • 클래스 선언은 include MODULE_NAME 또는 require MODULE_NAME 또는 매개변수를 주어서 선언하는 방법이 있음.
  • 클래스와 definition 의 차이점 : 클래스는 단독 개체임. 오직 한 시점에 하나의 노드에 하나의 클래스의 인스턴스만 존재함.
    • 하나의 노드에 여러 인스턴스가 필요한 경우 definition
    • 웹서버처럼 지정한 노드에 같은 용도의 다른 인스턴스끼리 충돌이 발생할 것 같으면 클래스 사용함.

표현식과 로직

조건문 : if, unless, case, 셀렉터

if EXPRESSION {
OPTIONAL_SOMETHING
} elsif ANOTHER_EXPRESSION {
OPTIONAL_SOMETHING_ELSE
} else {
OPTIONAL_OTHER_THING
}

case EXPRESSION {
CASE1 { BLOCK1 }
CASE2 { BLOCK2 }
CASE3 { BLOCK3 }
...
default : { ... }
}

$result = EXPRESSION ? { 
  CASE1 => VALUE1,
  CASE2 => VALUE2,
  CASE3 => VALUE3,
  default => DEFAULT_VALUE,
}

표현식 : 비교문, boolean 연산자, 산술 연산자

  • 비교 연산자 :  == , !=, < , <= , > , >=
  • ‹ Boolean 연산자 : and , or , !
  • 문자열, 배열 또는 해쉬 멤버쉽 연산자 : in
  • 산술 연사자 : + , - , * , / , << , >>

정규표현식

if $::hostname =~ /app.*staging/ {

if $uname =~ /(\d+)\.\d+\.\d+/ {
notify { "I have kernel version ${0}, major version ${1}": }
}

텍스트 대체

문자열을 대체하기 위해서는 regsubst 함수를 이용함.

$output = regsubst('Look at my cat picture','my (.*) picture','this
adorable \1')
notify { $output: }

출력결과
Notice: Look at this adorable cat

배열

['jerry', 'george', 'elaine']

package { [ 'php5-cli', 'php5-fpm', 'php-pear' ]:

$developers[0]

해쉬

$interfaces = {
'lo0' => '127.0.0.1',
'eth0' => '192.168.0.1',
}

$interfaces = { 
'lo0' => {
  'address' => '127.0.0.1',
  'netmask' => '255.0.0.0',
  },  
'eth0' => {
  'address' => '192.168.0.1',
  'netmask' => '255.255.255.0',
  }
}

리포팅 및 문제 해결

리포팅

디버그

  • --debug 옵션
$ papply --debug

Noop 실행

  • Noop은 no-operation을 뜻하며 실제 시스템에 적용하지 않으면서 모든 일을 수행함. 어떤 변경사항을 적용하기 전에 테스팅이 가능함.
$ papply --noop


구문 오류 검사

  • 매니페스트의 구문 오류가 없는지 확인하기 위해서 parser validate 명령어를 이용.
$ puppet parser validate nodes.pp


디버그 출력

  • notify, exec

모니터링

에러

컴파일 에러, 명령어 옵션 오타

퍼펏과 관련해 알아두면 좋은 내용

퍼펫 스타일

  • 코드를 모듈로 분리
  • 공통 코드를 definition 으로 리팩토링
  • 노드 선언은 간단하게 한다
  • 퍼펫 린트 사용
  • 주석이 필요 없는 코드 제작

퍼펫 관련 학습 자료

  • 참조문서
  • Puppet forge : puppet code 커뮤니티 저장소.  https://forge.puppetlabs.com/

    • $ puppet module search httpd
      Searching http://forge.puppetlabs.com ...
      NAME                                 DESCRIPTION                                                                                         AUTHOR          KEYWORDS                                         
      ....
      puppetlabs-apache                    Puppet module for Apache                                                                            @puppetlabs     web httpd centos rhel ubuntu ssl wsgi proxy      
      [vagrant@vagrant-centos64 ~]$ mkdir .puppet/modules
      [vagrant@vagrant-centos64 ~]$ puppet module install puppetlabs-apache
      Preparing to install into /home/vagrant/.puppet/modules ...
      Downloading from http://forge.puppetlabs.com ...
      Installing -- do not interrupt ...
      /home/vagrant/.puppet/modules
      └─┬ puppetlabs-apache (v1.2.0)
        ├── puppetlabs-concat (v1.1.2)
        └── puppetlabs-stdlib (v4.5.1)
      
      

더 나아가기