2022-12-17に更新

Serverspec

以下2つの点に留意していれば大体のことは解決する:
* 公式ドキュメントを参考にテストを書くこと
* Linux の仕様を理解していること

環境

【アプリケーションサーバー】
* Amazon Linux
* ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]

【テスト実行サーバー】
* Amazon Linux
* ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a) [x86_64-linux]

image

Serverspec を始める

$ 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: www.example.jp
 + spec/
 + spec/www.example.jp/
 + spec/www.example.jp/sample_spec.rb
 + spec/spec_helper.rb
 + Rakefile
 + .rspec

Serverspec はここで入力した target host name に対してテストを実行するので、もし実際のテスト実行対象のホスト名があなたが入力した target host name と異なるなら、~/.ssh/config を編集して実際の target host name を定義してあげる必要がある。

# ~/.ssh/config
Host the-taget-host-name-you-input
  HostName 12.34.567.890 # your actual target host
  IdentityFile ~/.ssh/your_private_key_file # if any
  User ec2-user # your login username on the target host

キーペアのプライベートキーファイルをダウンロードしたくなかったので、ボードに書いた『EC2 key pair の プライベートキーファイルをダウンロードしたくないし SSH 接続も自動でやってほしい』の方法でプライベートキーを登録した。

テストコードを書く

require 'spec_helper'

listen_port = 80
db_user = ENV['DB_USER']
db_password = ENV['DB_PASSWORD']
db_host = ENV['DB_HOST']
db_name = ENV['DB_NAME']
ec2_host = ENV['EC2_HOST']

# Test NGINX
# ・必要なパッケージがインストールされていること
# ・nginxの設定ファイルが正しい場所に存在していること
# ・nginxのプロセスが稼働していること
# ・nginxの自動起動設定がされていること
describe package('nginx') do
  it { should be_installed }
end

describe service('nginx') do
  it { should be_enabled }
  it { should be_running }
end

describe port(listen_port) do
  it { should be_listening }
end

describe file('/etc/nginx/conf.d/rails.conf') do
  it { should exist }
end

describe file('/etc/nginx/conf.d/rails.conf') do
  its(:content) { should match /server_name #{ec2_host}/ }
end

# Test MySQL
# ・DBが作られていること
describe command("mysqlshow -u #{db_user} -h #{db_host} -p#{db_password} #{db_name}" ) do
    its(:stdout) { should contain("#{db_name}").from("Database:") }
end

# Test Application
# ・必要なパッケージがインストールされていること
# ・pumaプロセスが稼働していること
# ・ALBのDNSのAレコードからアプリへアクセスしてステータスコード200で返ってくること
%w(python3 gcc-c++ make python3-pip git openssl-devel readline-devel zlib-devel).each do |pkg|
  describe package(pkg) do
    it { should be_installed }
  end
end

describe command('ruby -v') do
  let(:sudo_options) { '-u ec2-user -i' }
  its(:stdout) { should match /ruby 2\.6\.3p62/ }
end

describe package('rails') do
  let(:sudo_options) { '-u ec2-user -i' }
  it { should be_installed.by('gem').with_version('6.0.4.8') }
end

describe command('ps axu | grep puma | grep -v grep') do
  its(:exit_status) { should eq 0 }
end

describe command('curl http://ec2-*******.ap-northeast-1.elb.amazonaws.com/ -sIo /dev/null -w "%{http_code}\n"') do
  its(:stdout) { should match /^200$/ }
end

ポイント

正規表現

place = "東京都"
/#{place}/.match("Go to 東京都") # => #<MatchData "東京都">

Resource Types の process が使えない場合

  • コマンド名とプロセス名が一致していない場合は process が使えないらしい
  • 確かに puma プロセスはbundle exec rails s -e productionで起動させていたので、コマンド名とプロセス名が一致していない(恐らくps -C bundleで確認できるのかもしれない)
  • ∴ 以下のように command でテストするように変更した:
describe command('ps axu | grep puma | grep -v grep') do
  its(:exit_status) { should eq 0 }
end

sudo をコントロールする

  • 例えば、Ruby や rails はホームディレクトリ以下(/home/ec2-user/)にインストールしていた(/opt/ 以下にする人もいる)ので、sudo 権限でテストコマンドが実行されていると、「そんなコマンド存在しないんだが」とか言われてしまう
  • ゆえに、最初は「一時的に sudo を無効にすれば問題ない」と思い立ち、公式ドキュメントの記載通り以下のように記述した:
#sample_spec.rb

describe command('ruby -v') do
  let(:disable_sudo) { true }
  its(:stdout) { should match /ruby 2\.6\.3p62/ }
end

まあ普通に失敗しました。

ec2-user でログインしてテストコマンドを実行させないといけないみたいです。
公式ドキュメントに特定のオプションを sudo に渡すことができる記述方法が記載されています。

# Run command under ec2-user with simulate initial login.
describe command('ruby -v') do
  let(:sudo_options) { '-u ec2-user -i' }
  its(:stdout) { should match /ruby 2\.6\.3/ }
end

spec_helper.rb に追記する方法もありますが、ブロックスコープの記述方法の方がお手軽なのでそちらを採用しました。

ツイッターでシェア
みんなに共有、忘れないようにメモ

光の勢力

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント