ServerSpecの使い方をインストールから解説!EC2のWebサーバを自動テスト

2022年2月9日AWS

SeverspecでEC2のUpdateサーバを自動テスト

今回は、Serverspecを使って自動テストを行います!

早速!

Serverspecとは

サーバのテストを自動で実行するRubyで作られたプログラムです。

具体的には、「接続できるか」、「必要なポートは開いているか」、「サービスは動いているか」など、サーバを作った後の確認を自動で行ってくれます。

なんで自動でやるのか

人間が手動でやるとどこかでミスが起こる可能性があるからです。

それは、コマンドの打ち間違いであったり、ちゃんとやってあるだろうという思い込み、実行するコマンドの抜け漏れなどなど。

正しいテストが行われていないと、サーバにアクセスできなかったり、正しい動きをしてくれなかったりと言った問題を見つけることができません。

そうすると、実際にサーバを公開したあと、ユーザーからのクレームでようやく気づくと言ったことが起こってしまします。

このようなミスはテストする項目が増えれば増えるほど発生する可能性が上がります。

では、早速やっていきましょう!

事前準備

自動テストをやるので、テストする対象が必要です。

今回実施する環境はこちら

Serverspec環境イメージ

シンプルな構成なので手動でもOKです。

しかし、本ブログではコードから作成する方法もご紹介しているのでぜひIaCを体験してみてください。

事前準備は以下の通り

No事前準備項目参考URL
1テスト環境の構築Terraform実践! インストールからEC2の構築までをまとめてみた!
2テストサーバの構築EC2にAnsibleをインストールしてWebサーバを構築する手順をインストールから解説
3rubyのインストールEC2にrubyをインストールする手順 ~rbenvからbundlerの解説~

Serverspecのインストール

Serverspecはgemです。

なので、rubyインストールの記事で解説しているように、bundlerを使ってテスト実行サーバにインストールします。

$ mkdir serverspec_test
$ cd serverspec_test
$ bundle init
$ echo gem '"serverspec"' >> Gemfile
$ echo gem '"rake"' >> Gemfile
$ bundle install --path vendor/bundle

これで、Serverspecのインストールは完了です。

Serverspecの他に"rake"というgemをインストールしています。

これは、rubyのビルドツールでこの後生成されるRakefileというファイルに書かれた内容を実行できるように準備(ビルド)してくれるコマンドです。

テストのセットアップ

次にseverspecのセットアップをします。

$ pwd
/home/ec2-user/serverspec_test
$ bundle exec serverspec-init
$ bundle exec serverspec-init
Select OS type:

  1) UN*X
  2) Windows

Select number: 1

Select a backend type:

  1) SSH
  2) Exec (local)

Select number: 1

Vagrant instance y/n: n
Input target host name: target
 + spec/
 + spec/target/
 + spec/target/sample_spec.rb
 + spec/spec_helper.rb

$ bundle exec serverspec-initを実行することでテストするために必要なファイルなどが自動生成されます。

項目内容設定値備考
Select OS typeOSのタイプを選択1Windowsの場合のみ2を選択
Select a backend type接続方法を選択1localhostに接続する場合のみ2を選択
Vagrant instancevagrantで管理しているサーバに対しての接続か否かnvagrantvirtualboxなどを利用して仮想サーバを作成できるツールです
Input target host nameターゲットのホスト名targetこのホスト名に対して接続します。なんでもOKです。

実行後のファイル

$ ls -l
合計 12
-rw-r--r-- 1 ec2-user ec2-user 175 10月 13 23:07 Gemfile
-rw-rw-r-- 1 ec2-user ec2-user 976 10月 13 23:07 Gemfile.lock
-rw-rw-r-- 1 ec2-user ec2-user 685 10月 13 23:08 Rakefile
drwxrwxr-x 3 ec2-user ec2-user  42 10月 13 23:08 spec
drwxrwxr-x 3 ec2-user ec2-user  20 10月 13 23:07 vendor

テストの準備

ここで、どのようなテストをするのかをファイルに書いていきます。

$ bundle exec serverspec-initを実行した時に以下のファイルが作成されていることでしょう。

種類名称用途
ファイルRakefilerakeコマンドで実行する内容が記載されています。
ディレクトリspecどのようなテストをするのかが記載されたファイルが中に入っています。

specの中身はこのような構成になっております。

$ tree ~/serverspec_test/spec/
/home/ec2-user/serverspec_test/spec/
├── spec_helper.rb
└── target
    └── sample_spec.rb

先に、使うコマンドや流れをイメージしやすいように実行までやってしまいましょう。

sample_spec.rbの編集

specディレクトリの中に$ bundle exec serverspec-init の「Input target host name」で指定した名前のディレクトリが生成されていると思います。

Serverspecはテストを実行する時specディレクトリ配下のディレクトリをテスト対象サーバとします。

今回、specディレクトリの下には、targetディレクトリがあり、その中にsample_spec.rbというどんなテストをするかを定義するファイルがあります。

なので、「targetというサーバに対してsample_spec.rbで定義されたテストを実行する。」という動作になります。

別のサーバに対してもテストを行いたい場合はspecの下にホスト名のディレクトリを作成します。

sample_spec.rbは以下のようになるよう編集してください。

require 'spec_helper'


describe package('httpd') do
 # httpdがインストールされていることを確認
  it { should be_installed }
end


describe service('httpd') do
  # httpdのサービスが起動していることを確認
  it { should be_enabled }
  # httpdのサービスが自動起動設定になっていることを確認
  it { should be_running }
end

describe port(80) do
  # テスト対象に80番ポートでアクセスできることを確認
  it { should be_listening }
end

describe file('/var/www/html/index.html') do
  # /var/www/html/index.htmlが存在することを確認
  it { should exist }
end

対象への接続設定

serverspceはテスト対象にsshで接続してテストを行うためテスト実行サーバからテスト対象サーバに指定したホスト名でssh接続させる必要があります。

今回、テスト対象を「target」としているためtargetを名前解決してssh接続させる設定が必要です。

秘密鍵の配置

テスト対象には鍵認証で接続します。

そのため、テスト実行サーバに秘密鍵を配置する必要があります。

ローカルに秘密鍵がある場合ローカルから以下のコマンドで秘密鍵を配置します。

$ scp -i <テスト実行サーバに接続するための秘密鍵> <テスト対象サーバに接続するための秘密鍵> ec2-user@<テスト実行サーバのIP>:~/.ssh/

~/.ssh/configの編集

このファイルはssh接続する時に参照される設定ファイルです。

すでにある場合は追記、なければ新規作成してください。

今回の場合、targetというサーバに対して接続し、テストを行いたいのでHostをtargetと指定します。

こうるすことでsshの実行は、$ ssh target とするだけで良くなります。

秘密鍵や接続ユーザの指定はssh実行時に自動で探して設定してくれます。

Host target
        HostName <対象のアドレス>
        IdentityFile ~/.ssh/<秘密鍵>
        User ec2-user
        ServerAliveInterval 30
設定項目設定値設定内容
Hosttargetこの設定の名前です。
HostName対象のIPアドレス実際に接続するIPアドレス(DNSで名前解決できればホスト名でもOK)
IdentityFile秘密鍵の絶対パスHostNameのサーバに対して接続する時に使う秘密鍵の絶対パス
Userec2-userHostNameのサーバに対して接続する時のユーザ
ServerAliveInternal30必須ではないです。
無操作時にssh接続がタイムアウトで切断されるのを防止します。

実行

実行はRakefileのあるディレクトリで実行してください。

うまくいっていれば以下のような出力になっているかと思います。

$ bundle exec rake spec
(in /home/ec2-user/serverspec_test)
/home/ec2-user/.rbenv/versions/3.0.2/bin/ruby -I/home/ec2-user/serverspec_test/vendor/bundle/ruby/3.0.0/gems/rspec-core-3.10.1/lib:/home/ec2-user/serverspec_test/vendor/bundle/ruby/3.0.0/gems/rspec-support-3.10.2/lib /home/ec2-user/serverspec_test/vendor/bundle/ruby/3.0.0/gems/rspec-core-3.10.1/exe/rspec --pattern spec/target/\*_spec.rb

Package "httpd"
  is expected to be installed

Service "httpd"
  is expected to be enabled
  is expected to be running

Port "80"
  is expected to be listening

File "/var/www/html/index.html"
  is expected to exist

Finished in 1.11 seconds (files took 0.34133 seconds to load)
5 examples, 0 failures

実行がうまくいかない場合

このようなエラーが出ていたら、テストする以前の問題で失敗していたり正常なテストができていなかったりします。

原因と考えられるものをあげておきますので再度ご確認ください。

getaddrinfo: Name or service not known

テスト対象の名前解決が失敗し接続できずにエラーになっています。

~/.ssh/configの設定をお忘れではないですか?

Net::SSH::AuthenticationFailed:

認証エラーでテスト前に

~/.ssh/configの設定はお間違い無いですか?

特に秘密鍵についてご確認ください。

  • 存在しているか
  • パスに間違いはないか
  • 秘密鍵の権限が600になっているか
  • .sshの権限が700になっているか

SyntaxError:

テストを定義すしているsample_spec.rbに構文エラーがあります。

先程のサンプルと見比べて間違いがないか確認してください。

最後に

最後に

テストは成功しましたか?

自動ですとができるようになると、正しく定義さえして仕舞えば「誰が」、「何度やっても」正しい結果を得ることができます。

その性質から、先にテストコードを作成してからアプリケーションを作っていく「テスト駆動開発」という開発方法もあります。

これは、最初テストに失敗している状態からサーバを構築していき正しい状態になればテストが成功すると言った考え方で進める開発方法です。

手動によるミスが発生しないからこそできる方法だと思います。

また、今までTerraform、Ansibleを使って構築も自動化してきたので近々Jenkinsも使ってみようと思います。

それでは!最後までご覧いただきありがとうございました。

AWS

Posted by kotaro