🌊

複数サーバをテストするServerspecの構成

に公開

はじめに

Serverspecを使用することで、インフラ構成の単体テストを自動で実行できる。
特にテスト対象のサーバが増えていく場合には、手動確認では管理が煩雑になりやすく、構成テストの自動化を検討することになる。

本記事では、Serverspecの公式ドキュメントおよびリポジトリをもとに、複数台構成を前提としたServerspecの構成を整理した。
(公式の記載をベースにしているため、一定テンプレートとしてそのまま利用することもできると思う)


ディレクトリ構成


serverspec-template/
├── Rakefile
├── spec/
│   ├── spec_helper.rb
│   ├── web/
│   │   └── sample_spec.rb
│   └── db/
│       └── sample_spec.rb
└── hosts.yml


ファイル構成

hosts.yml(対象サーバ定義)

テスト対象のサーバ情報を記載するファイル。
SSH接続に必要な情報のほか、サーバ固有の属性やロール(役割)を付与することもできる。
これにより、テスト対象ごとに設定を切り替えたり、ロールに応じたspecを実行したりできる。

web:
  host: 192.168.1.10
  user: ec2-user
  key: ~/.ssh/id_rsa
  roles:
    - base
    - web
  server_id: 101

db:
  host: 192.168.1.20
  user: ec2-user
  key: ~/.ssh/id_rsa
  roles:
    - base
    - db
  server_id: 102

rolesserver_idは任意項目であり、運用方針に合わせて拡張できる。


spec/spec_helper.rb

spec_helper.rbはServerspecの共通設定ファイルであり、テスト全体の実行方法や接続方式を定義する。
以下の例では、各ホストに対して順にSSH接続し検証を行う。

require 'serverspec'
require 'net/ssh'
require 'yaml'

# 環境変数 TARGET_HOST に指定されたホストを取得
target = ENV['TARGET_HOST'] || raise("ERROR: TARGET_HOST is not set")

hosts = YAML.load_file(File.expand_path('../../hosts.yml', __FILE__))
config = hosts[target] || raise("ERROR: no configuration for TARGET_HOST=#{target}")

# SSH経由で実行
set :backend, :ssh
set :host, config['host']

options = Net::SSH::Config.for(config['host'])
options[:user] = config['user']
options[:keys] = [File.expand_path(config['key'])]
set :ssh_options, options

# 共通設定
set :env, LANG: 'C'
set :path, '/sbin:/usr/sbin:$PATH'

# 任意:テスト内でホストプロパティ参照可
set_property config

set :backend, :ssh はリモートサーバをSSH経由で検証する設定。
ローカル検証(Serverspecの実行サーバ自身)を行う場合は :exec に変更する。


テストコード(例:spec/web/sample_spec.rb)

各サーバの設定検証を記述する。
以下はWebサーバ(nginx)を例にしたテストコードである。

require_relative '../spec_helper'

describe 'Web server configuration' do
  describe package('nginx') do
    it { should be_installed }
  end

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

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

package, service, portなどはServerspecで標準提供されている。
公式リファレンス:https://serverspec.org/resource_types.html


Rakefile

RakefileはRubyのビルドツールであるRakeの設定ファイルであり、テスト実行タスクを定義する。
Rakeを利用することで、複数ホストのテストを簡潔に実行・管理できる。

以下の例では、複数ホストを個別または一括でテストできるようにしている。

require 'rake'
require 'rspec/core/rake_task'
require 'yaml'

hosts = YAML.load_file('hosts.yml').keys

# すべてのホストを対象としたタスク
task :spec => 'spec:all'

namespace :spec do
  task :all => hosts.map { |h| 'spec:' + h }

  hosts.each do |host|
    desc "Run serverspec to #{host}"
    RSpec::Core::RakeTask.new(host) do |t|
      ENV['TARGET_HOST'] = host
      t.pattern = "spec/{#{host}}/*_spec.rb"
    end
  end
end

処理概要

  • rake spec:すべてのホストを一括テスト
  • rake spec:web:特定ホストのみ実行
  • pattern で対象specを動的に制御(例:ロール別)

実行環境の準備

ServerspecはRubyで動作するため、まずRuby実行環境が必要となる。
Linuxでは標準でインストールされていることが多いが、
ruby -v コマンドでバージョンを確認が可能。

ruby -v
# 例: ruby 3.1.4

テストを実行するためには、以下のGem(Rubyパッケージ)が必要になる。

Gem名 用途
serverspec 構成テストの本体。RSpecを拡張してサーバの状態を検証する。
rake タスク実行ツール。Serverspecのテストをまとめて実行するために使用する。

これらをインストールする。

gem install serverspec rake

実行方法

環境が整ったら、Serverspecを実行してサーバ構成を検証する。

すべてのホストを対象にテストを実行

rake spec

特定のホストのみ実行

rake spec:web

参考ドキュメント


Discussion