fbpx

[和訳] Bashスクリプトをchef-applyに変換する #getchef

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

本稿は Convert Your Bash Scripts With chef-apply (2015/01/16) の和訳です。

Chefはインフラの自動化と検証を行う強力なツールセットです。しかし、すべての力を習得するのは大変です。ほとんどの人は新しいツールを学ぶのに1〜2時間試してみて、それからどうするかを決めるのが普通です。本日は、金曜日の午後の数時間を実験に使って、シェルスクリプトをChefでの宣言に置き換えることで、Chefの真価を素早く紹介したいと思います。それでは、単一のファイルをChefのrun listとして実行するchef-applyを用いてみましょう。

概要

始める前に、Chefがスクリプト言語であると見せかけようとすることさえ、言う価値があると思います。Chefは実行する動作のリストを提供するものというよりむしろ、Chef run listはシステムの望ましい最終状態を記述するものです。言い換えると、Chefの各Resourceは、次のようなコードの引き金となります。

もしシステムの状態がResourceが記述しているものと既に一致しているならば何も行わず、そうでなければシステムを正しい状態にするために必要などのような動作も実行する。

では、Chefにファイルが存在して特定の内容であってほしいなら、次のようにします。


file "/tmp/foo" do
content "This will be the file's content."
end

Chefは指定のファイルがその内容で存在しているかどうかを確認し、必要なら更新したり作成したりします。

このモデルに適合しないなら、シェルコードを実行するためのexecute Resourceがあります。さらに、Chefの動作のたびに実行することを防ぐためにnot_ifonly_if条件式を追加できます。

話の途中だけど、どれだけ便利かはわかったよ

もう十分! 金曜日の午後なんだから、試しにChefに何かをやらせてみたいんだよ!

我が家にはsqueezeboxserverという名前の音楽サーバがあり、最新バージョンではお気に入りの機能が削除されているので、Ubuntu 11以降では何も動作しない古いバージョンを使っています。そこでVirtualBox仮想マシンを管理するVagrantを用いてUbuntu 10仮想マシンを立てています。squeezeboxserverは音楽ライブラリをスキャンし、ファイルと再生リストデータをMySQLに保存します。

squeezeboxserverは依存関係と設定にとても口うるさいです。Debianパッケージをビルドするスクリプトを用いていますが、それは依存関係にあるパッケージをインストールしません。MySQLサーバがインストールされている必要がありますが、デフォルトではシステムグローバルのmysqldではなく、自身専用のmysqldを用います。もともと、このマシンを設定するためのBashスクリプトを書いていました。


rm /etc/localtime
ln -s /usr/share/zoneinfo/America/Los_Angeles /etc/localtime
apt-get update
export DEBIAN_FRONTEND=noninteractive
apt-get -y install mysql-server-5.1 libmysqlclient16-dev mysql-client-5.1
dpkg -i /home/chris/squeezebox/squeezeboxserver_7.5.6~32834_all.deb
tar -C / -xf /home/chris/backups/sbserver_prefs.tar
/etc/init.d/squeezeboxserver restart

おおよそうまく動作するこれは、驚くほど貧弱な8行のシェルスクリプトです。仮想マシンはさらに多くの手動作業を必要としており、仮想マシンを起動し直すのが怖いのでメンテナンスのためにホストサーバを停止したくないほどに、非常に壊れやすいものです。これらのコマンドがエラーを起こした際----それは予期しているよりもっと多くの頻度で起きうる----まったく頼りにならないもので、何を行っているかを明確に伝えていません。仮想マシンを削除したり再作成したりすることは同様に大変危険です。

ホストサーバのつい最近のメンテナンスで、これで止めにすることを決めて、chef-applyに変換しました。chef-applyはChef同梱のツールで、基本的にChefをスクリプト言語とみなせるようにしてくれます。Recipeなし、ディレクトリ構造なし、ChefのResourceの単一のファイルだけです。シェルスクリプトでやるのと同じようにshebang行に指定して「chef-applyスクリプト」とすることができます。


#!/usr/bin/env chef-apply

もともとのBashスクリプトを1行ずつChefに変換していきます。


rm /etc/localtime
ln -s /usr/share/zoneinfo/America/Los_Angeles /etc/localtime

マシンのタイムゾーンを設定する方法はいくつかあります。ここでは好みの方法を用いています。十分簡単な方法で、Chefにはlink Resourceがあります。


link "/etc/localtime" do
to "/usr/share/zoneinfo/America/Los_Angeles"
end

ここで、Chefに「サーバの正しい状態はこのシンボリックリンクを持つ」と伝えています。Chefはシンボリックリンクが既に存在しているかどうかを確認し、もし存在して正しいファイルを指していれば何もしません。


export DEBIAN_FRONTEND=noninteractive
apt-get -y install mysql-server-5.1 libmysqlclient16-dev mysql-client-5.1

Chefのpackage Resourceがこれをカバーしています。


package "mysql-server-5.1"
package "libmysqlclient16-dev"
package "mysql-client-5.1"

あるいは、Rubyに慣れ親しんでいて繰り返しを好まないなら、まったく同じことを行うループ表現を用いることができます。


["mysql-server-5.1", "libmysqlclient16-dev", "mysql-client-5.1"].each do |pkg_name|
package pkg_name
end

ただし、パッケージインストールのmysql-server-5.1はシステムのmysqldを起動します。service mysql stopコマンドで手動で停止することができますが、仮想マシンを再起動したら一緒に起動してきてしまいます。私はソフトウェアエンジニアであってシステム管理者ではないので、システムのmysqldをどのように永久に無効にするかを説明するのは面倒です。Chefのservice Resourceがこれを行ってくれます。


service "mysql" do
action :disable
end

これでシステム起動時にmysqldは起動しなくなります。

事前準備が済んだので、squeezeboxserver自体のインストールと設定に進みしょう。


dpkg -i /home/chris/squeezebox/squeezeboxserver_7.5.6~32834_all.deb

ここで予備知識のための一息を入れましょう。ChefのResourceは、ChefのResourceの実際の作業を行うProviderによって支えられています。先に記述したpackage "mysql-client-5.1"では、どのようなオペレーティングシステムで実行しているかを知る必要はありません。Chefはシステムを調べて適切なProviderを呼び出します。Red Hatベースのシステムではyum Providerで、Debianベースのシステムではもちろんpackage Resourceはapt Providerとして解決します。この結果、.debファイルをインストールするには、明示的にdpkg Providerを用いるdpkg_package Resourceを用いなければなりません。


dpkg_package "squeezeboxserver_7.5.6" do
source "/home/chris/squeezebox/squeezeboxserver_7.5.6~32834_all.deb"
end

この.debファイルはサーバを動作したままにしておきますが、squeezeboxserverを長い間動作させているので、用いたい設定ファイルの.tarがあります。


tar -C / -xf /home/chris/backups/sbserver_prefs.tar

これはそんなに悪くないので、実際にはtar Resourceを用いず、これをChefのexecute Resourceを用いてベタ書きします (tar Cookbookがありますが、金曜日の午後だし複雑なことをしたくないので)。通常、ChefのResourceは望ましい最終状態を記述するために用います。ときたま十分ではないので、シェルコマンドを実行するexecuteを用います。


execute "tar -C / -xf /home/chris/backups/squeezeboxserver.tar"

では、サーバを再起動し、音楽コレクションをスキャンしてMySQLデータベースに格納させるようにしましょう。


/etc/init.d/squeezeboxserver restart

十分簡単です。Chefにサービスを無効化させて、再度有効化させます。


service "squeezeboxserver" do
action :restart
end

これで、全部です。

調子がいいので、Chefはcronジョブの管理を簡単にしてくれるから、cronジョブを追加することを決めました。Bashで安全にcrontabsを編集するのは骨が折れるので、やろうと思っていませんでした。


cron "backup_config" do
minute "0"
hour "0"
user "vagrant"
command "tar -C / -cf /home/chris/backups/sbserver_prefs.tar /var/lib/squeezeboxserver/prefs"
end

このようにすれば、設定、再生リスト、MySQLデータの最新のバックアップを取得できます。最高だね。仮想マシンの削除や再構成もわずかな時間で何回も、単なる興味本位でできます。Chefは毎回同一に再構築します。もし何か違うことが起きたり、まったく不思議なことに、止まってしまったら教えてください。それが本当なら、chef-applyスクリプトに何行か追加します。オリジナルより確実でより優れているでしょう。

Chefの真意は、何かを行うときに気を利かせない、ということです。「気を利かせられる」と「デバッグしづらい」と考える人々に対して本当に安心できることです。「ファイルが存在して正しい内容か?」というすべてを調べることを単純に実行でき、「Debianではapt-getを、RHELではYumを、FreeBSDではpkg_add/pkgngを使って...」というクロスプラットフォームの実装は退屈で間違いやすいということがわかるでしょう。Chefはいつもすべて指示したことだけをやってくれます。

chef-applyは「Chef Lite」の一種です。Chefのクイックハックで、仕事を片付けるためのツールです。これをインフラ全体に対してはまったく動かしたくはないでしょう。これは単一のファイルで、Cookbook、Template、Role、User、Orgなど自動化に用いたいChefの機能がありません。Chefの完全な力に対して準備ができたときには、Recipeにコピーできるようなクロスプラットフォームのコード基盤を持っていることでしょう。

次に完全なchef-applyスクリプトを示します。Happy hacking!


link "/etc/localtime" do
to "/usr/share/zoneinfo/America/Los_Angeles"
end
package "mysql-server-5.1"
package "libmysqlclient16-dev"
package "mysql-client-5.1"
service "mysql" do
action :disable
end
dpkg_package "squeezeboxserver_7.5.6" do
source "/home/chris/squeezebox/#{DEB}"
end
# o/~ meet the new server / same as the old server o/~
execute "tar -C / -xf /home/chris/backups/sbserver_prefs.tar"
service "squeezeboxserver" do
action :restart
end
# ---- end app setup ----
cron "nightly_rescan" do
minute "30"
hour "0"
user "vagrant"
command "/usr/sbin/squeezeboxserver-scanner --rescan"
end
cron "backup_config" do
minute "0"
hour "0"
user "vagrant"
command "tar -C / -cf /home/chris/backups/sbserver_prefs.tar /var/lib/squeezeboxserver/prefs"
end
cron "backup_mysql" do
minute "5"
hour "0"
user "vagrant"
command "sudo mysqldump -S #{MYSQL_SOCK} slimserver | gzip -c > /home/chris/backups/sbserver_sql.tgz"
end
cron "backup_playlists" do
minute "10"
hour "0"
user "vagrant"
command "tar -cf /home/chris/backups/playlists.tar /home/chris/music/playlists"
end

新規CTA