Webアプリエンジニア養成読本 Advent Calendar 2014 23日目の記事です。

これまで、Webアプリエンジニア養成読本(以下 先のムック)のPHPデモアプリケーションをCentOS 7で動かすお話をしてきました。その中で、「Serverspecを利用した自動化(20日目)」と、すがさんが Itamae を利用した「Rubyでアプリケーション以外のコードを書く(19日目)」お話をしました。

その上で、サーバ構築自動化の総仕上げとして Itamae + Serverspec を用いてPHPアプリケーションが動くサーバを自動構築・自動テストにチャレンジしてみましょう!

本記事執筆時に利用したバージョンは、CentOS 7.0, Ruby 2.1.2p95, specinfra 2.10.4, Itamae 1.0.13, Serverspec 2.7.1 です。

Itamae, Serverspec の準備

最初に、インストールを行う対象となるサーバを準備します。次の状態を整えておいて下さい。

  • CentOS 7をインストールしたマシンを準備します。VMwareなど、手元のマシン上で動くVMにインストールしていただければ大丈夫です。
  • SSHの公開鍵認証でログインできるようにします。手順は、先のムック 3.2節 P.115に記載しています。
  • Ruby 2.0系以上をインストールしておきます。インストールしていない方は、先のムック 2.8節 P.65以降を参考にして下さい。
  • 可能であれば、構築直後の状態でSnapshotを取っておきましょう。

以上の準備が終わりましたら、次の手順を実行します。

$ mkdir (コードを保存するディレクトリ)
$ cd (コードを保存するディレクトリ)
$ gem install bundler
$ vim Gemfile   # 以下の内容を参考にして記述
$ bundle install
# Gemfile
source "https://rubygems.org"

gem "rake"
gem "itamae"
gem "serverspec"

以上で終了です。

コードを書く

Itamaeのレシピを書く

MySQL, Apache, PHPのレシピを書いて行きましょう。「CentOS 7でWebアプリエンジニア養成読本のサンプルを動かしてみる(PHP編)」の手順を基に作ってみます。すがさんのエントリをご覧頂いている方には、難なく書けるものです。

基本、コードを示しつつ、留意点を追加で説明します。

まず、MySQLから。4行目は、packagesリソースが現状sourceをサポートしていないため、commandで代用しています。20行目以降はmysql_secure_installation内部のコマンドをシミュレートしています。また、23行目はtestテーブルがなくなったバージョンがあるため、DROP時にエラーが起きても無視するようにしています。

# recipes/mysqld/mysqld.rb
MYSQL_PASSWORD=node[ENV['TARGET_HOST']]['mysqld']['password']

execute "yum -t -y install http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm"

%w{
  mysql-community-client
  mysql-community-devel
  mysql-community-server
}.each do |pkg_name|
  package pkg_name do
    action :install
  end 
end

service "mysqld" do
  action [ :enable, :start ]
end

execute "mysql -u root -e \"SET PASSWORD=PASSWORD('#{MYSQL_PASSWORD}');\""
execute "mysql -uroot -p#{MYSQL_PASSWORD} -e \"DELETE FROM mysql.user WHERE User='';\""
execute "mysql -uroot -p#{MYSQL_PASSWORD} -e \"DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');\""
execute "mysql -uroot -p#{MYSQL_PASSWORD} -e \"DROP DATABASE test;\"; echo"
execute "mysql -uroot -p#{MYSQL_PASSWORD} -e \"DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'\""
execute "mysql -uroot -p#{MYSQL_PASSWORD} -e \"FLUSH PRIVILEGES;\""

続いて、Apache, PHPです。こちらはMySQLに比べますとシンプルです。 php.ini は、既に編集済みのもの recipes/httpd/php.ini.erb として準備しました。

# recipes/httpd/httpd.conf
%w{
  httpd
  php
  php-gd
  php-mbstring
  php-xml
  php-pdo
  php-mysql
}.each do |pkg_name|
  package pkg_name do
    action :install
  end 
end

template "/etc/php.ini" do
  source "php.ini.erb"
end

service "httpd" do
  action [ :enable, :start ]
end

execute "firewall-cmd --permanent --add-service=http"
execute "firewall-cmd --reload"
execute "setsebool -P httpd_can_network_connect 1"

以上より、案外スッキリ書けます。Chefの文法に似ていますが、Chefほど複雑ではないので、覚えやすいかと思います。

Serverspecのテストを流用する

Serverspecのテストコードは、「Serverspecを利用した自動化(20日目)」で作成したものをそのまま流用します。

以下では、既にリポジトリにアップロードしているコードを流用するコマンドです。Windowsの方は、恐れ入りますが手動でダウンロードをお願いします。

$ mkdir -p spec/mysqld
$ cd spec/mysqld
$ wget https://raw.githubusercontent.com/koemu/webapp_mook_servertest/master/spec/saito-hb-vm007/mysql_spec.rb
$ cd ../../
$ mkdir -p spec/httpd
$ cd spec/httpd
$ wget https://raw.githubusercontent.com/koemu/webapp_mook_servertest/master/spec/saito-hb-vm007/httpd_spec.rb
$ cd ../../
$ cd spec
$ wget https://raw.githubusercontent.com/koemu/webapp_mook_servertest/master/spec/spec_helper.rb
$ cd ..

テストしたい状態が全く同じだから、テストコードが流用できるのです。

Rakefileを整える

Itamae はコマンドから直接レシピを実行できるのですが、せっかくなら Serverspec も一緒に実行したいですよね。そこで、同僚の @rrreeeyyy さんが作成した Rakefile を参考にします。これを使うと、設定ファイル properties.json に記述したサーバに対して、 Itamae による構築と Serverspec によるテストを同時にこなせるようになり、大変便利です。

なお、先のRakefileは今回のブログ用に数カ所編集しています。以下からダウンロードして利用して下さい。

$ wget https://raw.githubusercontent.com/koemu/webapp_mook_itamae_demo/master/Rakefile

続いて properties.json を準備します。今回は、ホスト名:saito-hb-vm007, IPアドレス:192.168.29.107 のサーバに対して実行できるようにします。なお、ホスト名・IPアドレスは、ご自身の環境に合わせて書き換えて下さい。

(properties.json の記述例)

{
  "saito-hb-vm007": {
    "ssh_user": "root",
    "ssh_port": 22,
    "roles": ["mysqld", "httpd"]
  }
}

最後に、SSHで接続できるように .ssh/config を編集しましょう。20日目のエントリで既に記述されていれば何もしなくて結構です。

(.ssh/config の記述例)

Host saito-hb-vm007
  HostName 192.168.29.107
  User (任意のユーザ名)

あらかじめ、recipesとspecは以下にディレクトリを作成しておく事で、ロールとして分類する事ができるようになっています。従って、 mysqld だけを実行する事も可能です。

以上で準備完了です。おつかれさまでした。

いざ実行!

まず、 rake コマンド実行の際に使えるオプションを確認します。ここまでの作業が正しくできている場合、コマンドを入力すると次の結果が得られるはずです。

$ bundle exec rake -vT
rake itamae:saito-hb-vm007      # Run itamae to saito-hb-vm007
rake serverspec:saito-hb-vm007  # Run serverspec to saito-hb-vm007

では、実行してみましょう。

$ bundle exec rake itamae:saito-hb-vm007 serverspec:saito-hb-vm007
bundle exec itamae ssh -h saito-hb-vm007 -u root -i  -p 22 -j properties.json recipes/mysqld/mysqld.rb recipes/httpd/httpd.rb
 INFO : Starting Itamae...
 INFO : Loading node data from /Users/saito/repos/webapp_mook_itamae_demo/properties.json...
 INFO : Recipe: /Users/saito/repos/webapp_mook_itamae_demo/recipes/mysqld/mysqld.rb
 INFO :    execute[yum -y install http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm]
 INFO :       action: run
(中略)
  MySQLにrootユーザでログインできる
    Command "mysql -uroot -pCHANGE_ME~ -e "SELECT user FROM mysql.user""
      exit_status
        should eq 0

Finished in 1.03 seconds (files took 0.2482 seconds to load)
21 examples, 0 failures

無事、自動インストール、そして自動テストが完了しました。

このあと、先のムックのPHP用デモアプリケーションである Tinitter をデプロイすると、 Tinitter が使えるようになります。

まとめ

ここまで、Itamae + Serverspec を用いた、サーバの構築・テストの自動化についてお話ししました。ソフトウェア開発でアプリケーション用のコードを書くのとともにテストコードを書くように、ITインフラをソフトウェアで自動化するときにも、構築手順と状態テストを同時に記述する事ができるのを知っていただけたかと思います。

ここまで紹介したスクリプトは、GitHub koemu/webapp_mook_itamae_demo に保存しています。あわせてご覧ください。

自動構築できるようになると、サーバ増設やテストサーバ構築時も当然自動化できますから、そのメリットはますますはっきりしてきます。手動による暖かみのあるサーバ構築はそろそろ終わりにして、サーバ構築をさくさく自動化することで、早く帰って酒を飲みましょう!!!

なお、以上の事を本格的に取り組む場合は、 Rakefile と spec_helper.rb に工夫が必要になります。このあたりをしっかりやろうとすると Ruby の知識がより深く必要となります。その時は、すがさんたちが執筆している「パーフェクトRuby」などを読んでみてください。

最後にちょっとだけ宣伝です。

僕の現職の上司である @netmarkjp さんが、ITインフラの設計・構築・運用・そしてチューニングまでを体系的に解説した本を出します。特に、チューニングのための指標の読み方は多くの方に役立つものになると思います。ITインフラにお悩みの方、先のムックの内容より更に一歩進んでみたい方は、ぜひお買い求め下さい。

それでは皆様、ごきげんよう。

※大型書店で立ち読みしてみてね!

謝辞

  • Rakefile の内容については、 @rrreeeyy さんの Rakefile をベースにしました。どうもありがとうございました。