2013年01月14日

#Bagrant 開発記 (0/n) - Vagrantのようなものをbash実装してみた

このエントリーをはてなブックマークに追加

Bash + Vagrant ⇒ Bagrant

これまでに何度も仮想マシンイメージを作って来て、どこか面倒臭さを感じていた。そんな中、Vagrantに出会い、ソレが欲しかったモノの1つであると感じ、調査・検証・評価。そして、bash実装する事にした。

Bagrantの機能
  • Bagrantfileで仮想マシンを定義
  • bagrantコマンドで仮想マシンをビルド・起動・停止
  • ハイパーバイザーはKVM
利用ライブラリ

自作したvmbuilderのみ。

使い方

詳細はhansode/bagrantを参照の事で、起動までは、下記手順で行える。

  1. Bagrantfileを作成
    $ bagrant init
  2. 仮想マシンイメージをビルド
    $ bagrant build
  3. 仮想マシンを起動
    $ bagrant up

また、hansode/bagrant-boxがBagrantfileを含んだテンプレート集となっているので、Bagrantfileを自作したい方の参考になるはず。

開発期間

移植作業だったので、結構あっさりと実装出来た気がする。

  • 設計: 3日(主にVagrantの調査)
  • 実装: 2日
今後の予定

開発した動機がそうであるように、何か機能追加される事があったら、自分自身が欲しいと思ったタイミング。

あとがき

これも、まだ、自動化したかった事の1つでしかない。

フィードバックなど

もしBagrantに興味がある方がいらっしゃいましたら、ご一報下さい。


bashクックブック
bashクックブック
posted with amazlet at 13.01.13
Carl Albing JP Vossen Cameron Newham
オライリージャパン
売り上げランキング: 307,566




2012年11月01日

#vmbuilder.sh 開発記 (1/n) - CentOS 5 のKVM仮想マシンイメージを作成可能へ

このエントリーをはてなブックマークに追加

複数ディストリビューション対応へ向けて

ギーク達はfedora対応を希望

前回のエントリに反応してくれたギーク達は、CentOSよりもfedora対応を希望していた。『fedora対応…!』と思ったけども、fedoraを使ってないので良くわかってない。それよりは、複数ディストリビューション対応への準備体操として、CentOS 5対応に着手してみた。

検証環境

インストール
$ git clone git://github.com/hansode/vmbuilder.git
実行方法
$ cd vmbuilder/kvm/rhel/6/
$ sudo ./vmbuilder.sh --distro-name=centos --distro-ver=5

実行してから約10分程度で実行したディレクトリ直下に仮想マシンイメージが作成される。

2012/11/01現在の対応ディストリビューション

distro-name と distro-ver に指定可能な組み合わせは下記の通り。

  • centos 5 (5.x)
  • centos 6 (6.x)
  • sl 6 (6.x)

新規追加されるタイミングは、今の所、自分が欲しいと思う時か、聞こえて来る周りからの声。

問題点

rhel6環境でrhel5を構築すると、仮想マシンイメージを作成可能ではあるが、rhel5環境としては不完全だ。

  • 今のvmbuilder.shの仕様では、ホスト環境のyumコマンドでゲスト環境を構築する
  • ゲスト環境におけるrpmdbのフォーマットは、ホスト環境に依存する

個人的に困ってないので、しばらくの間は保留扱い。

改善案

検証すべき項目

  1. ホスト環境とゲスト環境を一致させる
    • 例) rhel5用仮想マシンイメージを構築する場合は、rhel5環境で行う
  2. post installフェーズで、rpmdbを変換するなどの対応をする
  3. yumコマンドかyum.confにrpmdbのバージョン指定する方法があれば、指定してみる

上記のうち、 1 が良さそうなので、対応手段は、構築フェーズを分ける事だろうか。

  1. ゴールとなる仮想マシンをビルドする為のビルド環境(1次chroot環境) を構築
  2. 構築されたビルド環境(1次chroot環境)にて、ゲスト環境(2次chroot環境)を構築
  3. ホスト環境にてマシンイメージ化

これで対応出来そうな気がするので、あとは検証・実装するだけの事。この辺をしっかり実装しておかないと、fedora対応も大変そう。

あとがき

環境差異が発生するとは面白い事。

フィードバックなど

希望するネタ等、フィードバック、大歓迎です。


KVM徹底入門 Linuxカーネル仮想化基盤構築ガイド
平 初 森若 和雄 鶴野 龍一郎 まえだ こうへい
翔泳社
売り上げランキング: 51792



2012年10月25日

#vmbuilder.sh 開発記 (0/n) - vmbuilder.shと言う解決策

このエントリーをはてなブックマークに追加

コマンドラインで仮想マシンイメージを作ろう!

面倒臭かった。世の中に出回っているCentOS用仮想マシンイメージ作成手順が。

  1. インストールDVD(ISOファイル)を用意
  2. virt-installコマンドを多数のオプション指定で実行…
  3. VNC接続して…

この手順には問題・課題があり、幾つか挙げると、

  • 手作業が入るので多少なりとも作業ブレが発生
  • 自動化すべく、kickstartを使うとしても、ks.cfg作成などの準備作業が面倒臭い
  • libvirt依存、KVM依存
  • どうやってテストする…?

Ubuntuであれば、VMBuilderが上記の問題・課題を解決してくれる。

  1. $ sudo apt-get install ubuntu-vm-builder
  2. $ sudo vmbuilder [options]....

vmbuilderコマンド実行後、10分ほどで仮想マシンイメージを作成される。

vmbuilderのお手軽さを知っていると、CentOSにおいても同様・同等の事が出来る事を期待した。しかし、残念ながら、VMBuilderはubuntu用だった。ゆえに、VMBuilderではCentOS用の仮想マシンイメージを作成出来ない。VMBuilderに似たツールを探してみたが、満足の行く物は見つからなかった…。

無いなら…作ろう!そして作った。bashで!

検証環境

  • RHEL 6.X / CentOS 6.X / Scientific Linux 6.X
  • bash 4.00
  • git 1.7

※他にkpartxやpartedなどに依存するが、本エントリでは詳細な依存パッケージは省略。

インストール
$ git clone git://github.com/hansode/vmbuilder.git
実行方法

KVM環境がなくても、KVM用仮想マシンイメージを作成可能なのである。

$ cd vmbuilder/kvm/rhel/6/
$ sudo ./vmbuilder.sh

実行してから約10分。実行したディレクトリ直下に仮想マシンイメージが作成される。

⇒ centos-6.3_x86_64.raw

※2012/10/25 現在、 centos-6.3 がデフォルトセット。

動作確認

出来上がった仮想マシンイメージを軽く確認したくなる。その場合は、下記手順でkvm-ctl.shを実行。 ここで初めてKVMが登場する。kvm-ctl.shはkvmコマンドのラッパースクリプトなので、virsh系のコマンドは不要。依然として、libvirtに依存しないまま。

$ sudo ./misc/kvm-ctl.sh start --image-path=./centos-6.3_x86_64.raw

tcp/6901でVNCが口を開けてるので、VNCクライアントで接続する。

仮想マシンにログイン
  • user: root
  • pass: root

開発用途なので、脆弱なパスフレーズで良いものとしてる。

あとがき

これは、まだ、自動化したかった事の1つでしかない。

フィードバックなど

本エントリはインストール手順と実行手順に留めておき、次のエントリからは開発苦労話などを執筆予定。 希望するネタ等、フィードバック、大歓迎です。


入門bash 第3版
入門bash 第3版
posted with amazlet at 12.10.25
Cameron Newham Bill Rosenblatt
オライリージャパン
売り上げランキング: 122689



2012年06月22日

[RHEL][rpm] インストール済みパッケージ調査時に使うrpmコマンドとオプション

このエントリーをはてなブックマークに追加

欲しい情報を正確に

"rpm -qa" の結果を駆使していたけども、どうも使い勝手が悪い。 例えばsedと組み合わせてパッケージ名を取り出そうとすると、時々うまくパース出来ないケースに遭遇。(うまく正規表現をかけてないとも言う)。

rpmのmanをじっくり読んでみると、ノーマルな"rpm -qa"よりも沢山情報を出力可能だった。

検証環境
  • CentOS 6.2 (x86_64)
  • rpm 4.8.0
インストール済みパッケージ情報のうち、欲しい情報

この他に欲しい物は無い。今のところは。

  • インストール日時
  • パッケージ名
  • バージョン番号
  • リリース番号
  • アーキテクチャ

これらを一発で出すコマンド。

$ rpm -qa --qf '%{INSTALLTIME} %{NAME} %{Version} %{Release} %{ARCH}\n'

出力例

$ rpm -qa --qf '%{INSTALLTIME} %{NAME} %{Version} %{Release} %{ARCH}\n' | sort -r | head
1338259926 openssh-clients 5.3p1 70.el6 x86_64
1338259923 kernel 2.6.32 220.el6 x86_64
1338259917 dracut-kernel 004 256.el6 noarch
1338259915 dracut 004 256.el6 noarch
1338259913 plymouth 0.8.3 24.el6.centos x86_64
1338259912 libdrm 2.4.25 2.el6 x86_64
1338259910 plymouth-core-libs 0.8.3 24.el6.centos x86_64
1338259909 libedit 2.11 4.20080712cvs.1.el6 x86_64
1338259907 dash 0.5.5.1 3.1.el6 x86_64
1338259906 which 2.19 6.el6 x86_64

『これだけじゃ足りないぜ!』と言う場合は、rpm --querytagsを実行すると使用可能タグを確認可能。

$ rpm --querytags | head
ARCH
ARCHIVESIZE
BASENAMES
BUGURL
BUILDARCHS
BUILDHOST
BUILDTIME
C
CAPABILITY
CHANGELOGNAME

いったいいくつあるのか確認してみると、

$ rpm --querytags | wc -l
170

170も。。

あと書き

困った時のman。


プロのための Linuxシステム構築・運用技術 (Software Design plus)
中井 悦司
技術評論社
売り上げランキング: 19428



2012年03月06日

[Sphinx][Cygwin] 日本語フォルダ/ファイル名を扱えるようにするパッチを作った #sphinxjp

このエントリーをはてなブックマークに追加

フォルダに日本語が入ってる時に"make html"が失敗する

Sphinxを利用してドキュメントを作成していたら、make htmlに失敗する現象に遭遇した。

$ make html
sphinx-build -b html -d _build/doctrees   . _build/html
Running Sphinx v1.1.2
WARNING: the config value '__file__' is set to a string with non-ASCII characters; this can lead to Unicode errors occurring. Please use Unicode strings, e.g. u'Content'.
loading pickled environment... not yet created
building [html]: targets for 4 source files that are out of date
updating environment: 4 added, 0 changed, 0 removed
reading sources... [ 25%] cloud-client
Exception occurred:
  File "/usr/lib/python2.6/site-packages/Sphinx-1.1.2-py2.6.egg/sphinx/environment.py", line 758, in read_doc
    pub.set_source(None, src_path.encode(fs_encoding))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 73: ordinal not in range(128)
The full traceback has been saved in /tmp/sphinx-err-Cg4EMC.log, if you want to report the issue to the developers.
Please also report this if it was a user error, so that a better error message can be provided next time.
Either send bugs to the mailing list at ,
or report them in the tracker at . Thanks!
make: *** [html] Error 1

幾つか試してみると、失敗する時は、フォルダ名に日本語が入っている。 この辺を検索してみると、同じように日本語フォルダ/ファイル名問題に失敗してる事例を発見。

Sphinx翻訳ハッカソン(2011/3/19)

手元の環境にhttp://paste.pocoo.org/show/355901/を適用してみると動かない。これはSphinxのバージョン差異が問題だった。

  • Sphinx 1.0.7

上記パッチを参考に書いたのが、下記検証環境において動作確認したパッチ。

検証環境
  • CYGWIN_NT-6.1
  • Python 2.6.5
  • Sphinx 1.1.2
Sphinx-1.1.2-py2.6.patch(日本語フォルダ/ファイル名を扱えるようにするパッチ)
あとがき

本パッチのベースとなるパッチを作成・公開して下さった @shimizukawa 様、ありがとうございます。


エキスパートPythonプログラミング
Tarek Ziade
アスキー・メディアワークス
売り上げランキング: 7179



2012年01月27日

[RHEL][Upstart] Upstartにおけるulimit設定とcore dump

このエントリーをはてなブックマークに追加

原因調査の行き着く先か・・・

原因調査の為、core dumpさせたい時がある。 ulimitを設定すれば良い訳だが、サービス管理はUpstartを利用している。 SysVinitではなく、Upstartでulimitを設定するには、どうしたものか。

検証環境

  • RHEL 6.0 / CentOS 6.0 (x86_64)
  • Upstart 0.6.5

要件定義

  • SysVinitとUpstartで同じ設定ファイルを使いたい
  • ジョブ単位で設定したい

作業概要

下記の事前調査を元に作業概要をまとめると、下記の通り。

  1. /etc/sysctl.confによるカーネルパラメータ設定
  2. /etc/sysconfig/(ジョブ名) を追記(or作成)し、変数DAEMON_COREFILE_LIMITを定義
  3. /etc/init/(ジョブ名).conf を修正し、
    1. /etc/sysconfig/init を読み込む
    2. /etc/sysconfig/(ジョブ名) を読み込む
  4. 強制core dumpさせてcore dumpファイルを作成してみる

事前調査

SysVinitの起動スクリプトがulimitを設定する流れを追ってみる。

  1. サンプルとして/etc/init.d/ssh を確認。
  2. /etc/init.d/sshの30行目で /etc/rc.d/init.d/functions を読み込んでる
    29  # source function library
    30  . /etc/rc.d/init.d/functions
    
  3. /etc/rc.d/init.d/functionsの239行目でulimit設定してるのが分かる
    239        corelimit="ulimit -S -c ${DAEMON_COREFILE_LIMIT:-0}"
    
  4. 変数 DAEMON_CORE_LIMIT を定義してるのはどこか?
  5. /etc/rc.d/init.d/functionsの29行目のコメントにより、構成定義してるのは、30行目で読み込んでる/etc/sysconfig/initだと分かる。
    28 # Read in our configuration
    29    if [ -f /etc/sysconfig/init ]; then
    30        . /etc/sysconfig/init
    31    else
    
  6. /etc/sysconfig/init の内容を確認してみると、
     1  # color => new RH6.0 bootup
     2  # verbose => old-style bootup
     3  # anything else => new style bootup without ANSI colors or positioning
     4  BOOTUP=color
     5  # column to start "[  OK  ]" label in
     6  RES_COL=60
     7  # terminal sequence to move to that column. You could change this
     8  # to something like "tput hpa ${RES_COL}" if your terminal supports it
     9  MOVE_TO_COL="echo -en \\033[${RES_COL}G"
    10  # terminal sequence to set color to a 'success' color (currently: green)
    11  SETCOLOR_SUCCESS="echo -en \\033[0;32m"
    12  # terminal sequence to set color to a 'failure' color (currently: red)
    13  SETCOLOR_FAILURE="echo -en \\033[0;31m"
    14  # terminal sequence to set color to a 'warning' color (currently: yellow)
    15  SETCOLOR_WARNING="echo -en \\033[0;33m"
    16  # terminal sequence to reset to the default color.
    17  SETCOLOR_NORMAL="echo -en \\033[0;39m"
    18  # Set to anything other than 'no' to allow hotkey interactive startup...
    19  PROMPT=yes
    20  # Set to 'yes' to allow probing for devices with swap signatures
    21  AUTOSWAP=no
    22  # What ttys should gettys be started on?
    23  ACTIVE_CONSOLES=/dev/tty[1-6]
    24  # Set to '/sbin/sulogin' to prompt for password on single-user mode
    25  # Set to '/sbin/sushell' otherwise
    26  SINGLE=/sbin/sushell
    
    DAEMON_COREFILE_LIMIT は存在しない。
  7. /etc/sysconfig/sshd の33行目
    32  # pull in sysconfig settings
    33  [ -f /etc/sysconfig/sshd ] && . /etc/sysconfig/sshd
    
    /etc/sysconfig/sshd を読み込んでるのが分かる。ここでもDAEMON_COREFILE_LIMITは可能だ。
  8. /etc/sysconfig/sshdは存在しない。
    # ls -l /etc/sysconfig/sshd
    ls: cannot access /etc/sysconfig/sshd: No such file or directory
    
  9. ${DAEMON_COREFILE_LIMIT:-0} は、変数値が無い場合 0。設定しない場合は、 0 だと分かる。

sshの場合は、下記2ファイルのうちどちらかで定義すれば良い。

  • /etc/sysconfig/init
  • /etc/sysconfig/sshd

前者はSysVinit全体に対する設定ファイルで、後者はサービス個別の設定ファイル。 どちらで設定するかは、利用環境に依存する。

環境定義

検証用に fake-service を作成する。

ジョブ名fake-service
sys config/etc/sysconfig/fake-service
upstart config/etc/init/fake-service.conf

作業内容

core dump取得設定

core dumpファイルを取得する為の準備作業として、カーネルパラメータ設定。

/etc/sysctl.conf (追記)
kernel.core_pattern = /tmp/core
kernel.core_uses_pid = 1

/etc/sysctl.confを反映

# sysctl -p

これにより、 /tmp/core.PID としてcore dumpファイルが作成される。

fake-service設定
/etc/sysconfig/fake-service
DAEMON_COREFILE_LIMIT=unlimited
  • /etc/sysconfig/init に設定すると、SysVinit全体設定となるので、今回はfake-service限定としておく。
/etc/init/fake-service.conf
respawn

script
    # system global
    [ -f /etc/sysconfig/init ] && {
      . /etc/sysconfig/init
    }
    # job local
    [ -f /etc/sysconfig/fake-service ] && {
      . /etc/sysconfig/fake-service
    }

    # /etc/rc.d/init.d/functions line#239> corelimit="ulimit -S -c ${DAEMON_COREFILE_LIMIT:-0}"
    ulimit -c ${DAEMON_COREFILE_LIMIT:-0}

    exec sleep 3600
end script
  1. /etc/sysconfig/initを先に読み込む。
  2. /etc/sysconfig/fake-serviceを次に読み込む。
  3. DAEMON_COREFILE_LIMIT が定義済みであれば、 DAEMON_COREFILE_LIMITの値。未定義であれば、0。
Upstartのジョブ操作

ジョブが起動してない事を確認。

# initctl status fake-service
fake-service stop/waiting

ジョブを起動。

# initctl start fake-service
fake-service start/running, process 3500

プロセスIDが 3500 である事が分かる。

プロセスID指定でプロセスを確認。

# ps -p 3500
  PID TTY          TIME CMD
 3500 ?        00:00:00 sleep

Upstartによってexecしてるsleepである事が分かる。

QUITシグナルを送り、強制的にcore dumpさせる。

# kill -QUIT 3500

QUITシグナル送信後のジョブ状態を確認。

# initctl status fake-service
fake-service start/running, process 3595

QUITシグナル送信により、プロセスIDが変化してる。3500 → 3595。

core dumpファイルを確認

core dumpファイルが作成されてる事を確認出来る。

# ls -la /tmp/core.3500
-rw-------. 1 root root 319488 Jan 27 19:02 /tmp/core.3500

gdbによる調査・デバッグへと進むのであった・・・。

あと書き

/etc/sysconfig/を使わず、/etc/init/fake-service.conf内でulimitの設定値をハードコードしてしまっても良いのでは無いか?


プロのための Linuxシステム構築・運用技術 (Software Design plus)
中井 悦司
技術評論社
売り上げランキング: 6581



2012年01月26日

[RHEL][flog] ログローテートを考慮してないプログラムのログを安全にローテートする

このエントリーをはてなブックマークに追加

v.s. ログローテート未対応プログラム

  1. 標準出力しかしないプログラムがあったとする。
  2. プログラムの出力をログファイルとして保存する為に、標準出力をリダイレクトしてログファイルを作成して対応したとする。

こんな状況。

$ program > /path/to/command.log

このログファイルを、どうにかしてをローテートしたい。さて、どうする?

flog(file logger)と言う選択肢

いくつかあるであろう解決策の1つとして、今回はflogを使って解決した。

WHAT IS IT?
===========

flog (file logger) is a program that reads input from STDIN
and writes to a file. if a SIGHUP is received, the file will be
reopened, allowing for log rotation [see logrotate(8) on RH.]
The log file will only be reopened if flog detects that
rotation has occurred (ie, old file gone or inode changed).
flog is very small (less than 500 bytes memory footprint.)

コマンドで説明すると下記の通り。

$ program | flog /path/to/log

$ mv -i /path/to/log /path/to/log.1
$ kill -HUP "flog's PID"

後はHUPシグナル送信をlogrotate(8)内で行えば良いだけの事。 flogへのシグナル送信である所がミソ。

検証環境

  • RHEL 6.0 / CentOS 6.0 (x86_64)
  • alien 8.81
  • flog 1.8
  • upstart 0.6.5
  • logrotate 3.7.8

要件定義

  • サービス監視プログラムは修正しない
  • 標準出力をログファイルへ出力・保存
  • サービスを再起動する事無く、ログファイルを安全にローテート

作業概要

  1. flog環境構築
    1. 残念ながらflogのrpmは無く、debは存在するので、debからrpmを作成する。
    2. flogのdebパッケージをダウンロード
    3. alienを使ってdebからrpmへ変換
    4. flogをインストール
  2. upstart configを作成
  3. logrotate configを作成
  4. ログローテート確認

環境定義

サービスプログラム/tmp/fake-service.sh
ログファイル/var/log/fake-service.log
upstart/etc/init/fake-service.conf
logrotate/etc/logrotate.d/fake-service

事前作業

作業内容

flog環境構築

fakerootをインストール

$ sudo yum install -y fakeroot

flogのdebパッケージを取得

$ curl -O http://ftp.jaist.ac.jp/pub/Linux/ubuntu//pool/universe/f/flog/flog_1.8-3_amd64.deb

alienでdebをrpmへ変換

$ fakeroot alien --to-rpm ./flog_1.8-3_amd64.deb
flog-1.8-4.x86_64.rpm generated
find: `flog-1.8': No such file or directory

$ ls -l flog-1.8-4.x86_64.rpm
-rw-r--r-- 1 hansode hansode 9801 Jan 25 18:34 flog-1.8-4.x86_64.rpm

変換したrpmをインストール

$ sudo rpm -ivh flog-1.8-4.x86_64.rpm

インストールされている事を確認

$ which flog
/usr/bin/flog

$ rpm -qf `which flog`
flog-1.8-4.x86_64
ダミーのfake-service

実際に何か出力するだけのダミースクリプトを配置。

/tmp/fake-service.sh
#!/bin/sh

while date; do sleep 1; done

実行権限付与。

$ chmod +x /tmp/fake-service.sh
upstart設定とlogrotate設定
/etc/init/fake-service.conf
start on runlevel [2345]
stop on runlevel [016]

respawn

exec /tmp/fake-service.sh \
  | /usr/bin/flog \
 -p /var/run/fake-service.pid \
    /var/log/fake-service.log
  • fake-serviceの標準出力をflogが受け取り、/var/log/fake-service.logとして出力
  • -pオプションでflogのPIDを /var/log/fake-service.log として記録
/etc/logrotate.d/fake-service
/var/log/fake-service.log {
    rotate 10
    compress
    missingok
    sharedscripts
    create 0644 root root
    postrotate
      pid_file=/var/run/fake-service.pid
      [ -f ${pid_file} ] || exit 0
      pid=`cat ${pid_file}`
      ps -p ${pid} >/dev/null || exit 0
      kill -HUP ${pid}
    endscript
}
  • postrotateで、ローテート後の処理を定義可能。
  • flogプロセスにHUPシグナルを送信
  • flogのPIDは、PIDファイルから取得可能
ログローテート準備

サービスを起動。

$ sudo initctl start fake-service
fake-service start/running, process 28692

この例ではPIDが 28692。ログローテート確認時にも利用するのでメモ。

pidファイルを確認。

$ ls -la /var/run/fake-service.pid
-rw-r--r-- 1 root root 6 Jan 26 19:19 /var/run/fake-service.pid
$ cat /var/run/fake-service.pid
28694

flogのPIDが 28694 である事が分かる。

$ ps -fp `cat /var/run/fake-service.pid`
UID        PID  PPID  C STIME TTY          TIME CMD
root     28694 28692  0 19:19 ?        00:00:00 /usr/bin/flog -p /var/run/fake-service.pid /var/log/fake-service.log

プロセスID指定で確認してみると、flogである事が分かる。親PIDはupstartのPIDである事も分かる。

プロセスPID
fake-service28692
flog28694

ローテート前のログ状態を確認。

$ ls -l /var/log/fake-service.log*
-rw-r--r-- 1 root root 12758 Jan 26 19:21 /var/log/fake-service.log

ローテート前なので、ログファイルが1つ。

ログローテート実行

ログローテートしてみる。

$ sudo logrotate -f /etc/logrotate.d/fake-service
ログローテート後の確認

サービスのPIDに変化が無い事を確認。

$ sudo initctl status fake-service
fake-service start/running, process 28692

pidファイルを確認。

$ ls -la /var/run/fake-service.pid
-rw-r--r-- 1 root root 6 Jan 26 19:19 /var/run/fake-service.pid
$ cat /var/run/fake-service.pid
28694

pidファイルのPIDでプロセスを確認。

$ ps -fp `cat /var/run/fake-service.pid`
UID        PID  PPID  C STIME TTY          TIME CMD
root     28694 28692  0 19:19 ?        00:00:00 /usr/bin/flog -p /var/run/fake-service.pid /var/log/fake-service.log

flogである事が分かる。

ローテート後のログ状態を確認。

$ ls -la /var/log/fake-service.log*
-rw-r--r-- 1 root root 3599 Jan 26 19:34 /var/log/fake-service.log
-rw-r--r-- 1 root root  485 Jan 26 19:32 /var/log/fake-service.log.1.gz

ローテートされている事が分かる。

$ sudo initctl status fake-service
fake-service start/running, process 28692
プロセスPID
fake-service28692
flog28694

PIDは変化してない。

もう一度ログローテート

ローテートを実行。

$ sudo logrotate -f /etc/logrotate.d/fake-service

ログファイルを確認。

$ ls -la /var/log/fake-service.log*
-rw-r--r-- 1 root root 235 Jan 26 19:37 /var/log/fake-service.log
-rw-r--r-- 1 root root 787 Jan 26 19:37 /var/log/fake-service.log.1.gz
-rw-r--r-- 1 root root 485 Jan 26 19:32 /var/log/fake-service.log.2.gz

ローテートされている事を確認。

あと書き

ログローテートを考慮しないプログラムに遭遇して困ったら、flogが悩みを解決してくれるだろう。


プロのための Linuxシステム構築・運用技術 (Software Design plus)
中井 悦司
技術評論社
売り上げランキング: 6253



2012年01月25日

[RHEL] alienでパッケージ変換(deb→rpm)

このエントリーをはてなブックマークに追加

debをrpmへ変換したい

rpmは無いけどもdebには存在する場合に時々使える。 小さいパッケージであればalienで変換すれば手軽にrpmへ変換が可能。

検証環境

  • RHEL 6.0 / CentOS 6.0 (x86_64)
  • alien 8.81

作業概要

  1. alianのtarballをダウンロード
  2. tarballからrpmを作成

作業内容

依存パッケージをインストール

$ sudo yum install -y rpm-build perl-ExtUtils-MakeMaker

tarballを取得

$ curl -O http://ftp.debian.org/debian/pool/main/a/alien/alien_8.81.tar.gz

tarballからrpmをビルド

$ rpmbuild -ta alien_8.81.tar.gz

ビルドしたrpmをインストール

$ sudo rpm -ivh ~/rpmbuild/RPMS/noarch/alien-8.81-1.noarch.rpm

インストールされてる事を確認

$ which alien
/usr/bin/alien
$ rpm -qf `which alien`
alien-8.81-1.noarch



2011年12月19日

[RHEL][DRBD] Linux+DRBDで作るサーバ冗長構成

このエントリーをはてなブックマークに追加

名前は聞いた事があるのに、構築しなかった環境の1つ

DRBD環境構築が必要だったので、DRBD環境を構築。

構築完了したのは1ヶ月半も前の事。作業記録のタイムスタンプを見ると、11/08。 アウトプットするまでに随分と時間がかかってしまった事に反省。

検証環境
  • RHEL 6.0 / CentOS 6.0 (i686)
  • drbd 8.4.0
要件定義
作業概要
  1. DRBDをインストール
  2. DRBDの設定ファイルを作成
  3. DRBDを起動
  4. データ同期確認
サーバ構成
ノード名用途IPアドレスNIC
node1master192.0.2.2eth0
node2backup192.0.2.3
-Virtual IP192.0.2.254
作業内容
事前作業

DRBDをビルドするに辺り必要なパッケージをインストール。

$ sudo yum install -y gcc make automake autoconf flex rpm-build kernel-devel libxslt fakeroot

rpmbuildで必要となるディレクトリ構造を作成。く

$ mkdir -p /home/centos/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}

ソースをダウンロード

$ curl -O http://oss.linbit.com/drbd/8.4/drbd-8.4.0.tar.gz

ダウンロードしたソースを伸長。

$ tar zxvf drbd-8.4.0.tar.gz

configureスクリプトを実行。

$ cd drbd-8.4.0
$ ./configure

fakerootを経由してmakeを実行。fakerootを使う理由は、rpmをビルドするにはroot権限であるから。fakerootがroot権限であるかのような振る舞いをしてくれる。

$ fakeroot make rpm km-rpm

無事にビルドが完了すると、下記rpmが作成される。

$ ls -1 /home/centos/rpmbuild/RPMS/i386/
drbd-8.4.0-1.el6.i386.rpm
drbd-bash-completion-8.4.0-1.el6.i386.rpm
drbd-heartbeat-8.4.0-1.el6.i386.rpm
drbd-km-2.6.32_71.el6.i686-8.4.0-1.el6.i386.rpm
drbd-pacemaker-8.4.0-1.el6.i386.rpm
drbd-udev-8.4.0-1.el6.i386.rpm
drbd-utils-8.4.0-1.el6.i386.rpm
drbd-xen-8.4.0-1.el6.i386.rpm

ビルド済みrpmで必要なのは drbd-utilsとdrbd-km。これらをインストール。

$ sudo rpm -ivh \
 /home/centos/rpmbuild/RPMS/i386/drbd-utils-8.4.0-1.el6.i386.rpm \
 /home/centos/rpmbuild/RPMS/i386/drbd-km-2.6.32_71.el6.i686-8.4.0-1.el6.i386.rpm

カーネルモジュールをロードしてみる。

$ lsmod | grep drbd
$ sudo modprobe drbd
$ lsmod | grep drbd
drbd                  274063  0
libcrc32c                815  1 drbd

"/etc/init.d/drbd start "実行にmodprobe drbdが実行されるので、ここではmodprobeコマンドでカーネルモジュールを正常にロード出来る事を確認するだけで良い。

起動対象サービスに入ってるのを確認しておく。

$ chkconfig --list drbd
drbd            0:off   1:off   2:on    3:on    4:on    5:on    6:off
デバイスファイル用意

今回はrawファイルを作成しループバックマウントしてDRBD用デバイスファイルを調達する。

$ sudo dd if=/dev/zero of=/var/tmp/drbd.img bs=1M count=128
$ sudo losetup -f
/dev/loop0

作ったrawファイルを空きデバイス/dev/loop0にマッピングさせる。

$ sudo losetup /dev/loop0 /var/tmp/drbd.img
$ sudo losetup -a
/dev/loop0: [fd00]:266486 (/var/tmp/drbd.img)

これでDRBD用の同期対象デバイスが出来上がった。

DRBD設定

必要に応じて/etc/hostsにホスト登録しておく。 理由は、configでIPアドレス指定するにも関わらず、名前解決に失敗すると起動しない為。

$ sudo vi /etc/hosts
> 192.0.2.2  drbd-primary
> 192.0.2.3  drbd-secondary

configを追加。ドキュメントで拡張子は「.res」が推奨されているので、sandbox.resとして作成。

/etc/drbd.d/sandbox.res
resource sandbox {
  protocol C;
  device /dev/drbd0;
  disk   /dev/loop0;
  meta-disk internal;

  on drbd-primary {
    address 192.0.2.2:7801;
  }
  on drbd-secondary {
    address 192.0.2.3:7801;
  }
}

DRBDデバイスを初期化

$ sudo drbdadm create-md sandbox
Writing meta data...
initializing activity log
NOT initializing bitmap
New drbd meta data block successfully created.
success

※注意: iptablesが有効になってるとDRBD通信が行われない場合がある

DRBDを起動。

$ sudo /etc/init.d/drbd start
Starting DRBD resources: [
     create res: sandbox
   prepare disk: sandbox
    adjust disk: sandbox
     adjust net: sandbox
]
.....

DRBDが起動すると/proc/drbdが作成される。

$ cat /proc/drbd
version: 8.4.0 (api:1/proto:86-100)
GIT-hash: 28753f559ab51b549d16bcf487fe625d5919c49c build by centos@centos, 2011-11-08 16:16:36
 0: cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent C r-----
    ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:131032

この時、どちらもsecondaryになっているのが分かる。

データ同期確認

primary側でファイルを作成し、secondaryへデータ同期が行われるのを確認する。

ndoe1: (secondary→primary)

node1をprimaryに昇格させる。

$ sudo drbdadm primary --force sandbox

primaryからsecondaryへの同期処理が開始され、しばらくすると同期完了する。

$ cat /proc/drbd
version: 8.4.0 (api:1/proto:86-100)
GIT-hash: 28753f559ab51b549d16bcf487fe625d5919c49c build by centos@centos, 2011-11-08 16:16:36
 0: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r-----
    ns:2664 nr:0 dw:0 dr:3476 al:0 bm:0 lo:0 pe:3 ua:3 ap:0 ep:1 wo:b oos:128600
        [>....................] sync'ed:  3.2% (128600/131032)K
        finish: 0:00:45 speed: 2,432 (2,432) K/sec

$ cat /proc/drbd
version: 8.4.0 (api:1/proto:86-100)
GIT-hash: 28753f559ab51b549d16bcf487fe625d5919c49c build by centos@centos, 2011-11-08 16:16:36
 0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
    ns:131032 nr:0 dw:0 dr:131696 al:0 bm:8 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:0

DRBDデバイスを確認。設定通り/dev/drbd0が作成されているのが分かる。

$ ls -la /dev/drbd0
brw-rw---- 1 root disk 147, 0 Nov  8 17:19 /dev/drbd0

通常のディスクデバイスファイルと同様にDRBDデバイスをフォーマットし、マウントすれば利用可能となる。

$ sudo mkfs -t ext4 /dev/drbd0
$ sudo mkdir /mnt/drbd0
$ sudo mount -t ext4 /dev/drbd0 /mnt/drbd0

マウント後の内容確認。

$ ls -la /mnt/drbd0/
total 17
drwxr-xr-x  3 root root  1024 Nov  8 17:22 .
drwxr-xr-x. 3 root root  4096 Nov  8 17:23 ..
drwx------  2 root root 12288 Nov  8 17:22 lost+found

primary・secondary間でデータ同期されるのを確認するため、ファイルを作成してみる。

$ sudo touch /mnt/drbd0/test.txt
$ ls -la /mnt/drbd0/
total 17
drwxr-xr-x  3 root root  1024 Nov  8 17:23 .
drwxr-xr-x. 3 root root  4096 Nov  8 17:23 ..
drwx------  2 root root 12288 Nov  8 17:22 lost+found
-rw-r--r--  1 root root     0 Nov  8 17:23 test.txt
node1:(primary→secondary)

DRBDが使用中だとsecondaryへ降格出来ないので、デバイスをumountする。

$ sudo umount /mnt/drbd0

secondaryへ降格させる。

$ sudo drbdadm secondary sandbox
$ cat /proc/drbd
version: 8.4.0 (api:1/proto:86-100)
GIT-hash: 28753f559ab51b549d16bcf487fe625d5919c49c build by centos@centos, 2011-11-08 16:16:36
 0: cs:Connected ro:Secondary/Secondary ds:UpToDate/UpToDate C r-----
    ns:139687 nr:0 dw:8655 dr:132451 al:10 bm:8 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:0

これにより、他のsecondaryがprimaryへ昇格可能状態となる。

node2: (secondary→primary)

node2をprimaryへ昇格させる。

$ sudo drbdadm primary sandbox

/proc/drbdでprimaryになっているのが分かる。

$ cat /proc/drbd
version: 8.4.0 (api:1/proto:86-100)
GIT-hash: 28753f559ab51b549d16bcf487fe625d5919c49c build by centos@centos, 2011-11-08 16:16:36
 0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
    ns:0 nr:139687 dw:139687 dr:664 al:0 bm:8 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:0

DRBDデバイスの内容を確認する為、マウントする。

$ sudo mkdir /mnt/drbd0
$ sudo mount -t ext4 /dev/drbd0 /mnt/drbd0/

マウントポイントの内容を確認。node1で作成した test.txt が存在しているのが分かる。

$ ls -la /mnt/drbd0/
total 17
drwxr-xr-x  3 root root  1024 Nov  8 17:23 .
drwxr-xr-x. 3 root root  4096 Nov  8 17:25 ..
drwx------  2 root root 12288 Nov  8 17:22 lost+found
-rw-r--r--  1 root root     0 Nov  8 17:23 test.txt
node2: (primary→secondary)

umountし、secondaryへ降格させる。

$ sudo umount /mnt/drbd0
$ sudo drbdadm secondary sandbox

/dev/drbdでsecondaryに降格している事を確認。

$ cat /proc/drbd
version: 8.4.0 (api:1/proto:86-100)
GIT-hash: 28753f559ab51b549d16bcf487fe625d5919c49c build by centos@centos, 2011-11-08 16:16:36
 0: cs:Connected ro:Secondary/Secondary ds:UpToDate/UpToDate C r-----
    ns:18 nr:139687 dw:139705 dr:671 al:3 bm:8 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:0

これでnode1, node2がどちらもsecondaryになってる状態。 後はnode1をprimaryに昇格させて、同期させるだけ。

あと書き

DRBDのバージョンによってコマンド名、引数に違いがあるので、よく確認すべし。




2011年11月10日

[RHEL][ucarp] Linux + ucarpによるサーバ冗長化 (複数VIP編)

このエントリーをはてなブックマークに追加

複数NICと複数IPアドレス、複数VIP

本エントリは、前エントリ 『Linux + ucarpによるサーバ冗長化』 の続編。前エントリでは、単一ネットワークにおける冗長化。それに対し、本エントリでは複数ネットワークを扱う。

検証環境
  • RHEL 6.0 / CentOS 6.0
  • ucarp 1.5.2-1.el6
要件定義
  • 障害が発生したネットワークのVIPのみfailover
  • 正常ネットワークのVIPはfailoverしなくて良い
作業概要
  1. VIPの数だけconfigを作成
  2. ucarpを起動
  3. サービスの状態を確認
サーバ構成
 node1node2vip
役割masterbackup 
eth2192.0.2.2/25192.0.2.3/25192.0.2.126/25
eth3192.0.2.130/25192.0.2.131/25192.0.2.254/25
事前作業
  • Linux + ucarpによるサーバ冗長化により、ucarp環境が構築されている事
  • 前エントリで作成した /etc/ucarp/vip-001.conf が存在する場合は、/etc/ucarp/vip-001.conf.saved など、 suffixが .conf にならないようにしておく事。.savedにしておけば、include対象外となる。
    # mv -i /etc/ucarp/vip-001.conf /etc/ucarp/vip-001.conf.saved
作業内容

設定値に従い、ucarpの設定ファイルを作成。 今回はVIP数が2つなので、confファイルとIDが2つ用意する必要がある。

ucarp設定: node1編
node1:/etc/ucarp/vip-002.conf
SOURCE_ADDRESS=192.0.2.2

ID=002
BIND_INTERFACE=eth2
VIP_ADDRESS=192.0.2.126
OPTIONS="--shutdown --preempt"
node1:/etc/ucarp/vip-003.conf
SOURCE_ADDRESS=192.0.2.130

ID=003
BIND_INTERFACE=eth3
VIP_ADDRESS=192.0.2.254
OPTIONS="--shutdown --preempt"
ucarp設定: node2編
node2:/etc/ucarp/vip-002.conf
SOURCE_ADDRESS=192.0.2.3

ID=002
BIND_INTERFACE=eth2
VIP_ADDRESS=192.0.2.126
OPTIONS="--shutdown --preempt"
node2:/etc/ucarp/vip-003.conf
SOURCE_ADDRESS=192.0.2.131

ID=003
BIND_INTERFACE=eth3
VIP_ADDRESS=192.0.2.254
OPTIONS="--shutdown --preempt"
ucarp起動

前エントリ同様に、今回の設定でも重要なのは、ucarpの起動順番。 これは、先にucarpを起動させたノードがucarp-masterとなる為である。

  1. master(今回はnode1)
  2. backup(今回はnode2)

起動順番は十分気をつける。

node1# /etc/init.d/ucarp start
node2# /etc/init.d/ucarp start
正常時(ucarp起動後)

各ノードで "ip addr show" を実行すると、どちらにVIPが割り当てられているかを確認出来る。 ucarp起動順番やネットワークに問題がなければ、下記のようにmasterノードにVIPが割り当てられる。

node1
# ip addr show eth2 | grep -w inet
    inet 192.0.2.2/25 brd 192.0.2.127 scope global eth2
    inet 192.0.2.126/32 scope global eth2
# ip addr show eth3 | grep -w inet
    inet 192.0.2.130/25 brd 192.0.2.255 scope global eth3
    inet 192.0.2.254/32 scope global eth3
node2
# ip addr show eth2 | grep -w inet
    inet 192.0.2.3/25 brd 192.0.2.127 scope global eth2
# ip addr show eth3 | grep -w inet
    inet 192.0.2.131/25 brd 192.0.2.255 scope global eth3
ノード単位でfailover/failback

前エントリと同様に、ucarpプロセスを起動・停止させる事により、failoverを確認出来る。

node1
# /etc/init.d/ucarp stop
# /etc/init.d/ucarp start
node2
# /etc/init.d/ucarp stop
# /etc/init.d/ucarp start
切り替わる途中経過は、/var/log/messageで確認可能
# tail -F /var/log/message
failover時の状態

MASTERがnode1からnode2へ切り替わった時の/var/log/message出力例。 node2のstateがMASTERへ遷移しているのが分かる。

node1(master⇒backup):/var/log/message
Nov 10 02:53:01 centos ucarp[1437]: [WARNING] Spawning [/usr/libexec/ucarp/vip-down eth2 192.0.2.126]
Nov 10 02:53:01 centos ucarp[1446]: [WARNING] Spawning [/usr/libexec/ucarp/vip-down eth3 192.0.2.254]
Nov 10 02:53:01 centos ucarp: all ucarp daemons stopped and IP addresses unassigned
node2(backup⇒master):/var/log/message
Nov 10 02:53:02 centos ucarp[1426]: [WARNING] Switching to state: MASTER
Nov 10 02:53:02 centos ucarp[1435]: [WARNING] Switching to state: MASTER
Nov 10 02:53:02 centos ucarp[1435]: [WARNING] Spawning [/usr/libexec/ucarp/vip-up eth3 192.0.2.254]
Nov 10 02:53:02 centos ucarp[1426]: [WARNING] Spawning [/usr/libexec/ucarp/vip-up eth2 192.0.2.126]
VIPの数だけucarpプロセスが起動

Q. 下記状態では、ucarpはどんな動きをするのだろうか?

  • VIP#1 一方のネットワークに障害発生
  • VIP#2 もう一方のネットワークは正常

A. 障害発生中のVIPのみ切り替わる。

  • VIP#1 MASTERからBACKUPへ切り替わる
  • VIP#2 MASTERのまま

ucarpは、VIPの数と同等のプロセスが起動し、masterとbackupが通信し合って監視する。 VIPが2つある場合、ucarpプロセスも2つ。下記の通り、VIPが2の場合のucarpプロセスは、2つあるのが分かる。

# ps -ef | egrep '[u]carp'
root      1756     1  0 05:08 ?        00:00:00 /usr/sbin/ucarp --daemonize --interface=eth2 --pass=love --srcip=192.0.2.2 --vhid=002 --addr=192.0.2.126 --shutdown --preempt --upscript=/usr/libexec/ucarp/vip-up --downscript=/usr/libexec/ucarp/vip-down
root      1764     1  0 05:08 ?        00:00:00 /usr/sbin/ucarp --daemonize --interface=eth3 --pass=love --srcip=192.0.2.130 --vhid=003 --addr=192.0.2.254 --shutdown --preempt --upscript=/usr/libexec/ucarp/vip-up --downscript=/usr/libexec/ucarp/vip-down
2本ある監視ラインのうち、1本をdownさせてみるとどうなるのか

監視ライン1本をdownさせ、ucarpプロセスが独立して動作するのを観察してみる。

【方法】node1のeth1をdownさせる

node1
# ifdown eth3

【確認】 down後のucarp状態

node1:/var/log/message
Nov 10 05:29:24 centos ucarp[1764]: [ERROR] exiting: pfds[0].revents = 8
⇒ eth3を監視していたucarpが異常終了
node2:/var/log/message
Nov 10 05:29:25 centos ucarp[1811]: [WARNING] Switching to state: MASTER
Nov 10 05:29:25 centos ucarp[1811]: [WARNING] Spawning [/usr/libexec/ucarp/vip-up eth3 192.0.2.254]
⇒ eth3側のvipがupしている

【確認】 ucarpプロセスはどうなっているのか

node1
# ps -ef | egrep '[u]carp'
root      1756     1  0 05:08 ?        00:00:00 /usr/sbin/ucarp --daemonize --interface=eth2 --pass=love --srcip=192.0.2.2 --vhid=002 --addr=192.0.2.126 --shutdown --preempt --upscript=/usr/libexec/ucarp/vip-up --downscript=/usr/libexec/ucarp/vip-down
⇒ ucarpプロセスは1つ
node1
# ps -ef | egrep '[u]carp'
root      1803     1  0 05:29 ?        00:00:00 /usr/sbin/ucarp --daemonize --interface=eth2 --pass=love --srcip=192.0.2.3 --vhid=002 --addr=192.0.2.126 --shutdown --preempt --upscript=/usr/libexec/ucarp/vip-up --downscript=/usr/libexec/ucarp/vip-down
root      1811     1  0 05:29 ?        00:00:00 /usr/sbin/ucarp --daemonize --interface=eth3 --pass=love --srcip=192.0.2.131 --vhid=003 --addr=192.0.2.254 --shutdown --preempt --upscript=/usr/libexec/ucarp/vip-up --downscript=/usr/libexec/ucarp/vip-down
⇒ ucarpプロセスは2つ

この結果により、eth3側のみfailoverしている事が分かる。 VIPを更に1つ2つ追加しても、問題なく動作してくれるだろう。

あとがき

/etc/ucarp/vip-*.conf を追加した後は、upscript/downscriptを充実させれば良いだけか。