読者です 読者をやめる 読者になる 読者になる

Programming log - Shindo200

イベント参加記録とプログラミング系の雑記

Chef の思想や基本を優しく学びました

知っていることはブログに書いておかないと不安になる病気にかかってしまいましたので、Chef についてのメモを残しておきます。

はじめに

アプリケーションサーバMySQL とか Nginx とか様々なパッケージをインストールしているかと思います。皆さんはこれらのパッケージをどうやってインストールしていますか。

「パーケッジ管理ツールを使って手動でインストールしているよ!」

お疲れ様です><

「必要なパッケージをまとめてインストールするシェルスクリプトを作ったよ!」

シェルスクリプトを書くのは楽しいですね!

「構成管理ツールを使っているよ!」

わぉ!ツールの思想や使い方を私に教えてください!

アプリケーションサーバを構築したことがないよ!」

一緒に勉強しましょう。

……まあ、そんな感じで様々な方がいらっしゃると思うのですが、一番最初にあげた「手動でインストールしていく方法」には以下のような問題がありますのであまり行いたくないです。

  • サーバが複数台あるときに、作業に時間がかかる
  • 人手による作業なので、ケアレスミスが起こりやすい
  • 手順書などの資料を管理していかなければいけない

そこで、今回は構築管理ツール「Chef」を使って、アプリケーションサーバに様々なパッケージをインストールして、サーバの設定を行ってみます。

構成管理ツールとは

パッケージのインストールやサービスの起動設定をコードで記述しておいて、後で簡単に実行できる環境を提供するツール「構成管理ツール(Configuration management tool)」と呼びます。構成管理ツールを使うことには以下のようなメリットがあります。

  • サーバが複数代あっても、記述したコードを全てのサーバに適用するだけなので、作業に時間があまりかからない
  • プログラムによる作業なので、ケアレスミスが起こらない
  • 設定を記述したコードが手順書となるので、余計な手順書を作らなくて済む
  • サーバ環境を構築することを目的として作られているツールなので、シェルスクリプトなどを使ったときよりもコードをメンテナンスしやすい

構成管理ツールには「Chef」や「Ansible」などがあります。

Chef とは

「Chef」は RubyErlang で作られた構成管理ツールです。

Chef | IT automation for speed and awesomeness | Chef

自由に使えるオープンソース版と、様々なサポートが付いたエンタープライズ版の2種類があります。

Chef の用語

レシピ

「〜がインストールされている」「〜と書かれた設定ファイルが存在する」という最小単位の状態をコードで記述したファイルのことを「レシピ(Recipe)」と呼びます。

クックブック

レシピを組み合わせて、「〜がインストールされて、それを使うための〜という設定が整っている」という状態を定義しておくファイルを「クックブック(Cookbook)」と呼びます。1つのクックブックにつき、一つのパッケージについて書いておくのが一般的なやり方だそうです。クックブックを用意したいときは、自分で書いていくほかに「Opscode Community」からダウンロードする方法もあります。

Opscode Community

リポジトリ(キッチン)

クックブックやそのほかで Chef の実行に必要なファイルを集めたものを「リポジトリ(Repository)」、もしくは 「キッチン(Kitchen)」と呼びます。git を使うときはリポジトリ単位で管理していくのが一般的なやり方だそうですね。

Chef のサーバ構成

Chef には、「Chef Server/Client」というツールを使って「クライアント・サーバ形式」という方法でサーバの状態を管理する方法と、「Chef Solo」というツールを使ってスタンドアロン形式」という方法でサーバの状態を管理する方法の2通りがあります。

クライアント・サーバ形式(Chef server/client)

f:id:Shindo_Masaya:20140705141902j:plain:w600

レシピやクックブックを編集する場所であるワークステーション(Workstation)」ワークステーションで作ったレシピやクックブックを管理する場所である「Chef サーバ(Chef server)」、Chef サーバからレシピやクックブックを取得してサーバの状態を構築する場所である「ノード(Node)」の3つの構成でサーバを管理する方法を「クライアント・サーバ形式」と呼びます。ノードには Chef client ツールだけをインストールすればいいので、ノードの数が多くても楽に対応できますが、開発端末や管理対象サーバ以外に Chef サーバとして動かす端末が1台必要になってしまうという難点があるようです。

スタンドアロン形式(Chef solo)

f:id:Shindo_Masaya:20140713200523j:plain:w400

ワークステーションから各ノードにクックブックを直接送り、各ノードで Chef solo ツールを使ってクックブックを適用するという方法でサーバを管理する方法をスタンドアロン形式」と呼びます。クライアント・サーバ形式とは違い Chef サーバを用意する必要はありませんので、小規模な環境で有効なようです。

Chef の思想について

サーバの状態を管理する

Chef では以下のようなコードを記述してサーバを構築していきます。

package 'httpd' do
  action :install
end

Chef のことがわからなくても、「httpd というパッケージをインストールする」となんとなく読めますが、Chef の思想では「httpd というパッケージがインストールされている状態である」と読むのが正しいそうです。もともと Chef はサーバ構築作業を行うためのツールではなく、サーバの状態を管理するためのツールとして開発されたそうです。この違いを意識して Chef を使えると、「サーバの状態を知りたくなったときは Chef に記述したコードを見ればいい」と判断できるようになります。

冪等であるべき

Wikipediaから「冪等」の概念を引用します。 冪等 - Wikipedia

ある操作を1回行っても複数回行っても結果が同じであることをいう概念である。

ここに書かれているように、Chef で環境構築の処理を複数回行ってもサーバの状態は常に同じにならなければいけません。複数回実行すると結果が変わってしまうようなコードを書いていると、誤って複数回実行したときにトラブルの元になりますし、コードを見てもサーバの状態を知ることができなくなります。

サーバの状態を「収束」させる

コードには「サーバのあるべき状態」が記述されていますので、各サーバに微妙な違いがあったとしても、Chef を実行したときにサーバはコードに書いてある通りの状態に収まらないといけません。Chef では「実行するたびに、サーバが本来あるべき状態に収まる」ことを「収束」と表現しています。

サーバの状態は全て Chef に管理させる

Chef はサーバの状態を管理するためのツールなので、Chef を使うと決めたらパッケージの管理や設定は全て Chef にまかせてしまった方がいいです。手動でインストールしたパッケージがあったりしたら、コードだけを見てもサーバの状態を知ることができなくなります。

Chef のインストール

普段から Ruby を使っている人であれば、Rubygems からダウンロードしてインストールするのが楽だと思います。

$ gem install chef

公式ドキュメントや『Chef実践入門』や多くのブログ記事ではこの方法が紹介されています。

それ以外だと、公式サイトに「Chef Development Kit」という便利なツールキットが用意されていますので、こちらをインストールする方法もあります。

Chef Development Kit

公式チュートリアルは「Chef Development Kit」を使うことを想定していますので、公式チュートリアルに沿って勉強したい方は「Chef Development Kit」を使った方がいいのかもしれません。

chef-apply コマンドを使って Hello, world する

カレントディレクトリに「Hello, world!」と書かれたファイルを出力するレシピを作り、chef-apply というレシピを単体実行するコマンドを使って実行する演習を行って、レシピの書き方と Chef の動作のイメージを掴みましょう。

まずは以下のようなコードを記述します。

# ./hello_recipe.rb
file 'hello_world.txt' do
  content 'Hello, world!'
end

このコードが今回のレシピになります。大雑把に説明すると、「カレントディレクトリにある hello_world.txt ファイルには『Hello, World!』という内容が書かれていること」という定義を書きました。 早速 chef-apply コマンドを使ってレシピを実行してみます。

$ chef-apply hello_recipe.rb
Recipe: (chef-apply cookbook)::(chef-apply recipe)
  * file[hello_world.txt] action create
    - create new file hello_world.txt
    - update content in file hello_world.txt from none to dffd60
    --- hello_world.txt 2014-07-05 15:01:15.000000000 +0900
    +++ /var/folders/40/rs6fnn7n7k190r2p1bsfz81w0000gn/T/.hello_world.txt20140705-2513-1ralz4i 2014-07-05 15:01:15.000000000 +0900
    @@ -1 +1,2 @@
    +Hello, World!

うまくできたのでしょうか?生成されたファイルの内容を見てみます。

$ ls
hello_recipe.rb
hello_world.txt

$ cat hello_world.txt
Hello, world!

大成功でした!ついでに、冪等であることを確認するために、もう一度 chef-apply コマンドを実行してみます。

$ chef-apply hello_recipe.rb
Recipe: (chef-apply cookbook)::(chef-apply recipe)
  * file[hello_world.txt] action create (up to date)

もう一度ファイルの内容を見てみます。

$ cat hello_world.txt
Hello, world!

内容が変わっていませんね。複数回実行しても内容が変わりませんでしたので、「冪等である」と言えますね。今度は少し意地悪をして、hello_world.txt の内容を手動で書き換えてみます。

$ vi hello_world.txt
- Hello, word!
+ Have fun.

この状態で chef-apply コマンドを実行するとどうなるのでしょうか?試してみます。

$ chef-apply hello_recipe.rb

================================================================================
    Error executing action `create` on resource 'file[hello_world.txt]'
    ================================================================================

    Errno::EACCES
    -------------
    Permission denied @ dir_s_mkdir - /var/chef

# 以下略

エラーが出てしまいました。/var/chef ディレクトリ作成時の権限エラーなようですので、sudo を付けて実行します。

$ sudo chef-apply hello_recipe.rb
Recipe: (chef-apply cookbook)::(chef-apply recipe)
  * file[hello_world.txt] action create
    - update content in file hello_world.txt from 20a627 to dffd60
    --- hello_world.txt 2014-07-05 15:14:13.000000000 +0900
    +++ /tmp/.hello_world.txt20140705-2998-109c1on      2014-07-05 15:17:27.000000000 +0900
    @@ -1,2 +1,2 @@
    -Have fun.
    +Hello, World!

今度はうまく実行できました。ファイルの内容を見てみます。

$ cat hello_world.txt
Hello, world!

先ほど編集した「Have fun.」という文字が消えて、「Hello, world!」が書かれている状態になっています。これが「Chef を実行すると、サーバごとに個別に行った編集は消えて、あるべき状態に『収束』する」ということですね。 ちなみに、元々のファイル内容は /var/chef/backup ディレクトリにバックアップされるようです。(先ほど出たエラーは、バックアップの書き込みに失敗したというエラーだったようです。)

$ cat /var/chef/backup/hello_world.txt.chef-20140705151727.409540
Have fun.

少し使ってみての感想

「クライアント・サーバ形式」と「スタンドアロン形式」の違いを理解するのはそこまで難しいことではない

「『Chef Server/Client』と『Chef Solo』の違いがわかりにくい!」 という話しをよく聞きますが、公式サイトで優しく説明されていましたので、違いがわかりにくい感じはしませんでした。Syslog などクライアント・サーバ形式のツールを使ったことがある方ならば、公式サイトトップの「How chef works」項目にある図を見て勉強すれば、そんなに時間はかからずに違いがわかるようになるのではないでしょうか。

「Chef Server/Client」は中規模以上のサーバ構成向けのツール

アプリケーションサーバが3台あって、DBサーバが1台あって、ステージング用のサーバが1台あって……といった中規模以上のサーバ構成にならない限りは Chef Server は使う必要はなさそうに思えました。残念ですが、当分の間は私には触る機会がないかもしれないです。

「Chef Developer Kit」を使うと導入が楽になる

「Chef Developer Kit」には Ruby や Chef や Berkshelf など、Chef を使う上で必要なものが一通り入っています。Ruby のインストールができていない場合は「Chef Developer Kit」を使ったほうが導入が楽になると思います。私の環境では Rubygems でインストールした Ohai を実行したときに端末がフリーズする不具合が発生してしまいましたので、私は「Chef Developer Kit」を使うことにしました。

用語が覚えにくい

シェフ、キッチン、クックブック、レシピ、ナイフ……一聞では何のことかわからない可愛い名前が付けられていて、用語が覚えにくいです。「chef-solo」とか「chef-client」とか「knife」とか、増えるコマンドが多いのも少し辛いです。

Ruby が好きな人には良さそう

「I love Ruby!」

知っておかないといけないことはこれだけではない

今回は基本的なことだけしか書いていませんので、Chef を使う上で知っておかないといけないことはまだまだあります。公式ドキュメントとか各書籍などを読んで勉強していきましょう。

Chef活用ガイド コードではじめる構成管理

Chef活用ガイド コードではじめる構成管理

Chef実践入門 ~コードによるインフラ構成の自動化 (WEB+DB PRESS plus)

Chef実践入門 ~コードによるインフラ構成の自動化 (WEB+DB PRESS plus)