Linux
Subversion
Jenkins

JenkinsによるLinuxサーバの設定変更管理(yggdrasil)の徹底

More than 3 years have passed since last update.

Jenkins アドベントカレンダー 2013 の12月15日の分として参加させて頂きます。

Linuxサーバの設定変更管理をSubversion(以下SVN)で行う yggdrasilという試みを行っているのですが、
この中でもJenkinsが威力を発揮していることをご紹介します。

yggdrasil とは何か

Linuxサーバの設定ファイルをSVNでバージョン管理するためのコマンド(SVNのラッパー)です。
SVNとRuby(gem)がインストールされていれば # gem install yggdrasil で簡単にインストールできます。

yggdrasilの機能概要

・Linuxの各種設定ファイルをSVNリポジトリに反映(コミット)させることで、SVNのリポジトリブラウザ等で履歴や差分を確認できるようにします。
・SVNリポジトリに反映(コミット)する際に、コミット内容(変更箇所)をdiff形式で確認した上でコミットできるUIを提供します。
・実ディレクトリに .svnディレクトリを作成しないように設定ファイルをミラーディレクトリにクローンしてSVNコマンドを実行します。
・全サーバのコミット漏れの内容を一元的に確認するためのクライアント/サーバ機能を提供します。

問題は概ね変更の中にある

サーバの設定変更の問題が月日が経ってから発覚した、という経験はないでしょうか?
例えば、HDDの残量低下のアラートを受けてトレンドを確認したところ一ヶ月以上前に突然増加し始めていた、というような問題です。

ソフトウェア開発でも似たように、月日が経ってから不具合が発覚する場合がありますよね。
原因がすぐに特定できる場合は良いのですが、そうでない場合は、
どのバージョン(リビジョン)から不具合が再現するようになるのかを探索し、
再現し始めるバージョンでの変更箇所を確認するのが常套手段なのではないでしょうか。

サーバの設定でも同様の手法が使えたら素晴らしいと思いませんか?
これを実現するのが yggdrasil になります。
全サーバの全ての設定ファイルがSVNの リポジトリに反映されていれば
HDDの使用量が増加し始めた日に どのような設定変更を行ったのかが
SVNのログから手に取るように簡単にそして明確に確認することができます。

自分がどこを変えたか全部把握できてるか?

トラブルシューティングでは、試行錯誤せざるを得ないこともある思います。

ソフトウェア開発でバージョン管理システムを使っていると、
試行錯誤した場合でも、どの部分をどう変えたのかを全て差分確認し、
修正してみたけど結局は修正する必要が無かった箇所や、
デバック用に入れたコードの戻し忘れを
コミット前にきっちりチェックすることが出来ますよね。

サーバ設定の試行錯誤でも同様の手法が使えたら素晴らしいと思いませんか?
これを実現するのが yggdrasil になります。
全ての設定ファイルがSVNの リポジトリに反映されていれば
設定ファイルの変更箇所を漏らさず確認することが出来ます。
意図しない設定変更は事故の元です。
明示的にコミット操作を要求することで変更に対する責任を明確にし、
意図していない設定変更が混入することを回避できることになります。

リポジトリに反映されていれば、、

サーバの設定ファイルのバージョン管理がソフトウェア開発のバージョン管理と事情が異なる点として、
SVNにコミットしなくても設定ファイルの変更がサーバの動作に反映される点があります。
つまり、サーバの設定変更がリポジトリにコミットされる必然性が無いのです。

このため、サーバの設定変更時に必ずコミットする運用ルールを定めたとしても、
どうしてもコミット操作が漏れる可能性をゼロには出来ず、
少しずつコミットされていない設定ファイルが増えていってしまいます。(エントロピー増大の法則)

そうなってしまうと、リポジトリの信憑生が失われてしまい、
「いつから不具合があったのか?」「この差分は今行った変更なのか?」が不明になり、
設定ファイルをSVNでパージョン管理している意味が根底から崩れてしまいます。

異常を見張って正常性を維持してくれる有能な執事:Jenkins

そこで頼りになるのがJenkinsです。

ソフトウェア開発では「ビルドが通ること」「テストが通ること」をJenkinsに見張ってもらうことで、
確認結果をきっちりと記録するとともに、異常が発生した際にはタイムリーに叱ってくれ、
そのおかげでコードを正常な状態に維持することが出来ます。

同様に、全サーバの設定ファイルのコミット状況をJenkinsに見張ってもらい、
記録(見える化)と異常通知(気付く化)をしてもらうことで、
全ての設定ファイルがリポジトリに反映されている状態を維持できる、というわけです。

具体的には次のような動作をします。
Sequence of yggserve results

Using yggdrasil

I. Jenkinsのサーバでyggdrasil server(yggserve daemon)を起動させておきます。
II. 設定ファイルをSVN管理する各サーバで一定の時間帯にコミット漏れチェック(ygg check)を行うようにcronに設定します。
III. IIのcron動作が全て完了している時刻にJenkinsのJobとしてコミット漏れチェックの集約(yggserve results)を定時実行し、コミット漏れがあった場合はJenkinsの機能でサーバ管理者にアラートメールを送信します。
IV. サーバ管理者はアラートメールの内容、またはJenkinsにWEBアクセスすることでコミット漏れを確認することができます。

問題は変化の中にある

先に「問題は概ね変更の中にある」と書きましたが、
バージョン管理することによって設定ファイルの変更を把握できるようになると、
設定ファイルの変更に起因しないシステム障害が浮彫りになってきます。

例えば具体的には、「マウント外れ」や「IPルーティングの変更」等がそれに当たります。
試行錯誤の中で行ったルーティング変更やリブート時に疎通が無かったことによるマウント失敗などは
気付かずに後で問題になるケースがありました。
(年単位で稼働し続けたサーバをリブートすると、この手の地雷が大概埋まっていますよね)

そこでyggdrasilにサーバの状態をチェックするための「checker」という機能を設けました。
checkerは ~/.yggdrasil/checker/(checkerディレクトリ)の中の実行可能ファイルを実行し、
その標準出力をバージョン管理の対象にするという単純な機能です。

例えばchekcerディレクトリの中にmountを実行するシェルスクリプトを書いておけば、
mountの実行結果に変化が出ていないかをJenkinsが見張ってくれることになります。
実行結果の中には都度変化して変更管理に不向きな内容もありますが、
それらはsortやgrepやsedをパイプするシェルスクリプトを書くことで不要な変化を除外するようにします。

ちなみに私の勤め先では下記をcheckerで確認するようにしています。
・ mount の結果
・ route の結果
・ service --status-all の結果
・ chkconfig --list の結果
・ rpm -qa の結果
・ gem list の結果
・ tcpのlistenポート(netstatの結果)

特に重要なシステムではDBのスキーマダンプをとるcheckerを仕込むことで
不用意なスキーマ変更を検知すると共に、
スキーマ変更時にはコミットログにRedmineのチケット番号を必ず書くことで
トレーサビリティを確保するようにしていたりします。

最後に、Jenkinsさんありがとう

設定ファイルをバージョン管理するというyggdrasilの試みも
Jenkinsによる「正常性の継続維持」が無ければ
「設定ファイルのバックアップコピーを作る代わり」ぐらいに留まっていたと思います。

それが、Jenkinsによってコミット漏れが無いことが保証されることで、
SVNリポジトリに信憑性が得られ、
全サーバの変更点の見える化とトレーサビリティの確保につながりました。
また、意図しないシステムの変化に対してアラートが上がることで、
システムの安定稼働に大きく貢献する形になっています。
Jenkinsさん、毎日本当にありがとうございます。

明日のJenkins アドベントカレンダー 2013akiko-pusuさんです。お楽しみに。