ItamaeとServerspecを使ったサーバ構築と自動テストを試してみた
まえがき
こんにちはじょにーです。夏休みの自由研究です。
前から触ってみたかったItamaeと、Serverspecによるテストを行える環境を作ってみました。
こえむさんによる
Itamae + Serverspec でサーバ構築・テスト自動化 総仕上げ! | こえむの編集後記
こちらを参考に(というかほぼそのままなぞって)CentOS7にてItamaeとServerspec によるインフラ構築を試した記録です。
ほぼそのままなぞっただけですので、本来は記事として書くようなことでもないのですが、
特に予備知識なくそのままなぞった際に、うまくく動かないところがありましたので、トライアンドエラーを繰り返してかつそのまま記載しています。そのあたりの試行の参考になればいいなという感じです。
手順
IDCFクラウドにてCentOS7.1の仮想サーバーを2台準備しました
- admin01
- node01
上記にログインして進めていきます。
admin01を作業環境として、
node01にmysqlとhttpd、phpをインストール&テスト という使い方をしてみます。
まずはadmin01にログインし、
rubyのバージョンが2.0以上であることを確認します
[root@admin01 ~]# ruby -v ruby 2.0.0p598 (2014-11-13) [x86_64-linux]
admin01のhostsにnode01のローカルIPを記載します
[root@admin01 ~]# vi /etc/hosts (10.3.0.222 node01 を追記。IPアドレスはIDCFクラウドの管理画面より確認) [root@admin01 ~]# cat /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 10.3.0.222 node01
手順に従って、Itamae, Serverspecをインストールして準備します
[root@admin01 ~]# mkdir work [root@admin01 ~]# cd work/ [root@admin01 work]# gem install bundler Fetching: bundler-1.10.6.gem (100%) Successfully installed bundler-1.10.6 Parsing documentation for bundler-1.10.6 Installing ri documentation for bundler-1.10.6 1 gem installed [root@admin01 work]# vim Gemfile [root@admin01 work]# cat Gemfile # Gemfile source "https://rubygems.org" gem "rake" gem "itamae" gem "serverspec" [root@admin01 work]# bundle install
レシピを書いてみます
レシピ配置用のディレクトリを作っておきます
[root@admin01 work]# mkdir recipes [root@admin01 work]# mkdir recipes/mysqld [root@admin01 work]# mkdir recipes/httpd
お手本通りにmysqldのレシピを作成します
[root@admin01 work]# vi recipes/mysqld/mysqld.rb [root@admin01 work]# cat recipes/mysqld/mysqld.rb # 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;\""
続いて、httpdのレシピです
[root@admin01 work]# vi recipes/httpd/httpd.rb [root@admin01 work]# cat recipes/httpd/httpd.rb # recipes/httpd/httpd.rb %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"
php.iniはとりあえずローカルにあったものを持ってきてみました
[root@admin01 work]# cp /etc/php.ini ./recipes/httpd/php.ini.erb
手順に従ってServerspecのテストを持ってきます
[root@admin01 work]# mkdir -p spec/mysqld [root@admin01 work]# cd spec/mysqld [root@admin01 mysqld]# wget https://raw.githubusercontent.com/koemu/webapp_mook_servertest/master/spec/saito-hb-vm007/mysql_spec.rb 中略 2015-08-13 15:56:12 (209 MB/s) - `mysql_spec.rb' へ保存完了 [1093/1093] [root@admin01 mysqld]# cd ../../ [root@admin01 work]# mkdir -p spec/httpd [root@admin01 work]# cd spec/httpd [root@admin01 httpd]# wget https://raw.githubusercontent.com/koemu/webapp_mook_servertest/master/spec/saito-hb-vm007/httpd_spec.rb 中略 2015-08-13 15:56:33 (341 MB/s) - `httpd_spec.rb' へ保存完了 [1777/1777] [root@admin01 httpd]# cd ../../ [root@admin01 work]# cd spec [root@admin01 spec]# wget https://raw.githubusercontent.com/koemu/webapp_mook_servertest/master/spec/spec_helper.rb 中略 2015-08-13 15:56:51 (136 MB/s) - `spec_helper.rb' へ保存完了 [679/679] [root@admin01 spec]# cd ..
Rakefileを整えてみます
[root@admin01 work]# wget https://raw.githubusercontent.com/koemu/webapp_mook_itamae_demo/master/Rakefile 2015-08-13 15:59:16 (192 MB/s) - `Rakefile' へ保存完了 [1004/1004]
properties.jsonを書きます
[root@admin01 work]# vi properties.json [root@admin01 work]# cat properties.json { "node01": { "ssh_user": "root", "ssh_port": 22, "roles": ["mysqld", "httpd"] } }
sshの設定をします
[root@admin01 work]# vi ~/.ssh/config [root@admin01 work]# cat ~/.ssh/config Host node01 HostName node01 User root IdentityFile ~/.ssh/hoge.key
確認をします
[root@admin01 work]# bundle exec rake -vT rake aborted! LoadError: cannot load such file -- json /root/work/Rakefile:2:in `require' /root/work/Rakefile:2:in `<top (required)>' (See full trace by running task with --trace) [root@admin01 work]#
あれ、怒られましたね
jsonを入れます
[root@admin01 work]# gem install json Fetching: json-1.8.3.gem (100%) Building native extensions. This could take a while... ERROR: Error installing json: ERROR: Failed to build gem native extension. /usr/bin/ruby extconf.rb mkmf.rb can't find header files for ruby at /usr/share/include/ruby.h Gem files will remain installed in /usr/local/share/gems/gems/json-1.8.3 for inspection. Results logged to /usr/local/share/gems/gems/json-1.8.3/ext/json/ext/generator/gem_make.out
さらに怒られました Gemfileでやってみよう
[root@admin01 work]# vi Gemfile [root@admin01 work]# cat Gemfile # Gemfile source "https://rubygems.org" gem "json" gem "rake" gem "itamae" gem "serverspec" [root@admin01 work]# bundle install
なんか入ったっぽい
再度確認します
[root@admin01 work]# bundle exec rake -vT rake aborted! LoadError: cannot load such file -- json/pure /usr/share/gems/gems/json-1.7.7/lib/json.rb:60:in `require' /usr/share/gems/gems/json-1.7.7/lib/json.rb:60:in `rescue in <module:JSON>' /usr/share/gems/gems/json-1.7.7/lib/json.rb:57:in `<module:JSON>' /usr/share/gems/gems/json-1.7.7/lib/json.rb:54:in `<top (required)>' /root/work/Rakefile:2:in `require' /root/work/Rakefile:2:in `<top (required)>' (See full trace by running task with --trace)
ありゃ、今度はjson/pureがないそうです
Gemfileに書き足して再度bundle installします
[root@admin01 work]# vi Gemfile [root@admin01 work]# cat Gemfile # Gemfile source "https://rubygems.org" gem "json" gem "json_pure" gem "rake" gem "itamae" gem "serverspec" [root@admin01 work]# bundle install
なんか入ったっぽい
再再度確認します
[root@admin01 work]# bundle exec rake -vT rake itamae:node01 # Run itamae to node01 rake serverspec:node01 # Run serverspec to node01
OKでしたね
いよいよitamaeの実行とテストです
[root@admin01 work]# bundle exec rake itamae:node01 serverspec:node01 bundle exec itamae ssh -h node01 -u root -i -p 22 -j properties.json recipes/mysqld/mysqld.rb recipes/httpd/httpd.rb INFO : Starting Itamae... INFO : Loading node data from /root/work/properties.json... /usr/local/share/gems/gems/net-ssh-2.9.2/lib/net/ssh.rb:224:in `start': Authentication failed for user root@node01 (Net::SSH::AuthenticationFailed)
おっと 中略しますが鍵認証で接続できてませんでした
Rakefileをよく読むと鍵の指定をしているようなので、properties.jsonに鍵の指定を追記します
[root@admin01 work]# vi properties.json [root@admin01 work]# cat properties.json { "node01": { "ssh_user": "root", "ssh_port": 22, "private_key": "~/.ssh/hoge.key", "roles": ["mysqld", "httpd"] } }
再度実行してみます
[root@admin01 work]# bundle exec rake itamae:node01 serverspec:node01 (中略) /root/work/recipes/mysqld/mysqld.rb:2:in `load': undefined method `[]' for nil:NilClass (NoMethodError)
ということで、ちょっと謎のエラーが出て解決できないので、切り分けも含めてmysqldの実行とテストを後回しにします
properties.jsonからmysqldを削除
[root@admin01 work]# vi properties.json [root@admin01 work]# cat properties.json { "node01": { "ssh_user": "root", "ssh_port": 22, "private_key": "~/.ssh/hoge.key", "roles": ["httpd"] } }
httpdのみの設定で、実行してみます
[root@admin01 work]# bundle exec rake itamae:node01 serverspec:node01 bundle exec itamae ssh -h node01 -u root -i ~/.ssh/hoge.key -p 22 -j properties.json recipes/httpd/httpd.rb INFO : Starting Itamae... INFO : Loading node data from /root/work/properties.json... INFO : Recipe: /root/work/recipes/httpd/httpd.rb INFO : package[httpd] installed will change from 'false' to 'true' INFO : package[php] installed will change from 'false' to 'true' INFO : package[php-gd] installed will change from 'false' to 'true' INFO : package[php-mbstring] installed will change from 'false' to 'true' INFO : package[php-xml] installed will change from 'false' to 'true' INFO : package[php-pdo] installed will change from 'false' to 'true' INFO : package[php-mysql] installed will change from 'false' to 'true' INFO : diff: INFO : --- /etc/php.ini 2015-06-24 06:20:23.000000000 +0900 INFO : +++ /tmp/itamae_tmp/1439455347.5930629 2015-08-13 17:42:27.843020664 +0900 INFO : @@ -210,7 +210,7 @@ INFO : ; http://php.net/short-open-tag INFO : short_open_tag = Off INFO : INFO : -; Allow ASP-style <% %> tags. INFO : +; Allow ASP-style tags. INFO : ; http://php.net/asp-tags INFO : asp_tags = Off INFO : INFO : service[httpd] enabled will change from 'false' to 'true' INFO : service[httpd] running will change from 'false' to 'true' INFO : execute[firewall-cmd --permanent --add-service=http] executed will change from 'false' to 'true' ERROR : stdout | [91mFirewallD is not running[00m ERROR : Command `firewall-cmd --permanent --add-service=http` failed. (exit status: 252) ERROR : execute[firewall-cmd --permanent --add-service=http] Failed. /usr/bin/ruby -I/usr/local/share/gems/gems/rspec-core-3.3.2/lib:/usr/local/share/gems/gems/rspec-support-3.3.0/lib /usr/local/share/gems/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\{httpd\}/\*_spec.rb .......FF.... Failures: 1) Apacheのインストール PHPのインストール php.iniの設定を変更している Php config "date.timezone" value should eq "Asia/Tokyo" Failure/Error: its(:value) { should eq "Asia/Tokyo" } expected: "Asia/Tokyo" got: "" (compared using ==) # ./spec/httpd/httpd_spec.rb:38:in `block (5 levels) in <top (required)>' 2) Apacheのインストール PHPのインストール php.iniの設定を変更している Php config "mbstring.internal_encoding" value should eq "UTF-8" Failure/Error: its(:value) { should eq "UTF-8" } expected: "UTF-8" got: "" (compared using ==) # ./spec/httpd/httpd_spec.rb:42:in `block (5 levels) in <top (required)>' Finished in 1.32 seconds (files took 0.26656 seconds to load) 13 examples, 2 failures Failed examples: rspec ./spec/httpd/httpd_spec.rb:38 # Apacheのインストール PHPのインストール php.iniの設定を変更している Php config "date.timezone" value should eq "Asia/Tokyo" rspec ./spec/httpd/httpd_spec.rb:42 # Apacheのインストール PHPのインストール php.iniの設定を変更している Php config "mbstring.internal_encoding" value should eq "UTF-8" /usr/bin/ruby -I/usr/local/share/gems/gems/rspec-core-3.3.2/lib:/usr/local/share/gems/gems/rspec-support-3.3.0/lib /usr/local/share/gems/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\{httpd\}/\*_spec.rb failed
テストはちゃんと動いたようです。ということはmysqldのレシピに問題がありそうです。あとで見てみましょう。
ひとまず、httpdのテスト結果の方はどうかというと、ローカルに適当に置いてあったphp.iniなのでテストと差分があります。
php.iniを修正します
[root@admin01 work]# vi recipes/httpd/php.ini.erb date.timezone = Asia/Tokyo mbstring.internal_encoding = UTF-8
再度実行してみます
[root@admin01 work]# bundle exec rake itamae:node01 serverspec:node01 bundle exec itamae ssh -h node01 -u root -i ~/.ssh/hoge.key -p 22 -j properties.json recipes/httpd/httpd.rb INFO : Starting Itamae... INFO : Loading node data from /root/work/properties.json... INFO : Recipe: /root/work/recipes/httpd/httpd.rb INFO : diff: INFO : --- /etc/php.ini 2015-08-13 17:42:27.843020664 +0900 INFO : +++ /tmp/itamae_tmp/1439455835.036678 2015-08-13 17:50:35.053458574 +0900 INFO : @@ -875,7 +875,7 @@ INFO : [Date] INFO : ; Defines the default timezone used by the date functions INFO : ; http://php.net/date.timezone INFO : -;date.timezone = INFO : +date.timezone = Asia/Tokyo INFO : INFO : ; http://php.net/date.default-latitude INFO : ;date.default_latitude = 31.7667 INFO : @@ -1663,7 +1663,7 @@ INFO : ; Some encoding cannot work as internal encoding. INFO : ; (e.g. SJIS, BIG5, ISO-2022-*) INFO : ; http://php.net/mbstring.internal-encoding INFO : -;mbstring.internal_encoding = EUC-JP INFO : +mbstring.internal_encoding = UTF-8 INFO : INFO : ; http input encoding. INFO : ; http://php.net/mbstring.http-input INFO : execute[firewall-cmd --permanent --add-service=http] executed will change from 'false' to 'true' ERROR : stdout | [91mFirewallD is not running[00m ERROR : Command `firewall-cmd --permanent --add-service=http` failed. (exit status: 252) ERROR : execute[firewall-cmd --permanent --add-service=http] Failed. /usr/bin/ruby -I/usr/local/share/gems/gems/rspec-core-3.3.2/lib:/usr/local/share/gems/gems/rspec-support-3.3.0/lib /usr/local/share/gems/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\{httpd\}/\*_spec.rb ............. Finished in 0.70656 seconds (files took 0.26856 seconds to load) 13 examples, 0 failures
php.iniの内容が書き換わり、テストを全部通過することが出来ました。これでhttpdについてはOKですね。
さてmysqldの方に戻ってみましょう レシピの設定で怪しかったところを変えます
[root@admin01 work]# vi /root/work/recipes/mysqld/mysqld.rb MYSQL_PASSWORD="TESTPASSWORD"
mysqldのテストを行うように、properties.jsonを書き換えます
[root@admin01 work]# vi properties.json [root@admin01 work]# cat properties.json { "node01": { "ssh_user": "root", "ssh_port": 22, "private_key": "~/.ssh/hoge.key", "roles": ["mysqld"] } }
mysqldの実行とテストと行います
[root@admin01 work]# bundle exec rake itamae:node01 serverspec:node01 bundle exec itamae ssh -h node01 -u root -i ~/.ssh/hoge.key -p 22 -j properties.json recipes/mysqld/mysqld.rb INFO : Starting Itamae... INFO : Loading node data from /root/work/properties.json... INFO : Recipe: /root/work/recipes/mysqld/mysqld.rb INFO : execute[yum -t -y install http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm] executed will change from 'false' to 'true' INFO : package[mysql-community-client] installed will change from 'false' to 'true' INFO : package[mysql-community-devel] installed will change from 'false' to 'true' INFO : package[mysql-community-server] installed will change from 'false' to 'true' INFO : service[mysqld] running will change from 'false' to 'true' INFO : execute[mysql -u root -e "SET PASSWORD=PASSWORD('TESTPASSWORD');"] executed will change from 'false' to 'true' INFO : execute[mysql -uroot -pTESTWASSWORD -e "DELETE FROM mysql.user WHERE User='';"] executed will change from 'false' to 'true' INFO : execute[mysql -uroot -pTESTWASSWORD -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"] executed will change from 'false' to 'true' INFO : execute[mysql -uroot -pTESTWASSWORD -e "DROP DATABASE test;"; echo] executed will change from 'false' to 'true' INFO : execute[mysql -uroot -pTESTWASSWORD -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%'"] executed will change from 'false' to 'true' INFO : execute[mysql -uroot -pTESTWASSWORD -e "FLUSH PRIVILEGES;"] executed will change from 'false' to 'true' /usr/bin/ruby -I/usr/local/share/gems/gems/rspec-core-3.3.2/lib:/usr/local/share/gems/gems/rspec-support-3.3.0/lib /usr/local/share/gems/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\{mysqld\}/\*_spec.rb .......F Failures: 1) MySQLのインストール MySQLにrootユーザでログインできる Command "mysql -uroot -phbadmin -e "SELECT user FROM mysql.user"" exit_status should eq 0 Failure/Error: its(:exit_status) { should eq 0 } expected: 0 got: 1 (compared using ==) # ./spec/mysqld/mysql_spec.rb:40:in `block (4 levels) in <top (required)>' Finished in 0.70786 seconds (files took 0.25649 seconds to load) 8 examples, 1 failure Failed examples: rspec ./spec/mysqld/mysql_spec.rb:40 # MySQLのインストール MySQLにrootユーザでログインできる Command "mysql -uroot -phbadmin -e "SELECT user FROM mysql.user"" exit_status should eq 0 /usr/bin/ruby -I/usr/local/share/gems/gems/rspec-core-3.3.2/lib:/usr/local/share/gems/gems/rspec-support-3.3.0/lib /usr/local/share/gems/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\{mysqld\}/\*_spec.rb failed
一応ちゃんとテストまでできましたね。ということはnodeのあたりがうまく動いていなかったようですが、、、ruby全然わかりませんので誰か詳しい方教えてください><
さて今回のテストでFailedになった箇所を見てみますと、MySQLにrootでログインできなかった ということで、一番肝心なところがコケていたわけですが……。
テストの方を再度確認してみると
describe "MySQLにrootユーザでログインできる" do describe command('mysql -uroot -phbadmin -e "SELECT user FROM mysql.user"') do its(:exit_status) { should eq 0 } end end
とのことで、パスワードが違いますね。
-phbadmin ってこれ、いろいろ大丈夫かしらw
パスワードを書き換えます
[root@admin01 work]# vi spec/mysqld/mysql_spec.rb describe command('mysql -uroot -pTESTPASSWORD -e "SELECT user FROM mysql.user"') do
再度実行。
[root@admin01 work]# bundle exec rake itamae:node01 serverspec:node01 bundle exec itamae ssh -h node01 -u root -i ~/.ssh/hoge.key -p 22 -j properties.json recipes/mysqld/mysqld.rb INFO : Starting Itamae... INFO : Loading node data from /root/work/properties.json... INFO : Recipe: /root/work/recipes/mysqld/mysqld.rb INFO : execute[yum -t -y install http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm] executed will change from 'false' to 'true' ERROR : stdout | Loaded plugins: fastestmirror, remove-with-leaves, show-leaves ERROR : stdout | mysql-community-release-el7-5.noarch.rpm | 6.0 kB 00:00 ERROR : stdout | Examining /var/tmp/yum-root-cdVUFD/mysql-community-release-el7-5.noarch.rpm: mysql-community-release-el7-5.noarch ERROR : stdout | /var/tmp/yum-root-cdVUFD/mysql-community-release-el7-5.noarch.rpm: does not update installed package. ERROR : stdout | Error: Nothing to do ERROR : Command `yum -t -y install http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm` failed. (exit status: 1) ERROR : execute[yum -t -y install http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm] Failed. /usr/bin/ruby -I/usr/local/share/gems/gems/rspec-core-3.3.2/lib:/usr/local/share/gems/gems/rspec-support-3.3.0/lib /usr/local/share/gems/gems/rspec-core-3.3.2/exe/rspec --pattern spec/\{mysqld\}/\*_spec.rb ........ Finished in 0.36045 seconds (files took 0.27488 seconds to load) 8 examples, 0 failures
…無事通りました!この書き方ですと毎回executeでinstallしようとしてしまいますが、、、仕方ないですかね。
ともあれ、これでひとまず基礎的なところは追えたかと思います。
最近は仕事のほうでサーバーをちゃんと触る機会がなかなか少なくなって来てまして、久々に楽しかったです。rubyはわからんけど!w
余裕があれば後日、対象サーバーを増やしたりなどのバリエーションを試そうと思います。
僕のお財布にも余裕があるとたくさん増やせるのですが。。。まぁいいでしょうw