Table of Contents
Vagrantでknife-zeroを試そうとして挫折する人が多いらしいので、自分の考えるベストプラクティスを書いてみます。
追記:記事の一部を更新しました。詳細は末尾の更新履歴でご確認ください。
以下、Vagrantを開発環境で利用することを想定しています。
下記のドキュメントを参考にしました。
TL;DR
プライベートネットワークモードで立ち上げた2つのVMに、knife-zeroでレシピを適用する具体的な手順を説明します。
基本方針は下記の通り。
- コマンドラインでのパラメータを極力減らす。
- IPアドレスの記述は.envrcに集約して、その他の設定ファイルやコマンドラインでは環境変数を使う。
適切に設定ファイルを書けば、下記のような一連のコマンドでレシピの適用まで実行することができます。
% cd knife_zero_example
% direnv allow
% vagrant up
% bundle install --path=vendor/bundle --binstubs
% ./bin/berks vendor cookbooks
% ./bin/knife zero bootstrap $VAGRANT_HOST001
% ./bin/knife zero bootstrap $VAGRANT_HOST002
% ./bin/knife node run_list set host001.example build-essential
% ./bin/knife node run_list set host002.example build-essential
% ./bin/knife zero converge 'name:*.example' -a knife_zero.host
概要
動作確認環境
- Yosemite 10.10.5
- Vagrant 1.7.4
- VirtualBox 5.0.0
- ruby 2.2.3
- chef 12.4.1
- knife-zero 1.8.0
- berkshelf 3.3.0
- direnv 2.6.0
- CentOS 7.1(VM on VirtualBox)
目標
- vagrantで2台のVM(CentOS 7.1)をセットアップ
- プライベートネットワークで互いに疎通
- 2台のVMにコミュニティクックブックの build-essential を適用
VMのホスト名とIPアドレスは下記とします。
hostname | ip address |
---|---|
host001.example | 192.168.33.10 |
host002.example | 192.168.33.11 |
ネットワークアドレスは、VBoxManage list hostonlyifs
コマンドでVirtualBoxのホストオンリーネットワークのアドレスを確認して、そのレンジのアドレスを設定するようにしてください。
普通にVirtualBoxをインストールすると下記のような出力になると思います。
% VBoxManage list hostonlyifs
Name: vboxnet0
GUID: 786f6276-656e-4074-8000-0a0027000000
DHCP: Disabled
IPAddress: 192.168.33.1
NetworkMask: 255.255.255.0
IPV6Address:
IPV6NetworkMaskPrefixLength: 0
HardwareAddress: 0a:00:27:00:00:00
MediumType: Ethernet
Status: Up
VBoxNetworkName: HostInterfaceNetworking-vboxnet0
この場合、192.168.33.0/24
のレンジでアドレスを設定する必要があります。
手順
VMのアドレスを環境変数に設定(.envrc)
VMのIPアドレスを環境変数に設定します。 これらの環境変数はdirenvで自動的にロード・アンロードするようにします。
% mkdir knife_zero_example
% cd knife_zero_example
% cat <<EOF > .envrc
export VAGRANT_HOST001=192.168.33.10
export VAGRANT_HOST002=192.168.33.11
EOF
% direnv allow
direnvがない場合は直接読み込んでもよいです。
% source ~/.envrc
Vagrantfileの作成
% cat <<EOF> Vagrantfile
Vagrant.configure(2) do |config|
config.vm.box = "bento/centos-7.1"
config.vm.define :host001 do |host|
host.vm.hostname = "host001.example"
host.vm.network "private_network", ip: ENV['VAGRANT_HOST001']
end
config.vm.define :host002 do |host|
host.vm.hostname = "host002.example"
host.vm.network "private_network", ip: ENV['VAGRANT_HOST002']
end
# VMにログインする鍵を固定
config.ssh.insert_key = false
end
EOF
~/.ssh/config の設定変更
~/.ssh/config
に下記のエントリを追加します。
% cat <<EOF>> ~/.ssh/config
# Vagrant private network ip
Host 192.168.33.*
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
LogLevel FATAL
User vagrant
IdentityFile ~/.vagrant.d/insecure_private_key
EOF
vagrantで使うプライベートネットワークでのデフォルトのログインユーザをvagrantにし、鍵をデフォルトのものに固定します。
IdentityFileは、もしもVAGRANT_HOME環境変数を設定している場合には、その下のinsecure_private_keyファイルのパスに変更してください。
VMの立ち上げと疎通確認
VMを立ち上げて、ログインできるか確認して下さい。
% vagrant up
% ssh $VAGRANT_HOST001 hostname
host001.example
% ssh $VAGRANT_HOST002 hostname
host002.example
knife-zeroとberkshelfのインストール
knife-zeroとberkshelfをインストールします。
% cat <<EOF> Gemfile
source "https://rubygems.org"
gem "knife-zero"
gem "berkshelf"
EOF
% bundle install --path=vendor/bundle --binstubs
knifeコマンドのオプション引数を省略するために、.chef/knife.rb
を作成します。
% mkdir -p .chef
% cat <<EOF> .chef/knife.rb
# -z, --local-mode
local_mode true
# -x vagrant, --ssh-user vagrant
knife[:ssh_user] = "vagrant"
# --sudo
knife[:use_sudo] = true
EOF
knife.rb
のその他の設定は下記のドキュメントを参照してください。
knife.rb Optional Settings — Chef Docs
今回はknife-zeroの利用例として、コミュニティクックブックのbuild-essentialを2つのVMにインストールします。
このコミュニティクックブックを使うための設定をします。
% cat <<EOF> Berksfile
source "https://supermarket.chef.io"
cookbook "build-essential"
EOF
% ./bin/berks vendor cookbooks
ノードの初期設定
knife-zeroを使って、VMにchefをインストールするとともに、ノードとしてchef-zeroサーバに登録します。
% ./bin/knife zero bootstrap $VAGRANT_HOST001
% ./bin/knife zero bootstrap $VAGRANT_HOST002
nodes/
ディレクトリとclients/
ディレクトリ以下にそれぞれjsonファイルができていることを確認して下さい。
また、knife node list
コマンドを実行して、登録したVMのホスト名が表示されることを確認して下さい。
% ./bin/knife node list
host001.example
host002.example
レシピの適用
各ノードのrun_listにbuild-essentialレシピを追加します。
% ./bin/knife node run_list set host001.example build-essential
host001.example:
run_list: recipe[build-essential]
% ./bin/knife node run_list set host002.example build-essential
host002.example:
run_list: recipe[build-essential]
次に各ノードへレシピを適用します。
knife-soloではノードにレシピを適用するとき、knife solo cook FQDN
でホストを一つ指定します。
knife-zeroでは、knife solo cook FQDN
に相当するコマンドはknife zero converge QUERY
です。
QUERYで指定した条件にマッチするすべてのホストに対して並列にsshログインし、chef-client
を実行してレシピを適用します。
knife zero converge QUERY
では、対象のノードにsshでログインするためのIPアドレスをノード情報のAttribute名で指定する必要があります(-a
オプション)。
このAttributeは通常ipaddress
で良く、その場合は省略できます。
ただし、Vagrant + VirtualBoxのprivate_networkでIPアドレスを固定したVMにknife zero bootstrap
した場合、
ノードのAttributeとして記録されるipaddress
は、Vagrantfileで指定したアドレス192.168.33.*
ではなく、
10.0.2.*
のように異なるネットワークのアドレスになっているはずです。(さらにおそらくアドレス自体が同じ)
% ./bin/knife search node -a ipaddress
2 items found
host001.example:
ipaddress: 10.0.2.15
host002.example:
ipaddress: 10.0.2.15
knife-zeroのバージョン1.8.0以降であれば、bootstrap時にknife_zero.host
というAttributeに接続時のアドレスが記録されます。
% ./bin/knife search node -a knife_zero.host
2 items found
host001.example:
knife_zero.host: 192.168.33.10
host002.example:
knife_zero.host: 192.168.33.11
なので下記のようにknife_zero.host
を指定すればレシピを適用できます。
% ./bin/knife zero converge 'name:*' -a knife_zero.host
'name:*'
はクエリ文字列で、この例ではすべてのノードを対象にしています。
クエリの構造は knife search
と同様です。
# host001だけを指定
% ./bin/knife search node 'name:host001.example'
# exampleドメインに一致するホストだけを指定
% ./bin/knife search node 'name:*.example'
また、クエリ指定でsshログインして任意のコマンドを実行することもできます。
% ./bin/knife ssh 'name:*' -a knife_zero.host 'sudo yum update -y'
補足
ノード情報の保存先
knife exec
やknife node edit
で変更した情報は nodes/*.json
に保存されています。
これは本質的にはknife-solo(chef-solo)で書くものと同じなのですが、knife-zero(chef-zero)では非常に分量が多いです。
これについては、.chef/knife.rb
にAttributeのホワイトリストを書くことで制御できます。
chef-zero - Knife-Zeroで管理するnodeオブジェクトを任意のattributesに限定する - Qiita
Attributeのタイプ
knife exec
でnormalを指定していますが、chefのAttributeには他にもdefaultやoverrideなどの種類があります。
defaultで記録してしまうと、次にconvergeしたタイミングで消えるので注意してください。normalであればconvergeでは消えません。
優先順位は複雑なので公式のドキュメントを参照してください。
サンプルコード
設定ファイル一式まとめたものを下記に置きました。
https://github.com/kwhrtsk/knife_zero_example
knife-zero 1.7.1以前(蛇足)
knife_zero.host
にbootstrapで接続した時のIPアドレスが記録されるようになったのはknife-zero 1.8.0からです。
それ以前は knife node edit
でjsonファイルを編集するか、下記のようにknife exec
で接続用のアドレスを追加する必要がありました。
% ./bin/knife exec -E "search(:node, 'hostname:host001'){|n| n.normal['chef_ip'] = ENV['VAGRANT_HOST001']; n.save}"
% ./bin/knife exec -E "search(:node, 'hostname:host002'){|n| n.normal['chef_ip'] = ENV['VAGRANT_HOST002']; n.save}"
# 設定されているか確認
% ./bin/knife search node 'hostname:*' -a chef_ip
2 items found
host001.example:
chef_ip: 192.168.33.10
host002.example:
chef_ip: 192.168.33.11
knife exec
でどのようなことができるかは、下記のドキュメントが参考になります。
更新履歴
- 2015-08-27
- 本記事の内容が開発環境での利用を想定したものであることを追記
- knife-zefo 1.8.0で追加された機能に対応
- 2015-08-28
- サンプルのVagrantfileに書いたboxを変更(跡地)
chef/centos-7.1 => bento/centos-7.1
- サンプルのVagrantfileに書いたboxを変更(跡地)