最近は担当システムが平和だけど俺が平和じゃない。疲れてる。忘年会の連チャンもきっついトシになっちまった。会社の制度で1週間くらい休みがとれるので、一人で温泉とスノボと開発合宿でもしに北海道にでも行こうかなって思ってる。1月か2月くらいに。
えーと、担当しているサービスにserverspecを導入した。それにあたってテスト項目を考えたので軽くまとめる。もちろんserverspec導入前もサーバ構築後は動作確認というか、テストらしいことはしていたっちゃしていたんだけど、テスト項目をまともに考えたのはこれが初めてかもしれない。serverspecのバージョンは0.13.2である。Rubyは2.0.0。



0. 環境

下記のような環境に導入した。ありふれた構成だと思う。60台くらいの規模。DBはマスタ3台に分割されていて、それぞれにスレーブがn台ぶらさがっている。LBの箱は二つあるが、物理的には1台。OSはCentOS5.4と6.2が混在。ネットワークは2つのVLANをまたがっている。このあたりは環境差分を意識してテストする工夫が必要だったので、「3. 自分の環境に合わせるための工夫」のところに記述する。

01_serverspec_1

1. serverspecの構成

まずserverspecの構成。serverspec公式のチュートリアルにあったようにロールで分けるようにしていて、共通設定はbase、サーバ種別に依存するものは、webapp, memcached, db, dbbkとロールを作ってある。モニタリングサーバやjenkinsサーバ、MHAマネージャ用のロールはまだ作ってない。

02_serverspec_2

2. テスト項目

で、テスト項目。それぞれのロールのxxx_spec.rbの内容は下記のとおり。これがインフラ仕様でありテスト項目である。


  • Base(全サーバ共通のテスト項目)
    • base/base_spec.rb
      • ホスト名が正しいこと
      • Ethernetが1000Mb/sに設定されていること
      • VLAN IDが正しく振られていること
      • ルーティングテーブルが正しいこと
      • bondingが正しいモードで組まれていること
      • yumリポジトリが正しく設定されていること
      • LDAPの設定が正しいこと
      • LDAP異常時に接続するための特権ユーザが存在していて、正しい鍵を持っていること
      • タイムゾーンが正しいこと
      • カーネルパラメータが正しいこと
      • ulimitが正しく設定されていること
      • sudoersが正しいこと
      • resolv.confが正しく、名前解決できること
      • selinuxがオフになっていること
      • i18nが正しいこと
      • net-snmp, sysstat, ntp, mosh…など、全サーバ共通で持つべきパッケージがインストールされていること
      • sshd, snmpd, ntpdなど起動すべきサービスが起動していて、有効になっていること
      • それらの設定が正しいこと、ntpはちゃんと時間同期できていること
      • それらが意図したポートでリスンしていること
      • cpuspeed, portmap, sendmail…など不要なサービスが停止していること
      • RAIDの状態をチェックするためのユーティリティがインストールされていること
  • WebApp
    • Apache
      • webapp/httpd_spec.rb
        • 意図したバージョンのApacheがインストールされていること
        • httpdが起動していること
        • 80番ポートでリスンしていること
        • httpdサービスの自動起動がOFFになっていること
        • httpd用のユーザが存在していて、正しいuid, gidをもっていること
        • コンフィグファイルの内容が正しいこと
        • httpdが使うディレクトリが意図したオーナ/パーミッションで掘られていること
    • Tomcat
      • webapp/app_spec.rb
        • 意図したバージョンのJava, Tomcatがインストールされていること
        • tomcatが起動していること
        • 8009, 8080, 5400ポートがリスンしていること
        • tomcatサービスの自動起動がOFFになっていること
        • tomcat用のユーザが存在していて、正しいuid, gidをもっていること
        • コンフィグファイルの内容が正しいこと
        • tomcatが使うディレクトリが意図したオーナ/パーミッションで掘られていること
    • Cache, DB, 内部API, 外部APIと通信を行う
      • webapp/communicate_spec.rb
        • 通信先のcache, DB, 各種APIに疎通できること
    • 通信のあて先はhostsで設定された名前で行う
      • webapp/hosts_spec.rb
        • hostsの内容が正しいこと
    • ログローテーションはcronで行う
      • webapp/cron_spec.rb
        • crondが起動していること
        • crondサービスの自動起動がONになっていること
        • cronの設定が正しいこと
        • cronに仕込んであるログローテスクリプトが意図したオーナ/パーミッションで存在していること
    • flumeでログの収集を行う
      • webapp/flume_spec.rb
        • 意図したバージョンのflumeがインストールされていること
        • flumeが起動していること
        • flumeサービスの自動起動がONになっていること
        • flume用のユーザが存在していて、正しいuid, gidをもっていること
        • コンフィグファイルの内容が正しいこと
        • flumeが使うディレクトリが意図したオーナ/パーミッションで掘られていること
    • muninでモニタリングされている
      • webapp/munin-node_spec.rb
        • munin-nodeがインストールされていること
        • munin-nodeが起動していること
        • 4949ポートがリスンしていること
        • munin-nodeサービスの自動起動がONになっていること
        • WebAppサーバに仕込むべきmunin用のスクリプトが意図したオーナ/パーミッションで存在していること
        • コンフィグファイルの内容が正しいこと
    • ファイルシステム
      • webapp/filesystem_spec.rb
        • マウントポイントとファイルシステムが正しいこと(後述するが、DBのファイルシステムは他のサーバと違うため、ここにもfilesystem_spec.rbを置く)
  • Cache
    • memcached
      • memcached/memcached_spec.rb
        • 意図したバージョンのmemcachedがインストールされていること
        • memcahcedが起動していること
        • 11211番ポートでリスンしていること
        • memcachedサービスの自動起動がOFFになっていること
        • memcached用のユーザが存在していて、正しいuid, gidをもっていること
        • コンフィグファイルの内容が正しいこと
    • muninでモニタリングされている
      • memcached/munin-node_spec.rb
        • munin-nodeがインストールされていること
        • munin-nodeが起動していること
        • 4949ポートがリスンしていること
        • munin-nodeサービスの自動起動がONになっていること
        • memcachedサーバに仕込むべきmunin用のスクリプトが意図したオーナ/パーミッションで存在していること
        • コンフィグファイルの内容が正しいこと
    • ファイルシステム
      • memcached/filesystem_spec.rb
        • マウントポイントとファイルシステムが正しいこと(後述するが、DBのファイルシステムは他のサーバと違うため、ここにもfilesystem_spec.rbを置く)
  • DB
    • MySQL
      • db/mysql_spec.rb
        • 意図したバージョンのMySQLパッケージ群がインストールされていること
        • MHAがインストールされていること
        • MySQLが起動していること
        • 3306番ポートでリスンしていること
        • mysqlサービスの自動起動がOFFになっていること
        • MySQL用のユーザが存在していて、正しいuid, gidをもっていること。また必要な鍵を持っていること。
        • コンフィグファイルの内容が正しいこと
        • MySQLが使うディレクトリが意図したオーナ/パーミッションで掘られていること
        • MHAが使うディレクトリが意図したオーナ/パーミッションで掘られていること
        • 正しいMySQL接続ユーザが存在していること
        • percona-toolkitがインストールされていること
    • スレーブはDSRによって参照の負荷分散を行う。
      • db/db-network_spec.rb
        • lo:0がDSRで使う正しいループバックアドレスを持っていること
        • MHAで使うVIPが設定されていて、ONPARENT=noになっていること
        • マスタDBは、MHAで使うVIPがリスンしていること
    • sysctl.confが正しいこと
      • db/sysctl_spec.rb
        • Baseロールのカーネルパラメータに加えて、DSR用のカーネルパラメータ(ARPに応答しない)やDB固有のパラメータが設定されていること
    • muninでモニタリングされている
      • db/munin-node_spec.rb
        • munin-nodeがインストールされていること
        • munin-nodeが起動していること
        • 4949ポートがリスンしていること
        • munin-nodeサービスの自動起動がONになっていること
        • MySQLサーバに仕込むべきmunin用のスクリプトが意図したオーナ/パーミッションで存在していること
        • コンフィグファイルの内容が正しいこと
    • zabbixでモニタリングされている
      • db/zabbix-agent_spec.rb
        • second behind masterの数値をモニタリングするようになっていること
    • ファイルシステム
      • MySQLのデータディレクトリはxfsでnobarrier, noatimeがオプションとして付与されていること
  • Backup DB
    • MySQL
      • dbbk/mysql_spec.rb
        • 意図したバージョンのMySQLパッケージ群がインストールされていること
        • MySQLが起動していること
        • 3306番ポートでリスンしていること
        • mysqlサービスの自動起動がOFFになっていること
        • mysql用のユーザが存在していて、正しいuid, gidをもっていること。また必要な鍵を持っていること。
        • コンフィグファイルの内容が正しいこと
        • mysqlが使うディレクトリが意図したオーナ/パーミッションで掘られていること
        • 正しいMySQL接続ユーザが存在していること
        • percona-toolkitがインストールされていること
    • XtrabackupでBackup serverにバックアップをとっている
      • dbbk/xtrabackup_spec.rb
        • xtrabackupが意図したバージョンでインストールされていること
    • バックアップはcronで実行
      • dbbk/cron_spec.rb
        • crondが起動していること
        • crondサービスの自動起動がONになっていること
        • cronの設定が正しいこと
        • cronに仕込んであるバックアップスクリプトが意図したオーナ/パーミッションで存在していること
    • ファイルシステム
      • MySQLのデータディレクトリはxfsでnobarrier, noatimeがオプションとして付与されていること

3. 自分の環境に合わせるための工夫

そのまま使うと使い勝手に支障が出たので、Rakefilespec_helper.rbにいくらか細工をしている。


  • bundle exec rake serverspec:web01などとして実行するが、ホスト名(例:web01)ではなくIPでアクセスさせるようにした
    • これはDC内のインターナル通信において名前でアクセスする仕組みがないから(強いて言うならhostsファイルw)。properties.yamlを編集する際にhostsファイルの編集もセットになるのは嫌だった。なので、properties.yamlの:ipは必須項目となっている。
  • sshログインユーザ/パスワード(sudoパスワード)は必ず入力させるようにした
    • 「Jenkinsの公開鍵バラまいてそこからパスなしsudoでいいじゃん?」って声が聞こえてきそうだが、自動化の仕組みが万全じゃないってのもあって、構築→テストや、設定変更→テストのフローを思案中…。いったんは個人のLDAPアカウントを使う形にしてある。個人PCからでもテストできるしね。
    • 監視サーバから定期的に実行させるってのも案かな、って思ってたりもする。
  • 「パスワード: 」みたいな日本語プロンプトにも対応できるようにした
    • たまに実行がフリーズする鯖がいる…と思ったらコレが原因だった…ので対応。
  • OS別でテストフローを変化できるようにした
    • CentOS5.4とCentOS6.2でファイル名が違うものや設定内容が違うものをどうやってハンドリングするかを考えた。CentOS5.4のロールとCentOS6.2のロールを分けてみたりとかいろいろ手段を考えたんだが、テスト中で条件分岐させるのが一番しっくりきた。例えば、CentOS5.4のldap.confはCentOS6.2だとpam_ldap.confになっていたりするので…。下記のように。もっと良い案あったら誰か教えてください。

1
2
3
4
5
6
7
8
9
10
11
12
13
case check_centos_version
when '5.4'
describe file('/etc/ldap.conf') do
do_some_tests
end
when '6.2'
describe file('/etc/pam_ldap.conf') do
do_some_tests
end
else
puts "Error: Couldn't execute tests. Unknown OS."
exit 1
end

  • MySQLはマスタ/スレーブでテストのフローを変化できるようにした
    • このシステムではMySQLのカスケード接続はないので、レプリケーション接続が0であればスレーブ、1以上であればマスタと見なす。例えば下記のように、マスタでのみ、MHAのVIPがリスンしていることをテストする。

1
2
3
4
5
6
if is_master_db
describe interface('bond0.xxx:0') do
it { should have_ipv4_address("#{property[:mha_vip]}") }
it { should have_ipv4_address("#{property[:mha_vip]}/22") }
end
end

  • VLAN別で挙動を変化できるようにした
    • VLANによってデフォゲが異なるので…。これも判別してテストを行う必要があったので。

4. やってみた結果

おもしろいミスがたくさん見つかった
  • 1台だけxfsのマウントオプション違う。nobarrier付いてない。
  • MySQL1台だけスレッドキャッシュサイズ違う。
  • MySQL1台だけファイルフォーマットがBarracuda/Antelope違う
  • 1台だけLANがeth0,1じゃなくてeth3,4に刺さってた
  • AppサーバいくつかJavaのマイナーバージョンが違う
  • なんか、参照しているLDAPサーバが違うやつがあった(別のDC拠点のLDAP見てた)
  • resolv.confが違うやつがいた(同じく別のDCのやつ見てる…)
  • 持っているべき公開鍵を持っていないやついた
おわり

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <img localsrc="" alt="">

Set your Twitter account name in your settings to use the TwitterBar Section.