こんにちは、sunflatです。 今期のアニメは、とんかつDJアゲ太郎と宇宙パトロールルル子が好きです。
今回は、リモートのサーバーを設定するためのツールである Knife-Zero を使った時に、つまづいた点とその解決策をまとめてみました。
Knife-Zero とは
Misocaでは、サーバーの設定の自動化にChefを使っています。
Chefのレシピ(設定手順をコードで書いたもの)をリモートのノードに適用するためのツールとして、Misocaでは以前から knife-solo を使っていました。しかし、knife-soloが使っているChefの機能であるChef Soloが非推奨となったことなどから、代わりにKnife-Zeroを使うことを計画しています。 *1
Knife-Zero を使った時につまづいた点とその解決策
その1. ノードファイルに色々書き込まれる
knife-solo では、ノードオブジェクトの json ファイル(nodesディレクトリにあるもの。以下ノードファイルと呼ぶ)は、以下のように、ノード固有の属性(例: set_fqdn)とrun_listのみを書いておく感じでした。レシピを適用(knife-solo cook
)しても、ノードファイルは変化しません。
{ "set_fqdn": "hoge.example.com", "run_list": [ 〜 ] }
一方 Knife-Zero では、レシピを適応(knife-zero converge
)した時に、ノードの全ての属性がノードファイルに保存されます。*2
しかし、自動取得された動的なシステム情報などの属性も(かなり大量に)書き込まれてしまうため、ノードファイルをGit等でバージョン管理したい場合には不都合です。
解決策
.chef/knife.rb
にホワイトリストを設定しておけば、指定した属性のみが保存されるようになります(参考)。knife[:automatic_attribute_whitelist]
の場合、自動収集された属性(automatic属性)がホワイトリストの対象となります。
以下は、automatic属性のうち fqdn, hostname, chef_package.chef.version のみをノードファイルの保存する場合の、.chef/knife.rb
の設定例です。
local_mode true cookbook_path ['berks-cookbooks', 'site-cookbooks'] # ホワイトリストの設定 knife[:automatic_attribute_whitelist] = %w( fqdn/ hostname/ chef_packages/chef/version/ )
なお、ノードファイルに保存された default
と automatic
以下の属性は、次回のレシピ適用時には破棄されて使われません(ただし、automatic
のfqdn
属性のみ、Knife-Zero がレシピ適用時のsshの接続先として使う)。
ノード固有の属性を設定したい場合は、以下のようにノードファイルの normal
以下に書けば、レシピ適用時に使用されます。(About Attributes の Attributes Type を参考)
{ "normal": { "set_fqdn": "hoge.example.com" }, "run_list": [ 〜 ], }
また、ノードファイルを編集する時には、直接jsonファイルを編集するのではなく、以下のようにknifeコマンドで編集すれば、永続的な属性のみが表示されますし、保存時にバリデーションもしてくれます。 *3
knife node edit -z hoge.example.com
その2. ホワイトリストが有効にならない
その1の解決策でホワイトリストを設定する方法を紹介しましたが、最初はホワイトリストを定義してもそれが反映されず、原因究明に時間がかかりました。
結局、設定先のノードに古いバージョンのChefが入っていて、それがそのまま使われていたのが原因でした。動作確認にVagrantを使ったのですが、Ubuntu14.04のVagrant用イメージには古いバージョンのChefがプレインストールされています。
設定先のノードにChefをインストールするために knife zero bootstrap
コマンドを利用できますが、設定先のノードにChefが既にインストールされている場合は、(古いバージョンだったとしても)Chefのインストールは行われません。
解決策
knife zero bootstrap
を実行する前に古いバージョンのChefを予めアンインストールしておきましょう。VagrantのイメージにはChefが入っていることが多いので、自分で入れた覚えがなくても要注意です。
その3. FQDNがノード名として使われる
デフォルトでは、設定先ノードのFQDN(ドメイン名込みのホスト名)が、ノード名(ノードファイルのファイル名)やレシピ適用時のsshの接続先として使われます。このため、ノードのFQDNやその名前解決を設定する前の状態だと、ノードファイルのファイル名が意図しないものとなったり、レシピ適用時にsshで接続できなかったりして困ります。
解決策
knife zero bootstrap
を使って設定先にChefをインストールする時に、以下のように -N
オプションをつければ、設定先ノードのFQDNとは別の名前をノード名として使うことができます。*4
knife zero bootstrap [sshの接続先(IPアドレスなど)] -N [ノード名] ※必要に応じて、-x(sshのユーザ名)や、 --sudo(sudo権限で実行)などのオプションも付加
また、knife zero converge
を使ってレシピを適用する時には、-a
オプションをつけると、sshの接続先として使う属性(ノードファイルに保存された属性の名前)を変更できます。デフォルトでは fqdn
(ノードのFQDN)が使われますが、これを knife_zero.host
(knife zero bootstrap
実行時に使った接続先。ノードファイルにnormal属性として保存されている)に変更すれば、ノードのFQDNやその名前解決を設定する前の状態でも、レシピ適用時にsshで接続できるようになります。
knife zero converge -a knife_zero.host -x [sshのユーザ名] "name:[ノード名]" ※必要に応じて、-x(sshのユーザ名)などのオプションも付加
その4. デバッグ実行したい
Rubyでレシピを書いていると、pry-byebug などを使ってデバック実行をしたくなることがあります。レシピの中で
require 'pry' binding.pry
などと書けば停止はするのですが、 Knife-Zeroだとキー入力が伝わらないようなので、デバック実行中の操作ができなくて困りました。
解決策
(もはや Knife-Zeroを使っていないですが)設定先のノードにレシピを転送して、Chef Client Local Mode を使ってローカル環境にレシピを適用すればデバッグ実行できました。
.chef/knife.rb では、cookbook_path をフルパスで指定する必要があるようです(参考)。*5
chef_repo = File.join(File.dirname(__FILE__), "..") cookbook_path ["#{chef_repo}/berks-cookbooks", "#{chef_repo}/site-cookbooks"]
rsync などで chef-repo(レシピが含まれているリポジトリ)を設定先のノードへ転送し、設定先ノードのchef-repoのディレクトリ上で、以下のように Chef Client を Local Mode で起動します。
sudo chef-client -z
これで、普通にpry-byebugを使ったデバック実行が出来ました。
まとめ
今回は、Knife-Zero を使った時に、つまづいた点とその解決策を紹介しました。 Knife-Zero はまだ色々と試している段階ですが、今後のMisocaのサーバ運用に活用していきたいと思います。
*1:公式blog記事 https://www.chef.io/blog/2014/06/24/from-solo-to-zero-migrating-to-chef-client-local-mode/ などで、Chef Solo の代わりに Chef Client Local Mode(Chef Zero)を使うようにアナウンスされています。 そこで、Chef Client Local Mode を使ってレシピをリモートのノードに適用するためのツールであるKnife-Zeroを、knife-soloの代わりに使うことにしました。
*2:Chefは、ノードの設定だけでなく、ノードの状態を管理するツールでもあり、特定の状態を持ったノードを検索(サーチ機能)したりする時にこれらの保存した属性を使うことができます。
*3: .chef/knife.rb に local_mode true を書いておけば、-z オプションは省略できます
*4:ノード名には、将来割りあてる予定のFQDNを指定しておくと良いです。
*5:追記: chef_client用のホワイトリストを設定する場合は knife[:automatic_attribute_whitelist] ではなく automatic_attribute_whitelist というDSLで書きます。