Chef/初心者向けChef入門講座/templateを使う


templateを使う

さて、ここまでにntpdのインストールと起動を行ったと思いますが、設定ファイルはインストール直後のデフォルト状態です。
せっかくなので設定ファイルを書き換えて任意のサーバーを参照するようにしたいところですね。
それにはChefのテンプレート機能を使うのが便利です。

テンプレートとは雛形の機能で、テキストファイルに任意の文字を入力できる箇所を作って反映させることができる物です。
言葉だけだと何だか分からないかもしれないので実際にやってみましょう。

とりあえずやってみる

まずはテンプレート機能を使って単なる設定ファイルをを作成してみます。
test_cookbook/templates/default/etc/ntp.conf.erbを以下の内容で作ります。
server ntp.jst.mfeed.ad.jp
ntp.confとしては最少のファイルですね。
Chefのテンプレート機能はrubyのerbという機能を使って実現し、ファイルの拡張子はerbになります。

これを実際にリモートに作成するレシピは以下の通りです。
以前作ったtest_cookbook/recipes/default.rbの内容を活かしつつ以下の内容に変更します。
yum_package "ntp" do
  action :install
end

service "ntpd" do
  action [ :enable, :start ]
end

template "/etc/ntp.conf" do
  source "etc/ntp.conf.erb"
  notifies :restart, "service[ntpd]"
  action :create
end
templateリソースを追加しました。
第一引数は作成先ファイルのパスです。

sourceは作成元ファイルのパスですが、先程作成したのは test_cookbook/templates/default/etc/ntp.conf.erb でした。
templateリソースを使うと、自動的にtemplatesディレクトリのdefaultディレクトリからの相対パスになるのでこのような形で読み込むことが可能になります。

notifiesはtemplateの他にも様々なリソースで使用可能ですが、templateリソースにおいてはファイルが更新された場合に続けて実行する動作を指定できます。
ここでは直感的に理解できると思いますが、ntpdのサービスを再起動するようにしています。
設定ファイルを書き換えたらやはり反映させないと意味が無いですからね。

最後のactionは、ファイルの作成を行うようにしています。
これが基本形ですが、他にもdeleteやcreate_if_missingなどのactionが指定できるようです。

その他の情報についてはこちらの公式リファレンスを見て下さい。

Chefのレシピは基本的には書いた順番に実行されますので、インストールしてないのに起動を試みたりなどの矛盾が生じないようにしましょう。

では実行です。
knife solo cook [被管理サーバーIP] ~/chef/nodes/[被管理サーバーIP].json
ログでエラーが出ていないこと、設定が反映されてntpサーバーがntp.jst.mfeed.ad.jpに向いていることを確認してみて下さい。

ちゃんとテンプレートにする

これだけだとせっかくのtemplateの機能を使えてない上にfileリソース使っても同じなので、templateっぽくしてみます。

まずテンプレートファイルを以下の様に書き換えます。
server <%= @ntp_server %>
<%= %>で囲まれた記述が目を引くと思いますが、erbファイルで<%= %>で囲まれた部分の中身はrubyのコードです。
逆に言えば、この部分に任意のrubyのコードを記述することが可能になります。
今回、中にある @ntp_server はレシピ側から値を入れられる変数で、単にそれだけを記述したrubyのコードになっています。
ちなみにrubyのコードでは@を付けた変数はインスタンス変数です。

そしてレシピのtemplateリソースの部分を下記の様にします。
template "/etc/ntp.conf" do
  source "etc/ntp.conf.erb"
  notifies :restart, "service[ntpd]"
  action :create
  variables({
    :ntp_server => 'ntp1.jst.mfeed.ad.jp'
  })
end
variablesメソッドが追加されていて、引数に{}で囲ったハッシュ(連想配列)を渡すことでテンプレートファイルの変数に値をセットできます。
ここでは :ntp_server => と書くことで、テンプレートファイルの @ntp_server に値をセットしています。
テンプレート側は@でインスタンス変数ですが、レシピ側では:でシンボルになることに注意して下さい。

なお、以前メソッドの括弧()を省略できると書いたことがありますが、ここではvariablesメソッドの括弧()を省略することはできません。
この括弧()を省略して↓のように書くと、メソッドに対してブロックを渡すという風に解釈されるそうで、エラーになります。
variables { :ntp_server => 'ntp1.jst.mfeed.ad.jp' }

さて、ではレシピを実行してみましょう。
# knife zero chef_client 'name: [ノード名]'
新しい設定が反映されたでしょうか?

テンプレートに対して複数の値を渡すこともできます。
テンプレートを下記の様にします。
server <%= @ntp_server1 %>
server <%= @ntp_server2 %>
server <%= @ntp_server3 %>

レシピは下記の様にします。
template "/etc/ntp.conf" do
  source "etc/ntp.conf.erb"
  notifies :restart, "service[ntpd]"
  action :create
  variables({
    :ntp_server1 => 'ntp1.jst.mfeed.ad.jp',
    :ntp_server2 => 'ntp2.jst.mfeed.ad.jp',
    :ntp_server3 => 'ntp3.jst.mfeed.ad.jp'
  })
end
実行すればそれぞれ別の値が入ることが分かると思います。

もっとrubyっぽく使う

先程、<%= %>で囲うとrubyのコードを埋め込めるということを書きました。
せっかくの機能を有効活用するため、もう少しrubyのコードをうまく使った形で書いてみます。

今度はレシピを先にご案内です。
template "/etc/ntp.conf" do
  source "etc/ntp.conf.erb"
  notifies :restart, "service[ntpd]"
  action :create
  variables({
    :ntp_servers => [ 'ntp1.jst.mfeed.ad.jp', 'ntp2.jst.mfeed.ad.jp', 'ntp3.jst.mfeed.ad.jp' ]
  })
end
:ntp_serversに配列を渡しています。

そしてテンプレートは下記の様にします。
<% @ntp_servers.each do |ntp_server| %>
server <%= ntp_server %>
<% end %>
テンプレート側では@ntp_serversに格納された配列の中身を順番に処理して出力します。

ここで先程と同じく<%= %>で囲まれた部分に加え、<% %>で囲まれた部分が出てきました。
先程は触れませんでしたが、<%= %>の場合は、埋め込んだrubyコードの返り値を出力し、<% %>の場合は出力しないという違いがあります。
@ntp_servers.each do |ntp_server| と end の部分は単にループを制御するだけのコードのため、何かを出力する必要が無いので<% %>で囲います。
ntp_serverの部分は出力する必要があるので<%= %>で囲います。

レシピ側にも普通にrubyのコードが書けるので、逆に次のような書き方もあります。
まずテンプレートはこうします。
<%= @ntp_servers %>

そしてレシピはこうします。
template "/etc/ntp.conf" do
  source "etc/ntp.conf.erb"
  notifies :restart, "service[ntpd]"
  action :create

  servers = []
  for num in 1..3 do
    servers.push( "server ntp" + num.to_s + ".jst.mfeed.ad.jp" )
  end

  variables({
    :ntp_servers => servers.join( "\n" )
  })
end
複雑な処理をテンプレート側に集めてしまうと見栄えが悪くなると同時に設定ファイル自体の見通しが悪くなってしまいますので、このようにレシピ側に集めるという考え方もあるかと思います。
このあたりはどちらも一長一短ですので、自分のスタイルに合わせて行えば良いと思います。

そもそも設定ファイルのテンプレートでそんなに複雑な処理を必要とするケースがあるかどうかは分かりませんが・・・




  • 最終更新:2016-01-19 12:30:17

このWIKIを編集するにはパスワード入力が必要です

認証パスワード