Chefの概要
- Chefは、サーバやミドル、アプリの導入を自動化するツール
- 言語はRuby
- Cookbook・・・複数のレシピと属性ファイルから成る
- Recipe・・・ サーバを構築する上での具体的な処理
Concept
Infrasttucture as code
- インフラの構成管理をコードで行う。
冪等制
- ある操作を何度行っても、結果は同じである
構成
Client/Server
- 集中管理方式。
- ServerにはCookbook,Recipe,Attribute,Databagなどが格納されている。
- ClinetにはKnifeと呼ばれるプラグインがインストールされている。 -メリット:インフラ全体の確認がしやすいこと。 デメリット:導入・運用が、若干手間がかかること。
Solo
- スタンドアロン方式。
- メリット:導入が簡単。Ched Soloなど必要なものを一括で準備するだけ。
- デメリット:インフラ全体の確認、各ノードの連携は自前でやらなくてはいけない。
環境構築
Linux環境で実施するのが一般的ではあると思うが、ちゃんとWindows用のインストーラーが用意されている&今回の開発要件がWindowsであるため、Windows環境にインストールする。
CHEFの基本的なフォルダ構成
C:
├ chef
│ ├ cookbooks ・・・共通の処理(cookbook)を定義。INTAFRMで言うとSkeltonに近い。
│ │ │ インターネット上から取得したり、自作して汎用性があるものはここに格納される。
│ │ │
│ │ └ [cookbook(任意の名前)] ・・・共通処理の格納フォルダ。処理毎にフォルダを作成する。
│ │ │
│ │ ├ files ・・・内部用のリソースファイルの格納フォルダ。ISOイメージファイルやインストーラーを格納。
│ │ │
│ │ ├ providers
│ │ │ └ 個別Provider.rb ・・・処理の定義ファイル。クラスのようなイメージ。
│ │ │ 1クラスに複数アクションを定義し、さらに1つのアクションに対して複数メソッドを含んでいる。
│ │ │
│ │ ├ recipes
│ │ │ └ default.rb ・・・Provier呼び出し時に共通で呼び出されるRecipe。
│ │ │
│ │ ├ resources
│ │ │ └ 個別resource.rb ・・・Providerの変数を定義するファイル。ファイル名はprovidersと同じになる。
│ │ │
│ │ └ templates ・・・内部用ファイルの格納フォルダ。web.configなどのテンプレートを置く。
│ │
│ ├ data_bugs ・・・全Cookbook共通データの格納フォルダ。ドメインデータが格納される。
│ │ │
│ │ └ settings
│ │ └ common.json
│ │
│ │
│ └ site-cookbooks ・・・PJ個別の処理を定義。INTAFRMで言うとModelに近い。自分で作る。
│ │
│ └ [projectName] ・・・PJ資産の格納フォルダ。
│ │
│ ├ attributes ・・・設定ファイルの格納場所。
│ │ └ default.rb ・・・初期設定ファイル。PJ固有の変数等をここに定義する。
│ │
│ ├ libraries ・・・ライブラリの格納場所。
│ │
│ ├ recipes
│ │ └ 個別Recipe.rb ・・・作成したRecipe。Main()にあたる箇所で、ここから各provider(メソッド)を呼び出す。
│ │
│ └ templates ・・・内部用ファイルの格納フォルダ。web.configなどのテンプレートを置く。
│
└ opscode ・・・Windows版のChefモジュールの格納場所。
├
実行イメージ
Chefの文法
(1) attribute
# comment
default["HostName or PjName"]["businesscommon"]["cookbook名"]["パラメータ名"]='文字列'
default["HostName or PjName"]["businesscommon"]["cookbook名"]["パラメータ名"]=100
(2) resource
# Recipeからパラメータを受け取り、providerのアクションを呼び出す
# 対応するproviderに定義されているactionを定義
actions :install, :setup, :add, :changepassword
default_action :install
# パラメータの型、初期値等を定義
attribute :serverip, :required => true, kind_of => String
attribute :portno, :default => 80, kind_of => Integer
attribute :dbtype, kind_of: String, equal_to: ["SQLServer", "Symfoware"], default: "Symfoware"
(3) recipe
# 変数宣言
hoge = node["hostName"]["variableName"]["attributeに定義しているパラメータ名"]
serverip = node["TSM"]["businesscommon"]["ip"]
portno = node["TSM"]["businesscommon"]["portno"]
dbtype = node["TSM"]["businesscommon"]["dbtype"]
# リソースファイルの呼び出し
cookbook名_resource名 "任意の名前" do
# resourceにパラメータを渡す
serverip "#{serverip}"
portno "#{portno}"
dbtype "#{dbtype}"
# resource呼び出し時のアクションを指定
action :install
end
(4) provider
# アクションごとに定義する
action :install do
# 変数の宣言
dirpath = "C:\\test"
{Resourceタイプ} "Resource名(任意)" do
# (1) 実行条件
{only_if | not_if} {{条件文}} # 条件文はRubyで記載
# (2) アクション
action :{アクション名} # Resourceタイプ毎のアクションを指定
# (3) Notifications(通知)
# notifies :該当のResourceが実行された際に他のResourceに通知してResourceの実行を促す。
# subscribes:notifiesと逆で、他のResourceの実行終了後に該当ResourceのActionを指定して実行する。
{notifies|subscribes} :action, "{Resourceタイプ[Resource名]}", {:immediately|:delayed}
# (4) Attribute
{attribute} "value" # Resourceタイプ毎のAttributeを指定
end
powershell_script "任意の名前" do
action :run
code <<-EOH
cd #{dirpath}
[実行するpowershellコマンドを記述する]
EOH
end
end
上の例では「powershell_script」のリソースタイプを示しているが、実際には多くのリソースタイプが存在する。
一覧については公式ページのResourcesを参照すること。
開発環境
ChefというよりRubyの開発環境について。エディタ(notepad++、Terapad、Vim)、IDE(Eclipse、AptanaStudio)等、いくつか選択肢は考えられる。それぞれメリットデメリットはあるが詳細については割愛。個人的にはNetBeans+プラグインが一番扱いやすそうと感じた。まだ試してはいないが。
NetBeansとRuby Plugin
Chefの静的解析
- foodcritic(料理評論家)というlintツールを導入することで、約30程度のルールに沿って診断が可能。導入にあたっては、事前にRubyとRubyのDevKitのインストールが必要。
foodcriticでChefのcookbookの書き方をチェックする方法 - エラーの一覧と修正方法についてはこちらを参照。
用語集
DSL(Domain Specific Language)
和訳すると「ドメイン特化言語」。Puppetは独自の言語で記述(外部DSL)していくのに対し、ChefはRubyを独自に拡張した言語で記述(内部DSL)する。
LWRPs(LightWeight Resources/Providers)
Chefで定義済みのResource(package,template,etc)以外に独自のResourceTypeを定義するための仕組み。LWRPsはResourceとProviderから構成される。
Conding Knowleage
● Script、Command内でchef内の変数はダブルクォーテーションで囲む。
変数でよくインストールパス等を指定するが、空文字等が含まれると引数の数が変わってよく落ちる。Script、Command内では基本的にはダブルクォーテーションで囲むように心掛ける。
execute 'ASP.NET service register' do
command <<-EOH
# #{***}で書かれているchefの変数は、常に""で囲むように心掛ける。
if not %PROCESSOR_ARCHITECTURE%=="x86" ("#{aspnetRegiisExePath}" -i) else ("#{aspnet64RegiisExePath}" -i)
EOH
end
● Recipeから呼ばれるbatchは、内部でダブルクォーテーション対策をする。
Recipeからbatchを起動する際、上記のように引数をダブルクォーテーションで括って渡すが、そうすると受け取るbatch側はダブルクォーテーションが入った状態で引数を受け取る。処理として問題なければそれで良いが、batch内で再度ダブルクォーテーションで囲む必要がある場合は、一度引数を~(チルダ)で受け取るとダブルクォーテーションがない状態で受け取る事ができる。
rem チルダをつけると囲んでいる二重引用符がある場合はそれを取り除く
SET DRIVELETTER=%~1
● batchの実行はcdしてから
batchを実行する際に内部で相対パスを指定していると、呼ばれるbatchのカレントはchefのディレクトリになっているため失敗する。この問題を解決するには、一度カレントをbatchファイルが格納されている場所に変更してから処理を実行する。
batch 'call _Setup_System.SQL' do
codetemp = <<-EOH
cd "#{targetdir}PRONESDemo\\Setup\\DBSetup"
"#{sqldir}execSqlPlus.bat" "#{user}" "#{userpwd}" "#{connect}" _Setup_System.SQL
EOH
code codetemp.encode('Windows-31J','utf-8')
end
● 日本語が入る可能性がある場合は必ずエンコードする
rubyで上手く日本語が扱えないため、日本語が入る場合は必ずエンコードを実施する。
log 'PRONES Demo System Install command.' do
msgtemp =<<-EOH
msiexec /i "#{installerPath}" /passive /norestart TARGETDIR="#{targetdir}" ALLUSERS=""
EOH
message msgtemp.encode('Windows-31J','utf-8')
level :info
end