24
serverspecサーバ環境のテストを書いてみよう TIS 池田 大輔( @ike_dai )

serverspecでサーバ環境のテストを書いてみよう

Embed Size (px)

DESCRIPTION

社内勉強会で発表した資料です。 serverspecの基本から属性値の管理、カスタマイズ方法まで紹介しています。 ※2013/8/14 version 0.7.8時点の情報なので注意

Citation preview

Page 1: serverspecでサーバ環境のテストを書いてみよう

serverspecで

サーバ環境のテストを書いてみよう

TIS 池田 大輔( @ike_dai )

Page 2: serverspecでサーバ環境のテストを書いてみよう

Agenda● 1. 基本の紹介

○ serverspecとは何か?

○ 導入方法の紹介

○ 設定方法の紹介

○ テストコードの書き方

● 2. 簡単なデモ

○ テスト実行

○ 結果の表示

● 3. 属性情報の扱い方

○ 属性情報を外出しして実行

● 4. カスタマイズしてみる

○ NTP時刻同期状況テストを作ってみる

Page 3: serverspecでサーバ環境のテストを書いてみよう

serverspecの基本

● serverspecとは?

○ サーバの状態をテストするためのフレームワーク

○ Ruby実装 (8/14時点最新version 0.7.8 ※日々バージョンアップするので注意)

○ Rspecに準拠した形式で記述が可能→Rspecに慣れた方ならすぐに書けるかも

○ ChefやPuppet等環境の自動構成管理ツールと組み合わせて使うのに最適

○ serverspecは構成管理ツールに依存せずにテストコードが書ける

○ テスト実行方法は2種類

■ ローカルに対してテスト実行

■ SSH接続してテスト実行

○ テストコードを1箇所で集約管理

○ ただ単にSSH接続して実行するので特別なAgentの導入の必要がない

Page 4: serverspecでサーバ環境のテストを書いてみよう

serverspecの基本

● どんな用途で使う?

○ 自動構築した結果、正しく稼働しているか確認

○ 内部から見てどう動いているのかを確認するため、外から見てどうかは

Zabbix等の監視ツールを利用

■ ポートがリッスンしているか?iptablesでそのポートを開放する設定が

されているか?はserverspecで確認

■ 本当にそのポートにアクセスできるか?アクセスが拒否されるか?は

監視ツールで確認

Page 5: serverspecでサーバ環境のテストを書いてみよう

serverspecの導入方法

● gemコマンドで簡単にインストール可

● インストール後、テストコード初期設定実施

$ gem install serverspec

$ serverspec-initSelect a backend type:1) SSH2) Exec (local)Select number: 1

Vagrant instance y/n: nInput target host name: 192.168.xxx.xxx + spec/ + spec/192.168.xxx.xxx/ + spec/192.168.xxx.xxx/httpd_spec.rb + spec/spec_helper.rb + Rakefile

Page 6: serverspecでサーバ環境のテストを書いてみよう

● 事前設定○ 1.SSH接続設定

○ 2.sudo設定

SSH接続設定●● 1. 公開鍵のキーペア作成 (NoPasswordで)● 2. テスト対象機器側の鍵認証設定● 3. serverspec実行機器側での .ssh/config設定

serverspecの設定方法

$ vim .ssh/configHost 192.168.xxx.xxx

HostName 192.168.xxx.xxxPort 22IdentityFile ~/.ssh/serverspec_testUser maintain

serverspec-init実行時に指定したホスト名と一致するように設定

Page 7: serverspecでサーバ環境のテストを書いてみよう

sudo設定● SSHログイン後に実行されるテスト処理はsudoをつけて実行される● 接続ユーザに対してsudo権限を付与(実行されるサーバ側で設定)

● serverspec実行サーバ上の環境変数指定

● spec/spec_helper.rbを書き換えればパスワード認証のSSHログインも可能

serverspecの設定方法

# visudomaintain ALL=(ALL) NOPASSWD:ALL

$ export SUDO_PASSWORD=”xxxxxxxx”or$ export ASK_SUDO_PASSWORD=1

sudo実行時のパスワードを環境変数にセット

sudo実行時のパスワードを対話式入力有効化

Page 8: serverspecでサーバ環境のテストを書いてみよう

● 重要なのはリソースタイプとマッチャー

● この組み合わせで様々なテストが記述できる

● リソースタイプ

○ command,cron,default_gateway,file,group,host,interface,ipfilter,ipnat,iptables,kernel_module,linux_kernel_parameter,package,php_config,port,routing_table,selinux,service,user,yumrepo,zfs

● マッチャー

○ 例:commandリソースタイプの場合

■ return_stdout:あるコマンド実行時の標準出力の文字列確認テスト

■ return_stderr:あるコマンド実行時の標準エラー出力の文字列確認テスト

テストコードの書き方

詳しくはこちら: http://serverspec.org/

Page 9: serverspecでサーバ環境のテストを書いてみよう

● 例: 指定したパッケージがインストールされているかどうかのテスト

テストコードの基本

$ vim spec/httpd_spec.rb

require 'spec_helper'describe package('httpd') do it { should be_installed }end

リソースタイプを指定

マッチャーを指定してテスト実行

Page 10: serverspecでサーバ環境のテストを書いてみよう

● ソースコードが非常に見やすい

1. どのリソースタイプか?

- インストールディレクトリ/serverspec-バージョン/lib/serverspec/type以下を確認

- 先述の例のテストの場合、package.rbを確認

2. どのマッチャーか?

- be_installedの場合、def installed?を確認

- この中に処理が記述

- def installed?の内部ではcheck_installedメソッドが呼ばれている

3. 実際の処理メソッドを確認

- check_installedメソッドを確認(commands/redhat.rb,debian.rb...)- OS毎にテスト実行コマンドが違う場合はOS毎に用意されているファイルに

- OS共通のテスト実行コマンドの場合はcommands/base.rbに

ソースコードの追い方

Page 11: serverspecでサーバ環境のテストを書いてみよう

● テスト実行時に実際にはどんなコマンドが実行されているの?○ RedHat系の場合(lib/serverspec/commands/redhat.rb)

○ Debian系の場合(lib/serverspec/commands/debian.rb)

テスト実行時のコマンド

def check_installed(package,version=nil) cmd = "rpm -q #{escape(package)}" if ! version.nil? cmd = "#{cmd} | grep -w -- #{escape(version)}" end cmd end

def check_installed(package,version=nil) escaped_package = escape(package) "dpkg -s #{escaped_package} && ! dpkg -s #{escaped_package} | grep -E '^Status: .+ not-installed$'"end

Page 12: serverspecでサーバ環境のテストを書いてみよう

● テスト実行時に実際にはどんなコマンドが実行されているの?○ RedHat系の場合(lib/serverspec/commands/redhat.rb)

○ Debian系の場合(lib/serverspec/commands/debian.rb)

テスト実行時のコマンド

def check_installed(package,version=nil) cmd = "rpm -q #{escape(package)}" if ! version.nil? cmd = "#{cmd} | grep -w -- #{escape(version)}" end cmd end

def check_installed(package,version=nil) escaped_package = escape(package) "dpkg -s #{escaped_package} && ! dpkg -s #{escaped_package} | grep -E '^Status: .+ not-installed$'"end

Page 13: serverspecでサーバ環境のテストを書いてみよう

● 実行されるコマンドが何であるかを理解した上で書きましょう○ httpdパッケージのインストールバージョンをテストする場合の例

■ 極端な例ですが、以下2つはどちらもテストOKになる

テストコード作成時の注意点

実際にインストールされているパッケージ

$ rpm -q httpdhttpd-2.2.15-15.el6.centos.x86_64バージョン指定した場合に実行されるコマンド$ rpm -q httpd | grep -w -- 指定した文字列

describe package('httpd') do it { should be_installed.with_version('2.2') }end

describe package('httpd') do it { should be_installed.with_version('2.15') }end

Page 14: serverspecでサーバ環境のテストを書いてみよう

● 実行方法

● ~/.rspecファイルを編集して表示を見やすく

● テスト失敗時、どういったコマンドが実行されのかが表示される

デモ

$ rake spec

--color--format documentation(またはs)

色付けをして表示

実行結果を文字列表記

Failures: 1) Port "80" Failure/Error: it { should be_listening } sudo netstat -tunl | grep -- :80\ expected Port "80" to be listening # ./spec/192.168.xxx.xxx/httpd_spec.rb:13:in `block (2 levels) in <top (required)>'

実際に実行されたコマンド

Page 15: serverspecでサーバ環境のテストを書いてみよう

● テスト対象サーバ毎に変更する属性値を外だし管理可能1. 属性値情報をまとめたYAMLファイル作成

2. RakefileをYAMLファイルのキーの項目毎にテスト実行できるよう編集

3. spec/spec_helper.rbを編集し、属性値を変数に格納

4. テストコード内部で3.で格納した変数を利用するよう変更

設定情報を外だし

詳しくはこちら: http://mizzy.org/blog/2013/05/12/2/

Page 16: serverspecでサーバ環境のテストを書いてみよう

● サーバ毎に異なるApacheのバージョンのテストを実施する場合の例

1. 属性値情報をまとめたYAMLファイル作成(attributes.yml)

設定情報を外だし

192.168.xxx.xxx: :apache_version: 2.2.15192.168.yyy.yyy: :apache_version: 2.4.4

キー

属性値

Page 17: serverspecでサーバ環境のテストを書いてみよう

● サーバ毎に異なるApacheのバージョンのテストを実施する場合の例

2. RakefileをYAMLファイルのキーの項目毎にテスト実行できるよう編集

設定情報を外だし

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

attributes = YAML.load_file('attributes.yml')

desc "Run serverspec to all services"task :spec => 'spec:all'

namespace :spec do task :all => attributes.keys.map {|key| 'spec:' + key } attributes.keys.each do |key| desc "Run serverspec to #{key}" RSpec::Core::RakeTask.new(key.to_sym) do |t| ENV['TARGET_HOST'] = key t.pattern = "spec/#{key}/*_spec.rb" end end end

attrubutes.yml読込み

キー毎にspecを実行するよう変更

spec_helperで利用するため環境変数にキー情報を登録

Page 18: serverspecでサーバ環境のテストを書いてみよう

● サーバ毎に異なるApacheのバージョンのテストを実施する場合の例

3. spec/spec_helper.rbを編集し、属性値を変数に格納

設定情報を外だし

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

include Serverspec::Helper::Sshinclude Serverspec::Helper::DetectOSinclude Serverspec::Helper::Attributes

attributes = YAML.load_file('attributes.yml')

RSpec.configure do |c| ・・・略 attr_set attributes[ENV['TARGET_HOST']]end

attr_setで指定したキーの属性値を変数に格納

Page 19: serverspecでサーバ環境のテストを書いてみよう

● サーバ毎に異なるApacheのバージョンのテストを実施する場合の例

4. テストコード内部で3.で格納した変数を利用するよう変更

設定情報を外だし

describe package('httpd') do it { should be_installed.with_version(attr[:apache_version]) }end

attr[:属性名]という変数に値が格納

Page 20: serverspecでサーバ環境のテストを書いてみよう

● 簡単にカスタマイズすることも可能○ commandリソースを使えば任意のコマンド実行テストが可能だが

○ よく使うものは新たにリソースタイプ、マッチャーを作成すれば使い回しできる

● 参考例:ntpの時刻同期状況テストを新たに追加してみる

○ 目指す形■ テスト対象サーバ内の指定したntpサーバのステータスをテスト

カスタマイズしてみる

describe ntp('xxx.xxx.xxx.xxx') do its(:status) { should eq '*' }end

Page 21: serverspecでサーバ環境のテストを書いてみよう

● リソースタイプを追加○ lib/serverspec/helper/type.rbにリソースタイプを追加

○ 今回はntpというリソースタイプを新たに追加

カスタマイズしてみる

4: types = %w( 5: base yumrepo service package port file cron command linux_kernel_parameter iptables host6: routing_table default_gateway selinux user group zfs ipnat ipfilter kernel_module interface php_config ntp7: )

ここにタイプを追加することでserverspec/type/ntp.rbが読み込まれてリソースタイプが有効になる。

Page 22: serverspecでサーバ環境のテストを書いてみよう

● ntpリソースタイプの定義○ lib/serverspec/type/ntp.rbに定義内容を記述

カスタマイズしてみる

module Serverspec module Type class Ntp< Base def status ret = backend.run_command(commands.get_ntp_status_of(@name)) val = ret[:stdout].strip val end end end end

status情報を取得するためのメソッドを定義

Page 23: serverspecでサーバ環境のテストを書いてみよう

● 実行コマンド処理を記述

○ lib/serverspec/commands/linux.rbに実際の処理内容を記述

○ 各OSに依存する処理を書きたい場合はredhat.rbとかdebian.rbとかOS毎の

ファイルに処理を記載

カスタマイズしてみる

def get_ntp_status_of(name) "ntpq -p -n | grep #{name} | head -c1"end

実際に実行されるコマンド

$ sudo ntpq -p -n remote refid st t when poll reach delay offset jitter==================================================================*172.xx.xx.xx 172.xx.xxx.xx 6 u 248 1024 377 0.799 25.298 20.663

ここのステータス情報を取得

Page 24: serverspecでサーバ環境のテストを書いてみよう

● serverspecはサーバ内部の状況が正しいかどうかをテストす

るフレームワーク● ChefやPuppet等自動構築ツールに依存せず手軽に扱える

● SSHログインしてテスト実行することが可能なので複数サーバ

のテストを統合管理可能● カスタマイズも容易にできるのでいろんな場面に適用も可

まとめ