CentOSにchef-zeroのインストール

chef-zeroとは

chef-zero とは、Chef 11 Server 同等の REST API インターフェースを備えた軽量で簡易な Chef Server です。認証やデータの永続的な保存などを行わない代わりに導入が大変簡単で、Chef Clientなどのテストに有用です。 とのこと。

chef-zeroのインストール

chef-zeroが依存するGemにはRuby拡張をビルドするものがあるため、Development Toolsパッケージグループとruby-develパッケージ、openssl-develパッケージをインストールしておきます。

$ sudo yum groupinstall "Development Tools"
$ sudo yum install ruby-devel openssl-devel

gemが入っていない場合にはインストールします。

$ yum install rubygems
$ ruby -v                  
ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]

chef-zeroのインストールを行います。

$ sudo gem install chef-zero json --no-ri --no-rdoc
Building native extensions.  This could take a while...
Successfully installed mixlib-log-1.6.0
Successfully installed hashie-2.0.5
Successfully installed moneta-0.6.0
Successfully installed json-1.8.1
Successfully installed rack-1.5.2
Successfully installed chef-zero-1.7.2
Building native extensions.  This could take a while...
Successfully installed json-1.8.1
7 gems installed

chef-zero を実行します。 とりあえず、全てのサーバから接続を受け付けるようにして起動してみます。

$ chef-zero -H 0.0.0.0 &
[2] 2777
[vagrant@vagrant-centos64 ~]$ >> Starting Chef Zero (v1.7.2)...
>> WEBrick (v1.3.1) on Rack (v1.5) is listening at http://0.0.0.0:8889
>> Press CTRL+C to stop
workstationの設定

今回はworkstationとchef-clientは同一ホストにするので、引き続きchefクライアントのインストールを行います。

$   curl -L https://www.opscode.com/chef/install.sh | bash

つづいて、knifeコマンドを使えるようにしてみます。

$  mkdir /home/vagrant/.chef/
$ vim /home/vagrant/.chef/knife.rb

knife.rbの設定は次のようになります。 client_keyは適当なClientキーを指定し、node_nameも適当に指定します。 client_keyは読み込み可能なprivate key であれば何でも良いです。

log_level               :info
log_location            STDOUT
node_name               'ubuntu1'
client_key              '/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.8.0/spec/data/ssl/private_key.pem'
chef_server_url         'http://10.0.1.9:8889'

動作確認のため利用するレシピはOPSCODEのgetting-startedです。
このレシピはホームディレクトリに、chef-getting-started.txt を作成するレシピです。
レシピをChef Serverにアップロードします。

$ git clone https://github.com/opscode-cookbooks/getting-started.git
$ knife cookbook upload getting-started -o .
管理対象ノード(chef-client)の設定

chef-clientとして実行するには、client.rbが必要なので/etc/chef/client.rbの内容を編集します。 今回は、workstationと同じホストで試しているためnode_nameが同じになっています。 client_keyとvalidation_key は読み込み可能なprivate key であれば何でも良いです。

log_level               :info
log_location            STDOUT
node_name               'ubuntu1'
client_key              '/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.8.0/spec/data/ssl/private_key.pem'
validation_key          '/opt/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.8.0/spec/data/ssl/private_key.pem'
chef_server_url         'http://10.0.1.9:8889'

これでchef-clientを実行すると、chef-zeroサーバにノードが登録されます。

$ sudo chef-client 
[2013-11-25T23:17:00+00:00] INFO: Forking chef instance to converge...
Starting Chef Client, version 11.8.0
[2013-11-25T23:17:00+00:00] INFO: *** Chef 11.8.0 ***
[2013-11-25T23:17:00+00:00] INFO: Chef-client pid: 3811
[2013-11-25T23:17:00+00:00] INFO: Run List is []
[2013-11-25T23:17:00+00:00] INFO: Run List expands to []
[2013-11-25T23:17:00+00:00] INFO: Starting Chef Run for ubuntu1
[2013-11-25T23:17:00+00:00] INFO: Running start handlers
[2013-11-25T23:17:00+00:00] INFO: Start handlers complete.
[2013-11-25T23:17:00+00:00] INFO: HTTP Request Returned 404 Not Found : Object not found: /reports/nodes/ubuntu1/runs
resolving cookbooks for run list: []
[2013-11-25T23:17:00+00:00] INFO: Loading cookbooks []
Synchronizing Cookbooks:
Compiling Cookbooks...
[2013-11-25T23:17:00+00:00] WARN: Node ubuntu1 has an empty run list.
Converging 0 resources
[2013-11-25T23:17:00+00:00] INFO: Chef Run complete in 0.060747315 seconds
[2013-11-25T23:17:00+00:00] INFO: Running report handlers
[2013-11-25T23:17:00+00:00] INFO: Report handlers complete
Chef Client finished, 0 resources updated

$ knife node list
ubuntu1

引き続きノードにrecipeを追加します。

$knife node run_list add ubuntu1 "recipe[getting-started]"

最後にchef-clientを実行します。

$ sudo chef-client                                                                
[2013-11-26T13:18:22+00:00] INFO: Forking chef instance to converge...
Starting Chef Client, version 11.8.0
[2013-11-26T13:18:22+00:00] INFO: *** Chef 11.8.0 ***
[2013-11-26T13:18:22+00:00] INFO: Chef-client pid: 4521
[2013-11-26T13:18:22+00:00] INFO: Run List is [recipe[getting-started]]
[2013-11-26T13:18:22+00:00] INFO: Run List expands to [getting-started]
[2013-11-26T13:18:22+00:00] INFO: Starting Chef Run for ubuntu1
[2013-11-26T13:18:22+00:00] INFO: Running start handlers
[2013-11-26T13:18:22+00:00] INFO: Start handlers complete.
[2013-11-26T13:18:22+00:00] INFO: HTTP Request Returned 404 Not Found : Object not found: /reports/nodes/ubuntu1/runs
resolving cookbooks for run list: ["getting-started"]
[2013-11-26T13:18:22+00:00] INFO: Loading cookbooks [getting-started]
Synchronizing Cookbooks:
[2013-11-26T13:18:22+00:00] INFO: Storing updated cookbooks/getting-started/recipes/default.rb in the cache.
[2013-11-26T13:18:22+00:00] INFO: Storing updated cookbooks/getting-started/attributes/default.rb in the cache.
[2013-11-26T13:18:22+00:00] INFO: Storing updated cookbooks/getting-started/metadata.rb in the cache.
[2013-11-26T13:18:22+00:00] INFO: Storing updated cookbooks/getting-started/README.md in the cache.
  - getting-started
Compiling Cookbooks...
Converging 1 resources
Recipe: getting-started::default
  * template[/home/vagrant/chef-getting-started.txt] action create[2013-11-26T13:18:22+00:00] INFO: Processing template[/home/vagrant/chef-getting-started.txt] action create (getting-started::default line 20)
[2013-11-26T13:18:22+00:00] INFO: template[/home/vagrant/chef-getting-started.txt] created file /home/vagrant/chef-getting-started.txt

    - create new file /home/vagrant/chef-getting-started.txt[2013-11-26T13:18:22+00:00] INFO: template[/home/vagrant/chef-getting-started.txt] updated file contents /home/vagrant/chef-getting-started.txt

    - update content in file /home/vagrant/chef-getting-started.txt from none to e84a13
        --- /home/vagrant/chef-getting-started.txt      2013-11-26 13:18:22.966299400 +0000
        +++ /tmp/chef-rendered-template20131126-4521-17p6nv5    2013-11-26 13:18:22.966299400 +0000
        @@ -1 +1,6 @@
        +Welcome to Chef!
        +
        +This is Chef version 11.8.0.
        +Running on ubuntu.
        +Version 13.04.[2013-11-26T13:18:22+00:00] INFO: template[/home/vagrant/chef-getting-started.txt] mode changed to 644

    - change mode from '' to '0644'

[2013-11-26T13:18:23+00:00] INFO: Chef Run complete in 0.162571175 seconds
[2013-11-26T13:18:23+00:00] INFO: Running report handlers
[2013-11-26T13:18:23+00:00] INFO: Report handlers complete
Chef Client finished, 1 resources updated
雑感

validation_keyのコピーなどが発生しないため比較的簡単に使えるようになりますが、結局server、workstation、clientの構成は必要になるのでchef-soloと比べると手軽さは非常に落ちます。 ただし、Chef 11 Server 同等の REST API インターフェースを備えているということなので、そのあたりに価値を見いだせればお試しとして使ってみるのは良いかもしれません。

ChefのCookBookで、virtualenvを使えるようにする

poise/python · GitHub を使ってPython環境を作ると、自作のCookBookでpipやvirtualenvが使えるようになります。

poise/python · GitHub で は、Pythonのインストール、pipのインストール、virtualenvのインストールを行います。

インストールする場合はbuild-essentialが必要になります。
また、Redhat系の環境にパッケージでインストールするの場合はyumも必要になります。

インストール方法

recipesのdefault.rbを見ると、他のrecipeをincludeしているので、特に何も指定しなくてもpythonのインストール、pipのインストール、virtualenvのインストールが実行されることがわかります。

include_recipe "python::#{node['python']['install_method']}"
include_recipe "python::pip"
include_recipe "python::virtualenv"

パッケージインストールの場合は、run_listにpythonを追加するだけです。 chef-soloだったら、/tmp/vagrant-chef-1/dna.jsonなどに設定。

{
  "run_list" : [
    "recipe[python]"
  ]
}

ソースコードからインストールする場合には、environmentなどに、install_methodとversionを指定します(他にもcheck_sumなども指定できます)。 以下はchef-soloでの設定例です。

{
  "python" : {
    "install_method" : "source",
    "version" : "2.7.5"
  },
  "run_list": [
    "recipe[python]"
  ]
}

ソースコードからインストールする場合には、versionはソースコードを取得する先もある程度指定できます。

remote_file "#{Chef::Config[:file_cache_path]}/Python-#{version}.tar.bz2" do
  source "#{node['python']['url']}/#{version}/Python-#{version}.tar.bz2"
  checksum node['python']['checksum']
  mode "0644"
  not_if { ::File.exists?(install_path) }
end

recipes/source.rb を確認するとわかりますが、拡張子(.tar.bz2)の部分が固定なので、tar.bz2が無い場合にはエラーになってしまうので注意が必要です。
2.7.6は拡張子(.tar.bz2)のものが無いので、現時点ではエラーになりました。

pipやvirtualenvの使い方

pipの使い方は、virtualenvのrecipeを見ればわかるかと思います。

python_pip "virtualenv" do
  action :install
end

virtualenvとpipを使ってFlaskをインストールには、次のようなレシピを作って実行すればOKです。

include_recipe "python::pip"
include_recipe "python::virtualenv"

python_virtualenv "/home/vagrant/apps" do
  action :create
  owner "vagrant"
  group "vagrant"
end

python_pip "Flask" do
  action :install
  virtualenv "/home/vagrant/apps"
end

確認してみると、インストールされていることがわかります。

vagrant@vagrant-ubuntu:~$source ./apps/bin/activate
(apps)vagrant@vagrant-ubuntu:~$ pip list
argparse (1.2.1)
Flask (0.10.1)
itsdangerous (0.23)
Jinja2 (2.7.1)
MarkupSafe (0.18)
pip (1.4.1)
setuptools (0.9.8)
Werkzeug (0.9.4)
wsgiref (0.1.2)

opscodeのCookBook(selinux)を読む

まずは、比較的難しいことをしておらず、シンプルなopscodeのCookBookを読んでみます。 今回の読んでみるCookBookは、opscode-cookbooks/selinux · GitHub です。

ディレクトリ構成は次のようになっています。

`-- selinux
    |-- CHANGELOG.md
    |-- CONTRIBUTING
    |-- LICENSE
    |-- README.md
    |-- attributes
    |   `-- default.rb
    |-- metadata.rb
    |-- providers
    |   `-- state.rb
    |-- recipes
    |   |-- default.rb
    |   |-- disabled.rb
    |   |-- enforcing.rb
    |   `-- permissive.rb
    |-- resources
    |   `-- state.rb
    `-- templates
        `-- default
            `-- sysconfig
                `-- selinux.erb

Cookbook内のディレクトリの意味を知りたい場合は、サーバー設定ツール「Chef」の概要と基礎的な使い方のCookbookの構造の箇所が参考になります。

resourcesを見てみると、Recipe内で使われる設定対象が確認できるので確認します。 ここでは、利用できるactionやattributeを確認できます。

default_action :nothing
actions :enforcing, :disabled, :permissive

attribute :state, :default => nil

README.mdを見てもわかりますが、実際にこのcookbookを実行する際にはrun_listに、次のように指定します。

{
    "run_list":[
        "recipe[selinux::disabled]"
    ]
}

それぞれのrecipeを見てみると大体構成は次のようになっており、selinux_stateという独自のリソース(LWRP)が定義されています。

selinux_state "SELinux Disabled" do
  action :disabled
end

このリソース(selinux_state)は、providersのstate.rbにあります。 これは、リソースの名前は、大体『cookbook名_provider内のソース名 』という命名規則になっていることから、どのソースで定義されているかが判断できます。

state.rbでは、selinux_stateリソースで利用可能な、actionが定義されています。

action :disabled do
  unless @current_resource.state == "disabled"
    execute "selinux-disabled" do
      only_if "selinuxenabled"
      command "setenforce 0"
    end
    se_template = render_selinux_template("disabled")
  end
end

それぞれのactionの中で@current_resourceが定義されていて、@current_resourceにアクセスするとload_current_resourceメソッドが呼ばれます。

def load_current_resource
    @current_resource = Chef::Resource::SelinuxState.new(new_resource.name)
    s = shell_out("getenforce")
    @current_resource.state(s.stdout.downcase)
end

load_current_resourceの中で、@current_resource.stateにgetenforceの結果を設定して、それぞれのactionで、この値を利用しています。

chefのレシピを読み書きするときに知っておくと便利なこと1

only_if

only_ifは評価結果がtrue(return値が0)の時に実行。

ruby_block

ruby_blockを使うと、rubyのコードが記述可能になる。

ruby_block "{リソース名}" do
 block do
  Rubyのコードを記述
  :
 end
 action {:createRubyのコードを実行する)|:nothing(何もしない)}
end

actionとかは省略が可能。subscribes も指定可能。
actionを省略した場合は、createになる。

provider(LWRPs)

providerを使うことで、新規に自作のリソースを定義できる。
Custom Lightweight Resources — Chef Single-page Topics を見ると、providers の下に定義したproviderはRubyのソースの名前でそのまま使えるように見える。
実際にrecipeで利用する時は、cookbook名_Rubyのソースの名になる。
cookbook名に『-』が入っている時には、『_』を利用するようになる。

notifies

変更時に処理を指定する際に "notifies" を使いますが、notifies のデフォルトは delayed となり、キューに貯められて Chef の処理の最後にまとめて実行されます。
今回は、処理がひとつしかないので特に困りませんが、依存関係のある複数の処理が走る場合に、即時実行したい場合は、:immediately を指定しましょう。
るびま Chef でサーバ管理を楽チンにしよう! (第 2 回)

service "apache2" do
  case node['platform_family']
  when "rhel", "fedora", "suse"
    service_name "httpd"
    # If restarted/reloaded too quickly httpd has a habit of failing.
    # This may happen with multiple recipes notifying apache to restart - like
    # during the initial bootstrap.
    restart_command "/sbin/service httpd restart && sleep 1"
    reload_command "/sbin/service httpd reload && sleep 1"
  when "debian"
    service_name "apache2"
    restart_command "/usr/sbin/invoke-rc.d apache2 restart && sleep 1"
    reload_command "/usr/sbin/invoke-rc.d apache2 reload && sleep 1"
  when "arch"
    service_name "httpd"
  when "freebsd"
    service_name "apache22"
  end
  supports [:restart, :reload, :status]
  action :enable
end

template "/etc/sysconfig/httpd" do
  source "etc-sysconfig-httpd.erb"
  owner "root"
  group node['apache']['root_group']
  mode 00644
  notifies :restart, "service[apache2]"
  only_if { platform_family?("rhel", "fedora") }
end

とすると、templateを実行しnotifiesから呼ばれた時(package実行時)にapacheをrestartする。

subscribes

template "/tmp/somefile" do
  mode "0644"
  source "somefile.erb"
end

service "apache" do
  supports :restart => true, :reload => true
  action :enable
  subscribes :reload, resources("template[/tmp/somefile]"), :immediately
end

Notifications for Recipes and Resourcesのレシピを参照

notifiesとは逆で、他のリソースが変更された時に実行される。
設定ファイルの更新処理をsubscribes して、サービスのrestartを実行する。というように書かれていること多い。
opscodeのサンプルのレシピでも、そのように書かれている。
シンタックスは、下記の通り。

resource "name" do
  subscribes :action, "resource_type[resource_name]", :notification_timing
end

CentOSに最新のgitをインストールする

必要なパッケージをインストールする。

# yum install -y zlib-devel perl-devel gettext gcc curl-devel

Downloads - git-core - Git - the stupid content tracker - Google Project Hostingから最新版をダウンロードする。

# wget http://git-core.googlecode.com/files/git-1.8.2.3.tar.gz
# tar xvfz git-1.8.2.3.tar.gz

インストールを行う

# cd git-1.8.2.3
# ./configure 
# make
# make install
# git --version
git version 1.8.2.3

curl-develがインストールされていないと、下記のようなエラーがでる。

git fatal: Unable to find remote helper for 'https' curl