連載
» 2015年01月23日 18時00分 公開

新人インフラ技術者のためのサーバー構築/運用自動化入門(4):作業手順書はもういらない! Puppetにおける自動化の定義書「マニフェスト」の書き方と基礎文法まとめ (4/5)

[菅原亮, 岡本隆史,NTT OSSセンタ]

条件分岐によって動作を変える

 それでは設定ファイルの残課題、搭載メモリで設定値を変える部分を片付けてしまいましょう。K男さんの指示ではMaxKeepAliveRequestsを本番用サーバーは500、開発用サーバーは100を設定するようにとのことでした。

 またK男さんの話によると、K男さんとR子さんの職場にある本番用サーバーは必ず8GB以上のメモリが搭載されていて、開発用サーバーは4GB以下になっています。ですので、今回は搭載メモリで本番用か開発用かを判別してもよいとのことでした。搭載メモリは先ほどFacts変数から取得できることを説明しましたね。

 となると、次に来るのは「条件分岐」です。

 説明に入る前に一つだけ注意点があります。これから紹介する条件分岐を使うと、さまざまな環境で柔軟に対応できるマニフェストを作れるようになりますが、その半面プログラムのようになってしまい読みにくいマニフェストになりがちです。そのため条件分岐を使うのは、今回の例のように条件分岐でパラメーターを決定して、異なるOSやディストリビュージョンの環境差異を吸収する程度の利用に留めてください。

if文

 Puppetでは一般的なプログラミング言語と同等レベルの条件文が記述できます。ここでは搭載メモリが8GBより多いか少ないかを判定するだけなので「if」を使います。if文の基本形は以下の通りです。

if 条件 {

 コード

}

elsif 条件 {

 コード

}

else {

 コード

}


 条件には比較演算子(==, !=,< , >, <=, >=)や正規表現によるマッチング(=~, !~)が記述できます。それでは搭載メモリが8GBより多いか少ないかを判定して、結果によってMaxKeepAliveRequestsの値を変えてみましょう。

 最初に先ほどのhttpd.conf.erbで、MaxKeepAliveRequestsの行を以下のように修正します。

修正前 MaxKeepAliveRequests 100
修正後 MaxKeepAliveRequests <%= @keepalive %>

 次に値を判定するif文を書きます。Factsのmemorysize_mbを使えばMB単位で搭載メモリを調べられるので、以下のようにif文のブロックを作ります。

if $memorysize_mb > 8192 {
  $keepalive = 500
}
else {
  $keepalive = 100
}
notify {$keepalive:}

 このマニフェストはnotifyリソースで判定した結果を表示できるようになっているので、実験してみましょう。

#  puppet apply
if $memorysize_mb >= 8192 {
  $keepalive = 500
}
else {
  $keepalive = 100
}
notify {$keepalive:}
 
[CTRL]+[D]キーを押下
 
Notice: Compiled catalog for puppet in environment production in 0.04 seconds
Notice: 100
Notice: /Stage[main]/Main/Notify[100]/message: defined 'message' as '100'
Notice: Finished catalog run in 0.03 seconds

 実験した環境は搭載メモリが1GBなので、値として100が返ってきています。試しに条件文の8192を搭載メモリよりも低い192などの値に変更して、再度実験してみましょう。今度は500が返ってくるはずです。

 それではif文のブロックが出来上がったので、マニフェストに組み込みましょう。

if $memorysize_mb >= 8192 {
  $keepalive = 500
}
else {
  $keepalive = 100
}
 
package { 'httpd':
  ensure => present,
}
 
file { '/etc/httpd/conf/httpd.conf':
  ensure  => present,
  content => template('/root/httpd.conf.erb'),
  require => Package['httpd'],
}
 
service { 'httpd':
  ensure    => running,
  enable    => true,
  subscribe => File['/etc/httpd/conf/httpd.conf'],
}

 これで本番用サーバーと開発用サーバーの双方に同じマニフェストを使えるようになりました。

case文

 後はCentOSとUbuntuの両方に対応する件だけです。こちらはif文でも記述できますが、他のOSも追加になるかもしれませんので、後から追加しやすいcase文で記述しましょう。また、CentOSとUbuntuでhttpd.confを共用するのは面倒なので、こちらも切り替えることができるようにしておきます。

 コードは以下のようになります。

case $operatingsystem {
  centos: {
    $httpd = "httpd"
    $conf  = "/etc/httpd/conf/httpd.conf"
    $template = "httpd.conf_centos.erb"
  }
  ubuntu: {
    $httpd = "apache2"
    $conf  = "/etc/apache2/apache2.conf"
    $template = "httpd.conf_ubuntu.erb"
  }
  default: { fail("unknown operatingsystem") }
}
 
notify {$httpd:}
notify {$conf:}
notify {$template:}

 CentOSかUbuntuではない場合はエラー終了するようになっています。こちらもnotifyリソースで判定した結果を表示できるので、実験してみましょう。

#  puppet apply
case $operatingsystem {
  centos: {
    $httpd = "httpd"
    $conf  = "/etc/httpd/conf/httpd.conf"
    $template = "httpd.conf_centos.erb"
  }
  ubuntu: {
    $httpd = "apache2"
    $conf  = "/etc/apache2/apache2.conf"
    $template = "httpd.conf_ubuntu.erb"
  }
  default: { fail("unknown operatingsystem") }
}
notify {$httpd:}
notify {$conf:}
notify {$template:}
 
[CTRL]+[D]キーを押下
 
Notice: Compiled catalog for puppet in environment production in 0.03 seconds
Notice: /etc/httpd/conf/httpd.conf
Notice: /Stage[main]/Main/Notify[/etc/httpd/conf/httpd.conf]/message: defined 'message' as '/etc/httpd/conf/httpd.conf'
Notice: httpd.conf_centos.erb
Notice: /Stage[main]/Main/Notify[httpd.conf_centos.erb]/message: defined 'message' as 'httpd.conf_centos.erb'
Notice: httpd
Notice: /Stage[main]/Main/Notify[httpd]/message: defined 'message' as 'httpd'
Notice: Finished catalog run in 0.05 seconds

 実験した環境はCentOSなので、意図した結果になっていることが確認できました。このブロックもマニフェストに組み込みましょう。リソースのタイトルなどに変更が入ります。

  if $memorysize_mb >= 8192 {
    $keepalive = 500
  }
  else {
    $keepalive = 100
  }
 
  case $operatingsystem {
    centos: {
      $httpd = "httpd"
      $conf  = "/etc/httpd/conf/httpd.conf"
      $template = "httpd.conf_centos.erb"
    }
    ubuntu: {
      $httpd = "apache2"
      $conf  = "/etc/apache2/apache2.conf"
      $template = "httpd.conf_ubuntu.erb"
    }
    default: { fail("unknown operatingsystem") }
  }
 
  package { $httpd:
    ensure => present,
  }
 
  file { $conf:
    ensure  => present,
    content => template("http_server/$template"),
    require => Package[$httpd],
  }
 
  service { $httpd:
    ensure    => running,
    enable    => true,
    subscribe => File[$conf],
  }

 これでK男さんの要望にはほぼ応えることができるマニフェストができました。

agent/master型に対応するには

 ここまでは構築対象のサーバー上のスタンドアロンでマニフェストを実験してきましたが、agent/master型で運用すると、管理ノード(master)上で全てのノードの構成を一元管理できます。K男さんとR子さんの職場でも運用ではagent/master型を使うそうなので、ここで対応しておきましょう。

 agent/master型ではサーバー個別にマニフェストを定義できるよう「node [ホスト名]」でマニフェストを囲んだものを「site.pp(/etc/puppet/manifests/site.pp)」ファイルに記述します。前回agent/master型のPuppetではmaster側にある「site.pp」ファイル(/etc/puppet/manifests/site.pp)がagent側で実行されるマニフェストファイルになることを説明しましたね。ここにサーバーの数だけnodeを記述します。

 例えばサーバーのホスト名が「www01」なら以下のようになります。

node www01 {
  :(先ほどのマニフェスト)
}
  :(サーバーの数だけ繰り返し)

 ホスト名を「default」とすると、ホスト名のnodeブロックがない場合に適用するマニフェストを設定できます。これだけを見るとnodeのブロックごとにコピー&ペーストしなくてはならないので、K男さんの「サーバーを増設するときの修正が極力少なくて済むこと」という要望には応えられているか、少し不安になってきませんか。

 先ほどのマニフェストでは、複数のリソースや条件分岐などを記述していました。さらにノードを増やすときはマニフェスト全体をコピー&ペーストしなければならず効率も悪いですし、見通しが悪くなってノードが増えれば増えるほどメンテナンス性も悪くなっていきます。

 ノードが増えたときに何も書かないのは難しいですが、せめて数行程度ならラクですよね。そんな複数のリソースなどをまとめてしまう記法がPuppet言語にはあります。

Copyright © ITmedia, Inc. All Rights Reserved.

編集部からのお知らせ

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。