『Chef 実践入門』読書メモ

読了。 Chef Server の章は流し読み。

第1章

  • Infrastructure as Code
    • インフラをコード(= Chef のレシピ)で記述し Github で管理

第2章

  • chef-solo は Chef のスタンドアロン
  • コードで書いたサーバー設定の手順が「レシピ」
  • レシピに必要なデータやファイルをまとめる入れ物が「クックブック」
  • クックブック群を含む、Chef の実行に必要なファイルをまとめる入れ物が「リポジトリ」または「キッチン」
  • knife はリポジトリを操作するツール
  • knife-solo は Chef を chef-solo 環境で実行するためのユーティリティツール
  • Chef で管理するサーバーのことを「ノード」
  • ノードの状態を JSON で記述したものが「Node オブジェクト」

第3章

  • 「リソース」は service, package, template といった部品
  • 「Attribute」はテンプレートやレシピで参照できる key-value の値を管理する仕組み
  • 「Ohai」は Chef がシステム情報を取得するのに使っている Ruby ライブラリ
  • Attribute はノードの属性
  • 各ノードで共有したいデータには「Data Bug」を使う

第4章

  • Berkshelf を使ってコミュニティクックブックをインポートできる
  • 複数ノードへ chef-solo を実行する場合
    • xargs を使う
    • capistrano や fabric といった外部ツールを使う
    • Chef Server を使う

第5章

第6章

  • 特に無し

第7章

  • Test Kitchen
    • Chef のクックブックをテストするためのツール
    • Vagrant と組み合わせて、複数の OS や OS のバージョンでクックブックをテストできる
  • Test Kitchen では Minitest、Serverspec でテストを記述できる
  • さらに Jenkins を使ってクックブックでも CI

第8章

  • 従来のサーバー構築手順やスクリプトをクックブック化するところから始める
  • コミュニティクックブックを参考にする
    • Opscode
    • Basecamp
  • Foodcritic を使えばクックブックを検査できる
  • Chef でアプリケーションをデプロイしたい場合
  • Chef の拡張

第9章

  • Chef Server のメリット
    • Search 機能でロールなどを絞り込める
    • クックブックの同期作業がいらない
    • Chef Client をデーモンとしても扱える

第10章

  • 各ノードで chef-client コマンドを一括実行
    • tomahawk を使う
    • または knife ssh を使う
  • 大量物理サーバーをセットアップ

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

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

Capybara + Poltergeist を使ってテストするための環境を Vagrant + Chef で構築

プライベートで開発に関わっている Rails アプリが完成に近づいてきたので、 Capybara と RSpec を使ってインテグレーションテストを書くことにした。

JavaScript で動きをつけたページもきちんとテストしたいので、 JavaScript ドライバに Poltergeist を選択。

以下、作業メモ。

Chef で Phantomjs をインストール

まずは、Poltergeist が依存している、ヘッドレスブラウザの Phantomjs のインストールが必要。

Phantomjs はコミュニティ Cookbook を使ってインストールする。

Berkfile に

cookbook "phantomjs"

の1行を追加し、

berks vendor cookbooks

でインストール。既に cookbooks フォルダが存在する場合は、先に削除しておくこと。

開発環境は Vagrant で構築しているので、Vagrantfile に

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # ...

  config.vm.provision "chef_solo" do |chef|
    chef.cookbooks_path = ["./chef/cookbooks", "./chef/site-cookbooks"]

    # ...

    # Phantomjs のレシピを追加
    chef.add_recipe "phantomjs::default"
  end
end

を記述して

vagrant provision

を実行。

Capybara と Poltergeist をインストール

ここからは vagrant ssh仮想マシンに入って作業する。

Rails プロジェクトの Gemfile に

group :test do
  # 下記を追加
  gem "capybara"
  gem "database_cleaner"
  gem "poltergeist"
end

を記述。投入したテストデータがちゃんと削除されるように、database_cleaner もあわせて使う。

bundle install

を実行してインストール。

Capybara と Poltergeist と DatabaseCleaner を有効にする

spec_helper.rb に、Capybara と Poltergeist と DatabaseCleaner の設定を記述。

# ...

# Capybara の設定
require 'capybara/rspec'
require 'capybara/rails'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist

RSpec.configure do |config|
  # ...

  # database_cleaner の設定
  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end
  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end
end

これで準備完了

あとは spec/features フォルダ下にフィーチャーを書いて、

bin/rake spec:features

でテストを走らせればいい。

下記のように、js: true オプションを指定した箇所は Poltergeist を使って実行されるようになる。

describe "JavaScript を使ったページのテスト", js: true do
  it "JavaScript が実行されたかのテスト" do
    # テスト内容を書く
  end
end

Rails 開発環境を構築するために Chef を使って PostgreSQL をインストールするメモ

Rails アプリの開発環境を Vagrant + Chef で構築していて、 PostgreSQL のインストールでつまづいたのでメモ。

まず Berkshelf で postgresql のクックブックをダウンロード。

echo cookbook "postgresql" >> Berksfile
berks vendor cookbooks

postgresql クックブックはそのまま使うと、どうしてもエンコーディングUTF-8 を指定してデータベースを作成できなかった。 対策として、postgresql をインポートするクックブックを新規作成する。

knife cookbook create postgresql_server_utf8

デフォルトのレシピを記述。

ENV["LANGUAGE"] = ENV["LANG"] = ENV["LC_ALL"] = "en_US.UTF-8"
include_recipe "postgresql::server"

環境変数をセットしているのがポイント。

あとは Vagrantfile に

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hashicorp/precise64"

  config.vm.provision "chef_solo" do |chef|
    chef.cookbooks_path = ["./chef/cookbooks", "./chef/site-cookbooks"]

    chef.add_recipe "postgresql_server_utf8"
    chef.json = {
      "postgresql" => {
        "password" => {
          "postgres" => "postgres"
        },
        "initdb_locale" => "en_US.UTF-8",
        "config" => {
          "lc_messages" => "en_US.UTF-8",
          "lc_monetary" => "en_US.UTF-8",
          "lc_numeric" => "en_US.UTF-8",
          "lc_time" => "en_US.UTF-8"
        }
      }
    }
  end
end

を書いて、vagrant up/provision を実行すれば、 PostgreSQL をインストールできた。 エンコーディングUTF-8 を指定してデータベースを作成できるようにもなった。

Capistrano で Ruby と chef のインストールを自動化

アプリサーバーで使うパッケージのセットアップを chef-solo で自動化できたけど、Ruby と chef をインストールする作業は手作業のまま。この部分も自動化したい。

そこで Capistrano を使って Ruby と chef をインストールするスクリプトを書いてみた。

# coding: utf-8
set :application, "<app name>"
set :user, "<username>"
set :port, 10022
set :ruby_version, "1.9.3-p194"

role :app, "<host name>"

default_run_options[:pty] = true

desc "git tasks"
namespace :git do
  desc "install git"
  task :install, :roles => :app do
    sudo "yum install -y git"
  end
end

desc "rbenv tasks"
namespace :rbenv do
  desc "delete old rbenv"
  task :cleanup, :roles => :app do
    run "rm ~/.bash_profile"
    run "rm -rf ~/.rbenv"
  end

  desc "checkout newest rbenv"
  task :checkout, :roles => :app do
    run "git clone https://github.com/sstephenson/rbenv.git ~/.rbenv"
  end

  desc "configure shell"
  task :config, :roles => :app do
    run "echo 'export PATH=$HOME/.rbenv/bin:$PATH' >> ~/.bash_profile"
    run "echo 'eval \"$(rbenv init -)\"' >> ~/.bash_profile"
    run "source ~/.bash_profile"
  end

  desc "install rbenv"
  task :install, :roles => :app do
    cleanup
    checkout
    config
  end
end

desc "ruby-build tasks"
namespace :ruby_build do
  desc "delete old ruby-build"
  task :cleanup, :roles => :app do
    run "rm -rf ~/.rbenv/plugins/ruby-build"
  end

  desc "checkout newest ruby-build"
  task :checkout, :roles => :app do
    run "git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build"
  end

  desc "install ruby-build"
  task :install, :roles => :app do
    cleanup
    checkout
  end
end

desc "ruby tasks"
namespace :ruby do
  desc "install required packages to build ruby"
  task :prepare, :roles => :app do
    sudo "yum install -y " + %w[
      gcc-c++
      zlib-devel
      httpd-devel
      openssl-devel
      curl-devel
      ncurses-devel
      gdbm-devel
      readline-devel
      sqlite-devel
    ].join(" ")
  end

  desc "build ruby"
  task :build, :roles => :app do
    run "rbenv install #{ruby_version}"
    run "rbenv global #{ruby_version}"
  end

  desc "install ruby"
  task :install, :roles => :app do
    prepare
    build
  end
end

desc "chef tasks"
namespace :chef do
  desc "install chef-solo"
  task :install, :roles => :app do
    run "gem install chef --no-rdoc --no-ri"
    run "rbenv rehash"
  end

  desc "checkout newest chef-repo"
  task :repo, :roles => :app do
    run "rm -rf chef-repo"
    run "git clone https://bitbucket.org/<username>/chef-repo.git"
  end

  desc "execute chef-solo"
  task :solo, :roles => :app do
    sudo "env PATH=$PATH chef-solo -c ~/chef-repo/.chef/solo.rb -j ~/chef-repo/.chef/chef.json"
  end
end

desc "setup application server"
task :setup, :roles => :app do
  git.install
  rbenv.install
  ruby_build.install
  ruby.install
  chef.install

  chef.repo
  chef.solo
end

Ruby は rbenv + ruby-build を使ってインストールする。rbenv と ruby-build のインストールするために、 git を最初にインストールするようにした。

この Capfile を

cap setup

で実行すると、Ruby と chef がインストールされ、chef-solo が実行される。サーバーのセットアップ作業の大部分がコマンド1つで済むようになった。

あと残すのは、ユーザー追加や SSH の設定だけど、この部分はどうしようかな。何とかして自動化できないか考えてみよう。

chef-solo で環境構築を自動化する練習メモ

はじめに

さくら VPSRails アプリをデプロイするために、Nginx や MySQL やらインストールしてみたけど、同じ作業を VMware Player+CentOS でテストするときにやるかもしれない。さらには、将来 Amazon EC2 を使うときにも。今から環境構築は自動化しておいた方がよさそうだ。

chef を使ってみる

chef といっても、chef-solo だけど。chef-client/chef-server は導入が超面倒なので。その点、chef-solo はスタンドアロンで動くから導入が手軽。
パッケージのインストールだけなら rake や capistrano でもできるけど、設定ファイルを配置したいし、chef でいく。

chef をインストール

CentOS では既に rbenv + ruby-build を使って Ruby1.9.3 をインストールしてあるので、chef のインストルは gem で一発。

# chef をインストール
gem install chef --no-rdoc --no-ri

# rbenv を使っていたら必要
rbenv rehash

レシピの雛型を入手

chef で使うレシピの雛型が Github で公開されている。

これを基に、レシピを作成していく。

ホームディレクトリで

git clone https://github.com/opscode/chef-repo.git

を実行してダウンロード。

Vim をインストールするレシピを作成してみる

今回は練習として、Vim をインストールするレシピを書いてみる。作業は che-repo 内で行う。

cookbook 作成
rake new_cookbook COOKBOOK=vim

で cookbook を作成。cookbook はインストールするパッケージごとに作成するのがいいみたいだ。
本当は knife コマンドを使った方がいいんだけど、上手く動かなかったので、ひとまず new_cookbook で回避した。後で調べないとな。

レシピを記述

yum リポジトリから Vim をインストールし、設定ファイルを配置するレシピを書いてみる。

chef-repo/cookbooks/vim/recipes/default.rb に次を記述。

package "vim" do
  action :install
end

rcfile = File.join(node[:vim][:dir], ".vimrc")
template rcfile do
  source "vimrc.erb"
end

file rcfile do
  owner node[:vim][:user]
end
設定ファイルのテンプレートを記述

chef-repo/cookbooks/vim/templates/default/vimrc.erb に次を記述。

syntax on
filetype on
filetype indent on
filetype plugin on

set autoindent
set expandtab
set number
set nobackup

set backspace=indent,eol,start
set tabstop=2
set softtabstop=2
set shiftwidth=2
Attributes を記述

レシピやテンプレートで使う値を chef-repo/cookbooks/vim/attributes/default.rb に記述する。

default[:vim][:dir] = "/home/test"
default[:vim][:user] = "test"

インストール先やユーザー名など、環境によって変わる値は、レシピに直接書かずに Attributes に書くのがよさそうだな。

chef-solo を実行してみる

その前に設定ファイルを作成

chef-repo/.chef/solo.rb を作成。

file_cache_path "/tmp/chef-solo"
cookbook_path "/home/test/chef-repo/cookbooks"

cookbooks のディレクトリを指定している。

実行するレシピを指定するファイル chef-repo/.chef/chef.json も作成。

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

今回は Vim だけ。

chef-solo 実行
sudo chef-solo -c .chef/solo.rb -j .chef/chef.json

を実行。

Vim がインストールされて、設定ファイルが配置されたら OK。

まとめ

今回は Vim 止まりだったけど、MySQL や Nginx などをインストールするレシピを作成しておけば、数コマンドでWebサーバーの環境を構築できるようになる。作成したレシピはもちろん git で管理しておこう。

そうそう、Github には cookbook が大量に公開されていた。

この中から拝借するのもいい。ただ、最初のうちは使い方を覚えるために、自分でレシピを書いた方がいいと思う。