ラベル serverspec の投稿を表示しています。 すべての投稿を表示
ラベル serverspec の投稿を表示しています。 すべての投稿を表示

2015年3月27日金曜日

JenkinsとServerspecでサーバーの設定ファイルを定期監視する

このエントリーをはてなブックマークに追加 はてなブックマーク - JenkinsとServerspecでサーバーの設定ファイルを定期監視する

既に動いているサーバーの運用をしていて

  • 検証環境と本番環境で設定ファイルが意図せず違うことがある(DB接続先が違うというものではなく)
  • 運用でよく使う設定(cron,logrotate)の設定方針がサーバーで違う

など辛かったので、状況を改善するためにまずはJenkinsとServerspecを使って設定ファイルの定期監視をするようにしました。(本来はそのような状況になっていないべきですが、既にその状況になっている場合にはまず現状把握が大事かと個人的には思いました)

具体的には

  • Serverspecで指定された場所にファイルがあるか確認する(cronであればanacronなのか/etc/cron.dなのか/var/spool/なのか)
  • 設定ファイルをGitlabに登録し、実サーバーのファイルと同一であるか確認する(md5sum)

ということをJenkinsのデイリーで実行するジョブを設定するようにしてみました。

実際に行うと

  • SSHしなくても設定ファイルがどのようになっているかをGitlab(ブラウザ)から見れるように可視化
  • cronなどの設定がサーバーごとにどこにされているか分かるようにする
  • Gitlabに登録されたファイルと違う場合にはエラーとしてすぐに検出し、誰が何のために変えたかを確認し、Gitlabに登録することで履歴を追えるようにする

というメリットが得られました。

本サンプルではJenkinsを動かすサーバーとServerspecで検証するサーバーを同じにしていますが、実際はServerspecで検証したいサーバーは別ホストになると思うので適宜置き換えてください。

サンプル

toshihirock/MonitorFiles

とりあえず構成みたい、最終的にどんな感じになるか確認する場合にはどうぞ。

準備

各サーバーから設定ファイルを取得してGitlabに登録しておきます。検証、本番でファイルが違う場合にはフォルダを分けるなどして管理とします。

例えばnginxの設定ファイルが各環境で違う場合

nginx/
├── development
├── production
└── verification

という風にします。トップディレクトリをverificationなどの環境にしてその下にサービスごとにディレクトリを切ってもいいでしょうし、状況に応じて構成を変更すれば良いと思います。

差分が少ないファイル(DB接続先が違うだけなど)であれば管理するファイルは一つにしてServerspecのテスト内でファイル内の文字列を置き換える方式でも良いかもしれません。

Jenkinsのインストール

Jenkinsをインストールします。

  • インストール方法はJenkinsの公式サイト参照
  • JenkinsのGit Pluginをインストールしておくこと

また、Jenkinsユーザーになり、以下のコマンドでbundleは入れておきます。

$gem install bundle

Serverspecのテストを書く

設定ファイルが登録してあるリポジトリでServerspecのテストを書きます。書くテストコードですが、ServerspecはRubyなので以下のようにすることで設定ファイルが同一か確認出来きます。

require 'spec_helper'
require 'digest/md5'

describe file('/etc/nginx/nginx.conf') do
  its(:md5sum) { should eq Digest::MD5.file('nginx/nginx.conf').to_s }
end

パスの設定部分(nginx/nginx.conf)は適宜環境に合わせて変更してください。

Jenkinsで実行する

ジョブを作って以下のようなスクリプトを実行することでServerspecを実行できます。

bundle install
bundle exec rake

ただ、この状態だとJenkinsの出力結果で色がつかず見ずらいので、設定変更およびJenkinsプラグインを使って見やすくします。

まず、以下2つのJenkinsプラグインをインストールします。

次にJenkinsの設定でURL of theme CSSと記載されている場所にhttp://jazzzz.github.io/jenkins-black-console/black-console.cssというコンソールの背景を黒くするCSSを指定します。

また、対象のジョブの設定のColor ANSI Console Outputで任意のAnsiColorMapを指定します。

Jenkins側の設定はこれで終わりなのですが、Serverspec側でも.rspecファイルに–ttyを追加してRspec実行時にttyオプションを有効化します。

--color
--format documentation
--tty

これでジョブを実行すればいい感じに色付きで見えるようになります。

XMLでのテスト結果の出力を行う

通常出力されるメッセージでもわかりやすいのですが、せっかくJenkinsを使っているのでより見やすいようにXML出力して、グラフ形式などで見れるようにしようと思います。

RSpec(Servespec)ではXML出力は出来ないのでrspec_junit_formatterを利用します。

$echo "gem 'rspec_junit_formatter'" >> Gemfile
$bundle install

これでbundle exec rake –format RspecJunitFormatter –out reports/result.xmlとするとXML出力は可能です。ただし、CLIから実行するとホストが複数ある時に後で実行した結果をresultx.xmlで上書きするので、一つのホストの結果しか見えません。なので、Rakefileでホスト名ごとに結果のxmlを出力するようにします。また、ローカルで確認する場合にはXML出力でなく、documentフォーマットで見たいのでRakefileでは環境変数JENKINSが設定されている場合のみ、XML出力するようにします。

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

task :spec    => 'spec:all'
task :default => :spec

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

  task :all     => targets
  task :default => :all

  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"
      t.rspec_opts = "--format RspecJunitFormatter --out reports/#{target}.xml" if ENV['JENKINS']
    end
  end
end

上記変更後、Jenkinsのジョブで以下のように指定することでreports配下にホストごとの結果が出力され、以下のような形で確認できるようになります。

export JENKINS=True
bundle install
bundle exec rake

あとはJenkinsのジョブ設定のPublish JUnit test result reportのTest reports XMLsで「reports/*.xml」と指定すればOKです

終わりに

とりあえずこの対応を行っていくことで現状のサーバーの状況を確認、監視できるようになります。また、現状はChefAnsibleなどのコードのインフラ化は進んでいないのですが、これをもっと細かく作成できれば安心してコードによるインフラ構成管理に進めるような気がします。

2015年1月24日土曜日

踏み台サーバーを経由したホストでのServerspecを実行した時のメモ(+認証自動化)

このエントリーをはてなブックマークに追加 はてなブックマーク - 踏み台サーバーを経由したホストでのServerspecを実行した時のメモ(+認証自動化)

色々な制約があり、以下のように踏み台サーバーを経由してServerspecによるテストを行う必要がありました。

Serverspecを実行するホスト

↓

踏み台サーバー(公開鍵認認証。パスフレーズ入力必要あり。このサーバーでのファイル書き出し不可)

↓

テスト対象サーバー(パスワード認証。sudoを行う際にもパスワード入力が必要)

上記についてどのようにしてテストを出来るようにしたのかのメモ。また、都度「パスフレーズ」、「ログインパスワード」、「sudoパスワード」入力などが面倒なのでその辺りも自動化しました。

目次

  1. 公開鍵認証でのパスフレーズ入力を省略できるようにする
  2. 一度のSSHログインでテスト対象サーバーへSSHログインする
  3. sudo実行時のパスワードを都度入力しないようにする
  4. テスト対象サーバーログイン時のパスワード認証を自動化する

1.公開鍵認証でのパスフレーズ入力を省略できるようにする

ssh-agent でパスフレーズの入力を省く

上記に記載されているように ssh-agent を使って都度パスフレーズを入力しないようにします。

$ssh-agent bash
$ssh-add  ~/.ssh/id_rsa

addの際にパスフレーズを聞かれるので入力します。 上記までが完了すれば以降このシェルで踏み台サーバーへのSSHログイン時にはパスフレーズを聞かれることなくログインすることがでます。

$ssh hoge@FumidaiServer

ただし、あくまでもssh-agentが起動したシェルであればという制約があるため、ssh-agentを起動したシェルからexitした場合、再度ssh-agentの起動とパスフレーズの入力が必要です。

上記も自動化したいという場合、~/.bash_profileなどにログイン時にssh-agentの起動とexpectコマンドを利用してパスフレーズの入力を自動でさせることも可能です。

ssh-agent と expect で ssh のパスフレーズ入力を自動化

詳細は上記に記載されていましたが、直接パスワードを書かなければいけないのでセキュリティなど気になる人はやらない方が良いかもしれません。

2.一度のSSHログインでテスト対象サーバーへSSHログインする

ProxyCommand を使います。ProxyCommandを使うことによって踏み台サーバーへのログイン後、さらにテスト対象サーバーへSSH接続を自動で行います。

ProxyCommandによるsshの多段接続について

上記に記載されているようにServerspecを実行するホストの ~/.ssh/config を変更します。

Host FumidaiServer
  HostName FumidaiServer
  User hoge
  Port 22
  IdentityFile ~/.ssh/id_rsa

Host TestServer
  HostName TestServer
  User fuga
  Port 22
  ProxyCommand ssh -W %h:%p server

上記設定後、 

$ssh TestServer

とするとFumidaServerにSSHログイン後、自動でTestServerへSSH接続してくれます。

3.sudo実行時のパスワードを都度入力しないようにする

上記まで行えれば踏み台サーバーを気にせず、テスト対象サーバーへServerspecのテストを行うことができるかと思ったのですが、なぜか私の環境では正しいsudoのパスワードを入力してもパスワードが間違った扱いとなり、テストが実行できませんでした。

そこでsudo実行時のパスワードを省略するためには環境変数 SUDO_PASSWORD を設定しました。

$export SUDO_PASSWORD=password

詳細はserverspec-initによって自動生成される spec/spec_helper.rb を確認すれば分かるかと思います。

上記により、毎回テスト対象のサーバーへのログインパスワードの入力は必要ですが、Serverspecによるテスト自体はできるようになりました。

4.テスト対象サーバーログイン時のパスワード認証を自動化する

私の環境の場合、テスト対象のサーバーへのログイン時にパスワード認証が必要となります。 それについても自動化したいと思い、expectコマンドを使った簡単なスクリプトを作りました。

予め環境変数 LOGIN_PASSWORD を指定して、上記シェルスクリプトを実行すればテスト対象のサーバーへのパスワード認証を自動化できます。多分spec_helper.rbを上記のようなことを実行するコードに変える方がよりスマートだと思うのですが、Ruby力がまだなかったのでシェルスクリプトで対応できるようにしました。これでテスト実行時に手動入力する必要がなくなりました。

追記(2015/01/25)

Serverspec本にめっちゃ書いてあった。。。。こっちの方が自然だ。。。

まとめ

最初、この制約の中でうまくできるかなーという感じでしたが、Serverspec自体が テスト対象サーバーにSSHログインできれば良い というシンプルな構成だったので、いろんな部分を短時間で自動化させることができました。既に書いていたテストコードが無駄にならなくてよかった。。。

2014年6月10日火曜日

[Chef]expectコマンドを使ってAndroidSDKをインストールするレシピを作成してみた

このエントリーをはてなブックマークに追加 はてなブックマーク - [Chef]expectコマンドを使ってAndroidSDKをインストールするレシピを作成してみた

Chefを利用してAndroidSDK本体のインストール及び特定AndroidSDKインストールを自動化させたいと思っていました。

が、指定したAndroidSDKのインストールの途中で利用許諾の承認が必要であり、単純にexecuteコマンドを利用してインストールが出来ませんでした。

調査するとexpectコマンドを使うと対話形式の入力が必要な処理を自動化出来るとのことで実際に実施する事が出来たいのでそのメモを記載します。

そもそもexpectコマンドとは?

  • telnetやsshなどパスワード入力を求められるような処理を自動化出来る
  • 同様にインストール時に許諾への同意などが必要なものも自動化させる事が出来る

前提

  • Chef、Berkshelfなどはインストール済み
  • ホストはMac OSX 10.9.3
  • test-kitchenを利用。ドライバはvagrantを利用。

Chefやtest-kitchenの詳細は過去のブログを参考の事。

Berkshelf version3+Knife soloでnginx環境をVagrantに作ってみた話

[Chef]Berkshelfを利用したJenkinsクックブックを作成してserverspec+Kitchenでテストした話

参考

こちらのクックブックを参考にさせて頂きました。

gildegoma/chef-android-sdk

Github

置きました。

toshihirock/AndroidSDK

  • Ubuntuのテストはしてません
  • URLやAndroidSDKのバージョンは適宜変更してください。(そのうちattribute化したい。。。)

準備

クックブック作成します。

$knife cookbook create android -o .

AndroidSDKを利用する為にJavaのインストールが必要ですが、サードパーティのクックブックを利用 します。 また、AndroidSDKのダウンロード、展開の為にopscodeのarkというクックブックを利用します。

サードパーティのクックブックを使う為にBerksheflを利用する準備をします。

$berks init .

利用するためにmetadata.rbに追記を行います。

$cd android
$vi metadata.rb

name             'android'
maintainer       'YOUR_COMPANY_NAME'
maintainer_email 'YOUR_EMAIL'
license          'All rights reserved'
description      'Installs/Configures android'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version          '0.1.0'

depends "ark"
depends "java"

また、test-kitchenを使ってプロビジョニングを行うのでその為のファイルを作成します。

$kitchen init

既にBerkshlefで.kitchen.ymlが作成済みの場合にはコンフリクトしますが、yを入力して鵣川書きします。

今回、試験ははCentOSのみに今回はするため、.kitchen.ymlの一部をコメントアウトします。

$vi .kitchen.yml

編集。

platforms:
  #- name: ubuntu-12.04
  - name: centos-6.4

AndroidSDK本体のダウンロード、展開

まずはAndroidSDK本体のダウンロード、展開までのレシピを書きます。 本来はURLやパスはattributesの値とすべきですが、とりあえずベタ書きします。

$vi recipes/default.rb

編集。

include_recipe 'java'

%w{unzip expect}.each do |pkg|
  package pkg do
    action :install
  end
end

ark 'android' do
  url 'http://dl.google.com/android/adt/22.6.2/adt-bundle-linux-x86_64-20140321.zip'
  path '/usr/local/android'
end

URLはAndroidのサイトをみて確認してください。(ビット数に応じてダウンロードするzipが違いますが、今回は判定処理は割愛して64bitで確認)

試験環境の準備

VMの起動。

$kitchen create

VMにChefやBerkshelfのインストール、及びレシピの適用を行います。

$kitchen setup

状態を確認します。

$kitchne list

SSH接続して確認してみます。

$kitchen login
$ll /usr/local
lrwxrwxrwx. 1 root root   20 Jun  9 14:30 android -> /usr/local/android-1

expectコマンドを使ってみる

Chefのコードを書く前に正しく動作出来るかVMでコマンドを実行して確認してみます。

$kitchen login
$sudo su
$cd /usr/local/android/sdk/tools
$vi expectTest.sh

確認用のシェルスクリプトを編集します。

#!/bin/bash

expect -c '

spawn /usr/local/android/sdk/tools/android update sdk --no-ui --filter android-17
set timeout 1800
expect {
  -regexp "Do you accept the license.*" {
    exp_send "y\r"
    exp_continue
  }
}
'

ざっくり説明します。

  • spawn:実際に実行させたいコマンド
  • set timeout:expectの実行を許容する時間。短すぎるとコマンドの途中で強制終了してしまう。
  • regrexp:どの文字列が表示されたら入力を自動的に行うかの正規表現。今回の場合、利用規約のDo you accept …という文字列が表示された時に入力を行う事を示す。
  • exp_send:regrexpで合致する文字列が表示された時に自動入力する文字列。
  • exp_continue:これを指定しないと自動入力したあと復帰出来ないっぽいです。

実行権限を付与して、実行してみます。

$chmod a+x expectTest.sh
$./expectTest.sh

Chefのレシピでexpectコマンドを実行する

成功すればこれをChefのレシピに落とし込みます。

$exit
$vi recipes/default.rb

レシピに追記します。

script 'Install Android SDK' do
  android_version="android-17"
  interpreter 'expect'
  not_if { ::File.exists?("/usr/local/android/sdk/#{android_version}") }
  code <<-EOF
    spawn /usr/local/android/sdk/tools/android update sdk --no-ui --filter #{android_version}
    set timeout 1800
    expect {
      -regexp "Do you accept the license.*" {
        exp_send "y\r"
        exp_continue
      }
    }
  EOF
end

テストも書きます。今回はserverspecを利用します。 Gemfileに追加します。

$echo "gem \'serverspec\'" >> Gemfile

$mkdir -p test/integration/default/serverspec/localhost/
$vi test/integration/default/serverspec/localhost/default_spec.rb

テストを書きます。

require 'serverspec'
include Serverspec::Helper::Exec
include Serverspec::Helper::DetectOS

describe command('which java') do
  it { should return_exit_status 0 }
end

describe command('ls /usr/local/android/sdk/platforms/android-17') do
  it { should return_exit_status 0 }
end

色々実験したので一度、VM環境を削除します。

$kitchen destroy

その後、VMの作成、Chefの適用、serverspecのテストを実施します。

$kitchen test

問題なく完了すればOKです。