Puppet4.xではじめるサーバ設定自動化の、ファイル変更編です。
全体的な目次は、ここを参照してください。
主にCentOS 7を例に紹介しているので、その他OSについては読み替えてください。
※記載されている例は、その内容に関わる部分のみ記載しています。なので実際試す場合、親ディレクトリ作成、httpdインストールを別途行う必要があります。
ファイル変更
基本
ファイルを変更する場合、Puppetのマニフェストでfileリソースで定義します。
/tmp/hello_puppet.txtを変更する場合の例です。指定のパスにファイルがない場合は、ファイルが作成されます。
file { '/tmp/hello_puppet.txt':
ensure => "file",
owner => "root",
group => "root",
mode => "0644",
content => "hello puppet\n",
}
- fileの右側のタイトルに、ファイルのパスを指定
- ensure属性に、fileを指定
- owner属性に、ファイルの所有ユーザを指定
- group属性に、ファイルの所有グループを指定
- mode属性に、ファイルのパーミッッション(アクセス権限)を指定
- content属性に、ファイルの中身を指定。
ファイル変更の場合、ensure属性は必須でないですが、ensure属性にfileを指定します。なお、ensure属性にabsentを指定すると、ファイルの削除ができます。ただ、ファイル削除する場合は慎重に。
**content属性は、ファイルの中身です。**ファイルの中身が数行程度であれば、上記例のように直接記載することもできます。
テンプレートファイルで置き換える
あらかじめ用意したファイルに置き換える場合、テンプレートとなるファイルをcontent属性に指定します。
file { "/etc/httpd/conf/httpd.conf":
ensure => "file",
owner => "root",
group => "root",
mode => "0644",
content => template("apache/httpd.conf.erb"),
}
content属性に、ファイルの中身を直接記載せず、template関数(template())にテンプレートにするファイルのパスを指定します。拡張子erbが付いている理由は次回。例のfile02.ppを実行する場合、テンプレートにするファイルを次のように配置します。
.
|-- file02.pp
`-- modules
`-- apache
`-- templates
`-- httpd.conf.erb
※puppet applyの場合のディレクトリ構成
下記コマンドで実行します。※Puppetだと、テンプレートファイルと同じ内容のファイルがすでに指定のパスにある場合、ファイルは変更されません。
/opt/puppetlabs/bin/puppet apply file02.pp --modulepath=modules -t
**modulepathオプションで、どこにテンプレートファイルを置いてあるか指定します。**例では、カレントディレクトリのmodulesディレクトリの下にテンプレートファイルがあるので、modulesを相対パスで指定してます。ちなみに、絶対パスでもよいです。
テンプレートファイルの置き場所は、ちょっとわかりにくいですが、modulepathオプションで指定するディレクトリの下に、モジュール名のディレクトリがあって、さらにその下にtemplatesディレクトリがあって、さらにその下にテンプレートファイルがあるイメージです。
(※modulesディレクトリの2個下に、templatesという名前のディレクトリがあるのが必須で、それより下のディレクトリ構成は自由です。)
テンプレートファイルをサーバごとに変える
同じマニフェストファイルを実行して、サーバごとに配布する設定ファイルを変えたい場合、content属性のtemplate関数に渡すパスを変えることで実現できます。
# (1)
$httpd_tmpl = $hostname ? {
"web01" => "apache/web01/httpd.conf.erb",
/^web.*/ => "apache/web/httpd.conf.erb",
default => "apache/default/httpd.conf.erb",
}
# (2)
file { "/etc/httpd/conf/httpd.conf":
ensure => "file",
owner => "root",
group => "root",
mode => "0644",
content => template($httpd_tmpl),
}
この例では、(1)でサーバのホスト名を条件に、テンプレートファイルのパスを指定しています。ホスト名が、
- web01の場合、apache/web01/httpd.conf.erb
- 正規表現/^web.*/に一致する場合、apache/web/httpd.conf.erb
- どれにも当てはまらない場合、apache/default/httpd.conf.erb
としています。(2)のcontentに、(1)で決まったテンプレートのパスを設定しています。なお、file03.ppを実行する場合、次のようなディレクトリ構成で、ファイルを用意しておきます。
.
|-- file03.pp
`-- modules
`-- apache
`-- templates
|-- default
| `-- httpd.conf.erb
|-- web
| `-- httpd.conf.erb
`-- web01
`-- httpd.conf.erb
※puppet applyの場合のディレクトリ構成
ファイル変更前にシンタックスチェックする
ファイル変更前にシンタックスチェックをしたい場合、validate_cmd属性にシンタックスチェック用コマンドを指定します。チェック用コマンドは、問題がない場合に0を返すコマンドを指定します。シンタックスチェックで問題があった場合、ファイル置き換え前にエラーになります。ちなみにドライランのnoopだと、残念ながらエラーになりません。
httpd.confのチェックをする場合の例です。チェックコマンドは、CentOS7の場合です。
file { "/etc/httpd/conf/httpd.conf":
ensure => "file",
owner => "root",
group => "root",
mode => "0644",
content => template("apache/httpd.conf.erb"),
validate_cmd => "/usr/sbin/httpd -t -f %",
}
validate_cmd属性のコマンドの%は、コマンド実行時に配布するファイル名に置き換えられます。なお、コマンドは、フルパスで記載が必要です。validate_cmd属性は、puppet3.5以降で対応しています。
配布前にシンタックスチェックする機能は、設定ファイル変更直後に自動でリロードするようなミドルウェアなどで役立ちます。配布時チェックすることで、シンタックスエラーによるサービス影響を防げます。
実際に、シンタックスエラー時のログ例の一部です。
Error: Execution of '/usr/sbin/httpd -t -f /etc/httpd/conf/httpd.conf20160502-229-11sah4d' returned 1: AH00526: Syntax error on line 103 of /etc/httpd/conf/httpd.conf20160502-229-11sah4d:
<Directory> directive missing closing '>'
Error: /Stage[main]/Main/File[/etc/httpd/conf/httpd.conf]/content: change from {md5}f5e7449c0f17bc856e86011cb5d152ba to {md5}3cd7eaeebfd2554f9d26c0fcd5031a9d failed: Execution of '/usr/sbin/httpd -t -f /etc/httpd/conf/httpd.conf20160502-229-11sah4d' returned 1: AH00526: Syntax error on line 103 of /etc/httpd/conf/httpd.conf20160502-229-11sah4d:
<Directory> directive missing closing '>'
XMLのvalidate_cmd
参考までに、XML用のチェックコマンド例です。Rubyで正常に読めるかで判定しています。
file { "/tmp/puppet_sample.xml":
ensure => "file",
owner => "root",
group => "root",
mode => "0644",
content => template("sample/puppet_sample.xml.erb"),
validate_cmd => "/opt/puppetlabs/puppet/bin/ruby -e \"require 'rexml/document'; REXML::Document.new(open('%'))\"",
}
YAMLのvalidate_cmd
参考までに、YAML用のチェックコマンド例です。Rubyで正常に読めるかで判定しています。
file { "/tmp/puppet_sample.yaml":
ensure => "file",
owner => "root",
group => "root",
mode => "0644",
content => template("sample/puppet_sample.yaml.erb"),
validate_cmd => "/opt/puppetlabs/puppet/bin/ruby -e \"require 'yaml'; YAML.load_file('%')\"",
}
バイナリーファイルを配布する
バイナリーファイルを配布する場合、配布するバイナリーファイルをsource属性に指定します。
file { "/opt/gitbucket/4.0/gitbucket.war":
ensure => "file",
owner => "root",
group => "root",
mode => "0644",
source => "puppet:///modules/gitbucket/gitbucket.war",
}
source属性に、配布するバイナリーファイルのパスを指定します。template関数の指定と違って、puppet:///modulesがつくのに注意です。file07.ppを実行する場合、配布するファイルを次のように配置ます。
.
|-- file07.pp
`-- modules
`-- gitbucket
`-- files
`-- gitbucket.war
※puppet applyの場合のディレクトリ構成
下記コマンドで実行します。
/opt/puppetlabs/bin/puppet apply file07.pp --modulepath=modules -t
**modulepathオプションで、どこにバイナリーファイルが置いてあるか指定します。**例では、カレントディレクトリのmodulesディレクトリの下にバイナリーファイルがあるので、modulesを相対パスで指定してます。ちなみに、絶対パスでもよいです。
バイナリーファイルの置き場所は、ちょっとわかりにくいですが、modulepathオプションで指定するディレクトリの下に、モジュール名のディレクトリがあって、さらにその下にfilesディレクトリがあって、さらにその下にバイナリーファイルがあるイメージです。
(※modulesディレクトリの2個下に、filesという名前のディレクトリがあるのが必須で、それより下のディレクトリ構成は自由です。)
ファイルをwebから取得する
Puppet 4.4.0から、fileリソースで直接HTTP,HTTPS経由のファイル取得ができるようになりました。source属性に、対象のURLを記載します。
file { "/opt/pssh/pssh-2.3.1.tar.gz":
ensure => "file",
owner => "root",
group => "root",
mode => "0644",
source => "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/parallel-ssh/pssh-2.3.1.tar.gz",
}
ただし、直接ダウンロードできない場合(※接続先で、302リダイレクトされるとダメ?)もあるようなので、うまくいかない場合は、execリソースのwgetコマンドで代用します。
次の例では、creates属性で配布先にファイルがないことをチェックしてから、commandのwgetコマンドを実行しています。もし、ダウンロードに時間がかかりそうな場合、timeout属性でタイムアウトを十分長い時間に設定しておきます。デフォルト300秒を、例では600秒に変更。timeout属性を0に設定すると、タイムアウトしない設定になります。
exec { "wget gitbucket.war":
command => "wget https://github.com/gitbucket/gitbucket/releases/download/4.0/gitbucket.war -P /opt/gitbucket/4.0",
creates => "/opt/gitbucket/4.0/gitbucket.war",
path => "/usr/bin",
timeout => "600",
}
ファイルがすでにある場合変更しない
すでにファイルがあった場合に、ファイルの中身を変更したくないときは、replace属性にfalseを指定します。ファイルがないときだけ、ファイルを作りたい場合に使います。
file { '/tmp/hello_puppet.txt':
ensure => "file",
owner => "root",
group => "root",
mode => "0644",
content => "hello puppet\n",
replace => "false",
}
参考
fileリソースの詳しい情報は、下記参照です。
テンプレートファイルをサーバごとに分岐させている部分は、下記参照です。