Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

大規模サーバ更改でServerspecを使ってみました

こんにちは、おじさん技術者の iga です。

とあるサーバ更改のプロジェクトで、「Serverspecを使った設定チェック」を実施しましたので、その時のノウハウを共有したいと思います。

設定チェックの対象となるサーバが全部で約600台あり、あるサーバ種別で最大282台と大規模なため、人力でのチェックはあきらめていました。
そこで利用したのが、Serverspecです。

f:id:acro-engineer:20161119145144j:plain

Serverspecとは

Serverspecは、サーバの状態をコードにより自動的にテストするためのツールです。
公式サイトはこちらです。
http://serverspec.org/

Ruby製のテストフレームワークRSpecがベースになっていて、抽象化したコードによってサーバの状態を確認するようになっています。

システム構成の概要

今回のテスト対象のシステム構成は、次の図のようになっています。

f:id:acro-engineer:20161120193702j:plain

メンテナンス端末にServerspecをインストールして、メンテナンス端末からテスト対象のサーバにsshで接続できるようになっています。

今回のカスタマイズ方針

サーバの台数は多いのですが、同じ役割のサーバが数十台で構成されるとなっているため、Serverspec標準のテスト方法だと、同じチェック内容を大量に複製する必要があります。
標準のフォルダ構成だと、以下の図のようになります。

f:id:acro-engineer:20161119150226j:plain

「websvr001」と「websvr002」に同じテストを適用していますが、台数が少ない間はファイルのコピーやシンボリックリンクで対応できますが、台数が増えると管理しきれなくなります。

そこで、複数サーバでテストを共有するため、公式サイトにも記述されている「How to share Serverspec tests among hosts」という手法を取りました。

f:id:acro-engineer:20161119150227j:plain

サーバ種別ごとにテスト対象を配置することで、同じサーバ種別で台数が増えても、管理できるようになりました。


ただ、サンプルで記述されている内容だと、以下のような問題があってそのまま適用できませんでした。
1) 対象サーバが固定で記述されている。
→台数が多いので、テスト時間短縮のためあるサーバ種別だけテストしたい、ということができない。
2) サーバ種別(Role)をサーバ名から取得するようになっている。
→サーバ名が命名規則に沿ってつけられているが、サーバ種別が分かりやすい名前になっていない。
→記述ミスがあると実行の無駄になってしまうので、分かりやすい記述にしたかった。

今回対応するカスタマイズ内容

今回の対応(以降、Role対応 と記載します)では、以下のことを行いました。
1) 対象サーバとサーバ種別は、JSON形式の外部ファイルに用意しておく。
2) サーバ種別は、分かりやすい名前にしておく。

具体的なカスタマイズ内容

Role対応するため、Rakefileを次のように修正しました。
Rakefileは、Serverspecが自動生成した、テストを実行する処理が記述されたファイルになります。

まずは実行対象のサーバ情報を取り出すところです。

標準のRakefile
  targets = []
  Dir.glob('./spec/*').each do |dir|
    next unless File.directory?(dir)
    target = File.basename(dir)
    target = "_#{target}" if target == "default"
    targets << target
  end

標準ではspecフォルダ配下のフォルダが実行対象サーバ名(またはIPアドレス)になっているので、それを読み込んで実行対象(target)に保存しています。

Role対応版Rakefile
  # 環境変数から使用するIPアドレスリストを取得
  rolePath = ENV['SERVERSPEC_ROLE']

  # specフォルダ配下のrole名を取得する
  roles = []
  Dir.glob('./spec/*').each do |dir|
    next unless File.directory?(dir)
    target = File.basename(dir)
    roles << target
  end

  # role別のIPアドレスリストをjsonファイルから読み込む
  all_addrs = []
  targets = []
  roles.each do |role|
    ip_addrs = get_ipaddr(rolePath, role)
    if ip_addrs
      all_addrs.concat(ip_addrs)

      ip_addrs.each do |ip_addr|
        targets << {:role => role, :addr => ip_addr}
      end
    end
  end


Role対応では、specフォルダ配下のフォルダがサーバ種別になっているので、それを読み込みます。
そして、JSONファイルからサーバ種別と実行対象サーバ名を読み込んで、specフォルダ配下にサーバ種別が定義されている場合に、サーバ種別と実行対象サーバ名をtargetに保存しています。
読み込むJSONファイル名は、環境変数「SERVERSPEC_ROLE」から取得しています。


JSONファイルのフォーマットは、次のようにしています。
サーバ種別をキーとして、実行対象サーバ名を配列として定義しています。

  {
    "websvr" : [
      "websvr001",
      "websvr002"
    ],
    "appsvr" : [
      "appsvr001"
    ],
    "dbsvr" : [
      "dbsvr001"
    ]
  }

テストの実行部分は次のようになります。

標準のRakefile
  targets.each do |target|
    original_target = target == "_default" ? target[1..-1] : target
    desc "Run serverspec tests to #{original_target}"
    RSpec::Core::RakeTask.new(target.to_sym) do |t|
      ENV['TARGET_HOST'] = original_target
      t.pattern = "spec/#{original_target}/*_spec.rb"
    end
  end

標準では、targetに入っているサーバ分、テストを実行しています。

Role対応版Rakefile
  targets.each do |target|
    original_role = target[:role]
    original_target = target[:addr]
    begin
      desc "Run serverspec tests to #{original_target}"
      RSpec::Core::RakeTask.new(original_target.to_sym) do |t|
        ENV['EXEC_TIME'] = Time.now.strftime("%Y%m%d_%H%M%S").to_s
        ENV['SERVER_KIND'] = original_role
        ENV['TARGET_HOST'] = original_target
        t.pattern = "spec/#{original_role}/*_spec.rb"
        t.fail_on_error = false
      end
    rescue => ex
      puts ex.message
    end
  end

Role対応では、標準と同じくtargetに入っているサーバ分、テストを実行しています。その際、specフォルダ配下のサーバ種別をtargetに格納したroleから決定するようにしています。

Role対応の結果、サーバ種別「websvr」に対してテストする場合、次のように実行します。

  $ export SERVERSPEC_ROLE=addr/websvr.json
  $ rake spec

まとめ

今回、初めてServerspecを利用しましたが、その威力に感動しました。
これまでは、サーバの設定確認といえば目視やdiffを使った差分確認など、人の注意力に頼った作業をやっていました。
それでは設定ミスを見落としたことが、後になって見つかって大変になる、ということをやってきました。

Serverspecを利用すると、設定のOK/NGが分かりやすく出てくるため、NG理由を確認するのも設定ミスなのかテスト内容のミスなのか、切り分けが容易になりました。


それでは!


Acroquest Technologyでは、キャリア採用を行っています。


  • ビッグデータHadoop/Spark、NoSQL)、データ分析(Elasticsearch、Python関連)、Web開発(SpringCloud/SpringBoot、AngularJS)といった最新のOSSを利用する開発プロジェクトに関わりたい。
  • マイクロサービスDevOpsなどの技術を使ったり、データ分析機械学習などのスキルを活かしたい。
  • 社会貢献性の高いプロジェクトや、顧客の価値を創造するようなプロジェクトで、提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や、対外的な勉強会の開催・参加を通した技術の発信、社内勉強会での技術情報共有により、エンジニアとして成長したい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 
急増するDevOps案件の中でスキルを活かしたいエンジニア募集! - Acroquest Technology株式会社のインフラエンジニア中途・インターンシップ・契約・委託の求人 - Wantedlywww.wantedly.com