SyntaxHighlighter

2013/01/03

apt(LWRP)

Cookbook情報

cookbook[apt]LWRP編、レシピ編はこちら

概要

debian/ubuntuのパッケージリポジトリ管理システムのaptの設定を行う。

解説

cookbook[apt]の持つLWRPについて説明。任意のリポジトリ追加やパッケージのpinningが設定できる。

LWRP

LWRPはCookbook名+Resource名で指定でき、任意のレシピ内で使います。利用したいResourceをもつCookbookをrun_listに入れておき、他のCookbookを作る時に呼び出します。

apt_repository

aptのリポジトリを追加する。これによりpackageリソースで追加したリポジトリからのインストールが可能になる。

公式のREADMEではnginxの例が出ているので、自作のCookbookから例を。

Mongodbの10gen提供リポジトリを追加して、インストールするレシピ。https://github.com/higanworks-cookbooks/mongodb-10gen/blob/master/recipes/default.rb

apt_repository "mongodb-10gen" do
  uri "http://downloads-distro.mongodb.org/repo/ubuntu-upstart"
  distribution "dist"
  components ["10gen"]
  keyserver "keyserver.ubuntu.com"
  key "7F0CEB10"
end

これでリポジトリが追加され、ついでにapt-get updateされる。Ver10.14以前のChefではバグでupdateが走らないため、executeで明示的に呼ぶ必要がある。

apt_preference

こちらはpreferenceのパラメータを指定して、そのとおり設定ファイルを作成するResource

公式READMEから使い方。

apt_preference "libmysqlclient16" do
  pin "version 5.1.49-3"
  pin_priority "700"
end

こちらは有効なケースが結構限られるのであまり使っていない、ちなみに不要になったらaction:removeで除去出来る。

適用例

apt_repositoryを実際に適用したら、設定ファイルがこのように作成される。

$ cat /etc/apt/sources.list.d/mongodb-10gen.list deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen

過不足無し、リポジトリ追加完了。

あとがき

LWRPのお手軽さと、他のレシピからも使える汎用性を紹介したいのでLWRPだけに絞ったaptのcookbook紹介を作成しました。

Cookbookはなるべく各環境で専用の物を書くものではなく、できるだけ汎用的に作ってAttributeやLWRPを活用して環境を構築するという事の参考になるはず。

2013/01/02

apt(recipe)

Cookbook情報

cookbook[apt]のレシピ編、LWRP編はこちら。

概要

debian/ubuntuのパッケージリポジトリ管理システムのaptの設定を行う。

解説

ubuntu系ではできるだけ入れておいたほうがよい。レシピの役割はパッケージリストの更新と、キャッシュサーバ/クライアントのセットアップ。

キャッシュサーバのクライアント設定はChefServerSearchを使う参考になります。
サーバのインベントリを自動集約しておくと恩恵がありますよという例のひとつ。

ちなみにサーバをBootstrapしつつrun_listを適用する場合にはリポジトリ情報が古くてpackageリソースを含むCookbookはだいたいコケる。初めに読ませて更新させるか、include_reciperecipe[apt::default]を呼ぶとよい。

Recipes

レシピのコーナー

default

update-notifier-commonの導入と、apt-get updateの実行、それと他のレシピから呼べるようなexecuteリソースを定義している。

cacher-ng

apt-cacher-ngパッケージの導入とプロキシサービスの自動起動。レシピも短いので全て掲載。

package "apt-cacher-ng" do
  action :install
end

service "apt-cacher-ng" do
  supports :restart => true, :status => false
  action [ :enable, :start ]
end

#this will help seed the proxy
include_recipe "apt::cacher-client"

このレシピを適用するとapt-cache-ngパッケージがインストールされプロキシとして動作する、ブラウザから確認できる。

apt-cache-ng.png

と、同時にChefServerを使っていると、recipe[apt::cacher-ng]runlistに登録されたサーバというアトリビュートがnodeに対して付与される。この集中管理されたアトリビュートを理解することがChefをより活用するためのキーポイントにもなる、次のレシピが例。

cacher-client

aptのProxy設定をするレシピ、/etc/apt/apt.conf.d/01proxyファイルを編集して利用するProxyをコントロールする。

さて、肝心のProxyサーバアドレスを取得する仕組みをレシピを抜粋して紹介してみる、まずはservers変数にサーバリストを格納する部分。

servers = []
if node['apt'] && node['apt']['cacher_ipaddress']
  cacher = Chef::Node.new
  cacher.name(node['apt']['cacher_ipaddress'])
  cacher.ipaddress(node['apt']['cacher_ipaddress'])
  servers << cacher
end

unless Chef::Config[:solo]
  query = 'recipes:apt\:\:cacher-ng'
  query += " AND chef_environment:#{node.chef_environment}" if node['apt']['cacher-client']['restrict_environment']
  Chef::Log.debug("apt::cacher-client searching for '#{query}'")
  servers += search(:node, query)
end

初めにnode['apt']['cacher_ipaddress']があればそれを使うようにしている。EnvironmentRoleで設定できる。
それよりやはりSearchを使った次のブロック(unless以降)に注目したい。

条件が沢山並ぶようだが、とりあえず一つ目のここだけquery = 'recipes:apt\:\:cacher-ng'わかればいい。

このクエリはChefのSearchAPIを使って、プロキシサーバとして指定するIPを決定するために使われる。

具体的にはrunlistにapt-cacher-ngがあるnodeを問い合わせて、そのnode情報を格納しているのだ。

実際にクエリしてみる、recipe[apt::cacher-ng]をrunlistに持つnodeが実際にいると引っかかるのがわかる。

$ knife search node 'recipes:apt\:\:cacher-ng'
1 items found

Node Name:   apt-test
Environment: apt-book-test
FQDN:        localhost
IP:          210.152.***.***
Run List:    recipe[apt::default], recipe[apt::cacher-ng]
Roles:       
Recipes:     apt::cacher-ng
Platform:    ubuntu 12.04
Tags:        

そしてProxyを指定する設定ファイルにnodeの持つipaddressアトリビュートを当てはめている部分が下記。

if servers.length > 0
  Chef::Log.info("apt-cacher-ng server found on #{servers[0]}.")
  template '/etc/apt/apt.conf.d/01proxy' do
    source '01proxy.erb'
    owner 'root'
    group 'root'
    mode 00644
    variables(
      :proxy => servers[0]['ipaddress']
      )
  end.run_action(:create)
else
  Chef::Log.info('No apt-cacher-ng server found.')
  file '/etc/apt/apt.conf.d/01proxy' do
    action :delete
  end
end

要はChefServerを使っている場合、レシピによって作成してあるaptのProxyサーバがあれば、あとはclientのレシピを適用するだけで自動で適切なProxyを使ってくれるということになる。
apt-cacher-ngが適用されているNodeが変われば、全てのクライアントもサーバIPを変更してくれるし、apt-cacher-ng適用Nodeがなくなれば勝手にProxyを使うのをやめてくれる。

Attributes

node['apt']['cacher-client']['restrict_environment']

Proxyサーバに使うIPを種痘する際に、Environmentの一致を条件に入れるか設定できる。
ロケーション別にEnvironmentを分けている場合などに有効。

node['apt']['cacher_ipaddress']

defaultとして定義はされていないが、このアトリビュートを設定するとapt-cacher-ngが動作しているサーバを明示的に指定できる。

実行例

ほぼレシピの説明通りなので省略、Client側の設定ファイルが下記のようになる。

$ cat /etc/apt/apt.conf.d/01proxy
Acquire::http::Proxy "http://210.152.***.***:3142";

Attribute特に指定なし、サンプルのrunlistはこう。

  • Proxy用nodeのrunlist:
    "recipe[apt::default],recipe[apt::cacher-ng]"
  • Clientのrunlist:
    "recipe[apt::default],recipe[apt::cacher-client]"

あとがき

このレシピはRole(または各Nodeのアトリビュート)とSearchによるChefServerのインベントリ収集の強みがわかりやすいので紹介しました。

構築=構成管理=維持管理を同列に行うことで、コンフィグの変更を全サーバに適用するとか、わざわざ配布し直すとか、そういった作業が実際不要になるということがわかると思う。

2012/12/26

build-essential

Cookbook情報

概要

各プラットフォームに対して、ビルドパッケージ群をまとめて導入する。

解説

Ubuntu Serverではgcc,libcmakeを使えるようにするために、とりあえずbuild-essentialをインストールします。 この感覚を複数のOS、ディストリビューションで再現するためのCookbookです。

Readmeから対応プラットフォームを抜粋。

  • Linux (fedora redhat centos ubuntu debian amazon scientific)
  • Darwin (macosx 10.6+)
  • SmartOs

SmartOSはcookbook[pkgin]に依存しているので一緒にChefServerに入れておけば動作します。

Recipes

レシピは一つ。Ohaiがプラットフォームを判断して適当なパッケージをinstallするだけです。

default

パッケージインストール部分をチェック、ディストリビューション毎にパッケージの配列を分岐させていますね。

packages = case node['platform_family']
  when "debian"
    %w{build-essential binutils-doc}
  when "rhel", "fedora"
    %w{gcc gcc-c++ kernel-devel make}
  when "suse"
    %w{gcc gcc-c++ kernel-default-devel make m4} # in SLES there is no kernel-devel
  end

packages.each do |pkg|
  r = package pkg do
    action ( compiletime ? :nothing : :install )
  end
  r.run_action(:install) if compiletime
end

%w{autoconf flex bison}.each do |pkg|
  r = package pkg do
    action ( compiletime ? :nothing : :install )
  end
  r.run_action(:install) if compiletime
end

このあとSmartOSやMacOSの記述ですが割愛します。

Attributes

設定が必要なデーモンなどの導入ではないので、特に気にするものはないです。

実行ログ1: CentOSに適用

sshが繋がる状態のCentOSをChef-clientに仕立ててついでにレシピを適用します。

$ knife bootstrap #{server} -r "recipe[build-essential]"

クラウドベンダに対応したknifeのプラグインを使ってインスタンスの作成から一発でやってもよいです。

$ knife zcloudjp machine create -I sdc:jpc:centos-6:1.3.0 -N cent66 -r "recipe[build-essential]"

検出されたプラットフォームに対応して、chef-clientによるコンバージェンスが行われます。

INFO: Loading cookbooks [build-essential]
INFO: Processing package[gcc] action install (build-essential::default line 51)
INFO: package[gcc] installing gcc-4.4.6-4.el6 from base repository
INFO: Processing package[gcc-c++] action install (build-essential::default line 51)
INFO: package[gcc-c++] installing gcc-c++-4.4.6-4.el6 from base repository
INFO: Processing package[kernel-devel] action install (build-essential::default line 51)
INFO: package[kernel-devel] installing kernel-devel-2.6.32-279.19.1.el6 from updates repository
INFO: Processing package[make] action install (build-essential::default line 51)
INFO: Processing package[autoconf] action install (build-essential::default line 58)
INFO: package[autoconf] installing autoconf-2.63-5.1.el6 from base repository
INFO: Processing package[flex] action install (build-essential::default line 58)
INFO: package[flex] installing flex-2.5.35-8.el6 from base repository
INFO: Processing package[bison] action install (build-essential::default line 58)
INFO: package[bison] installing bison-2.4.1-5.el6 from base repository

ビルド関連ツールがインストールされた状態にしてくれました。

実行ログ2: SmartOSに適用

Joyent SmartOSに対して行います、cookbook[pkgin]を添えます。

$ knife bootstrap #{server} -r "recipe[pkgin],recipe[build-essential]"

クラウドベンダに対応したknifeプラグインなら。

$ knife zcloudjp machine create -I sdc:sdc:base64:1.8.4 -N smart184 -r "recipe[pkgin],recipe[build-essential]"

検出されたプラットフォームに対応して、chef-clientによるコンバージェンスが行われます。

INFO: Loading cookbooks [build-essential, pkgin]
INFO: Processing pkgin_package[gcc47] action install (build-essential::default line 67)
INFO: Processing pkgin_package[gcc47-runtime] action install (build-essential::default line 67)
INFO: Processing pkgin_package[scmgit-base] action install (build-essential::default line 67)
INFO: Processing pkgin_package[gmake] action install (build-essential::default line 67)
INFO: Processing pkgin_package[pkg-config] action install (build-essential::default line 67)
INFO: Processing pkgin_package[binutils] action install (build-essential::default line 67)

こちらもビルド関連ツールがインストールされた状態にしてくれました。

あとがき

Chefはクロスプラットフォームの対応を進めており、少々モノが違っても大体同じことが出来るように作られています。
サーバの役割は外部に対してサービスを提供することであり、構築に付随する負担を削減しようという思想がこのCookbookにシンプルに現れているような気がします。

多くの人にとって、サーバ環境構築は目的でなくサービスを展開する手段なのですから。

2012/12/19

Package Installer

Cookbook情報

概要

Chefのビルトインリソースpackageをラップして、各種パッケージの構成をAttributeとして管理できるCookbook。

解説

レシピが内部DSLで良かったと思える一品、packageリソースが対応するプラットフォームすべてに有効だ。

パッケージの導入&削除およびバージョン指定&自動更新をEnvironmentRoleのメタデータとして管理できるので多少の構成変更ならCookbookの変更が不要になることも大きい。
もしパッケージをインストール/アンインストールするだけのCookbookを書いていたらpackage_installerに統合したらよい。

recipe

defaultが一つだけ、そして10行しか無いのでまるごと掲載する。

余談だがattributeの指定にシンボルを使うのはFoodcritic FC001に引っかかるので、一応覚えておこう。

default

node[:package_installer][:packages].each do |pkg_name, pkg_info|
  if(pkg_info)
    pkg_action = pkg_info[:action] || :install
    pkg_version = pkg_info[:version]
  end
  package pkg_name do
    action pkg_action
    version pkg_version if pkg_version
  end
end

バージョンを貰えば指定つきで、各種パッケージを指定したactionで構成するだけと非常にシンプルだ。

Attributes

  • ['package_installer']['packages']
  • ['package_installer']['packages']['$pkgname']
    • ['action']:省略時は:install
    • ['version']: 省略可

Attribute設定の例

このCookbookに限った話ではないが、packages以下の要素を複数のRole,Environmentで同じように指定した場合上書きでなくマージされる

あるRoleでvimを指定して、

"package_installer": {
  "packages": {
    "vim": nill
  } 
}

ほかのRoleでtmuxを指定したとする。

"package_installer": {
  "packages": {
    "tmux": {"action": "upgrade"}
  }
}

Nodeの持つ最終的なAttributesはこのようになる。

"package_installer": {
  "packages": {
    "vim": null,
    "tmux": {"action": "upgrade"}
  }
}

当然どこかでrun_listrecipe[package_installer]を一度入れておけば、Chef-clientサーバの状態をそのようにしておいてくれる。

適用例1

ubuntu_baseというRoleを作って、よく使うユーティリティをdefault_attiributesにて指定するというような使い方が便利だろう。

{"name": "base_ubuntu",
  "description": "Server Basic Settings",
  "json_class": "Chef::Role",
  "default_attributes": {
    "package_installer": {
      "packages": {
        "dstat": null,
        "vim": null,
        "curl": {
          "action": "upgrade"
        },
        "yajl-tools": null,
        "tmux": null,
        "iotop": null,
        "nano": {
          "action": "remove"
        },
        "bsd-mailx": null
      }
    }
  },
  "override_attributes": {},
  "chef_type": "role",
  "run_list": [
    "recipe[package_installer::default]"
  ],
  "env_run_lists": {}
}

例ではopscodeのaptのCookbookも入れている、Chefサーバかcookbookのパスに一緒に入れておくことをお勧め。

実行ログ例1

INFO: Processing package[curl] action upgrade (package_installer::default line 7) 
INFO: package[curl] upgraded from uninstalled to 7.22.0-3ubuntu4 
INFO: Processing package[tmux] action install (package_installer::default line 7) 
INFO: Processing package[bsd-mailx] action install (package_installer::default line 7) 
INFO: Processing package[yajl-tools] action install (package_installer::default line 7) 
INFO: Processing package[nano] action remove (package_installer::default line 7) 
INFO: package[nano] removed INFO: Processing package[dstat] action install (package_installer::default line 7) 
INFO: Processing package[iotop] action install (package_installer::default line 7) 
INFO: Processing package[vim] action install (package_installer::default line 7) 

適用例2

syslog-ngのレシピを適用したいが、他のsyslog系を止めたい。これをRoleに書くことでCookbook修正の手間を軽減できる。

-- snip --
"default_attributes": {
  "package_installer": {
    "packages": {
      "rsyslog": { "action": "remove" },
      "syslog": { "action": "remove" }
    }
  }
},
"run_list": [ "recipe[syslog-ng::default]" ]
-- snip -- 

この場合はもちろん、How to write a good Chef cookbookのようにレシピ内で書いても良いが。

あとがき

このCookbookはOpscode作でなくコミュニティでShareされているもので、なおかつ1コミットで終了してライセンス表記もない。
しかし『Chef導入≠レシピ書く』を印象付けるのにとてもわかりやすいため紹介することにした。

このブログについて

『Opscode ChefのCookbookレビュー』は、OpsCodeの構成管理ツールChefについて、主にOpscodeコミュニティで入手できるCookbooksの解説と使い方を投稿するブログです。

汎用的に作られたCookbookを使うためには、EnvironmentRoleAttribute重ねがけすることになります。
Chefを導入してしばらく経ちますが、特にAttributeが重要だと気付いてからはコミュニティのCookbooksを積極的に利用しています。

レビューによってCookbookの使い方、書き方のコツを身につけつつ、ついでに情報公開することが目的です。