2012年03月06日
フォルダに日本語が入ってる時に"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
幾つか試してみると、失敗する時は、フォルダ名に日本語が入っている。 この辺を検索してみると、同じように日本語フォルダ/ファイル名問題に失敗してる事例を発見。
- 清水川
- 日本語ファイル名を使うとmake htmlできない問題をちょっと追ってみたい。 元ネタ:
http://twitter.com/kotakanbe/statuses/48632925364826113- Sphinxで日本語ファイル名/ディレクトリ名を扱えるようにするパッチが 出来ました
http://paste.pocoo.org/show/355901/ 人柱とコードレビューアを募集中です。
手元の環境に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 様、ありがとうございます。
アスキー・メディアワークス
売り上げランキング: 7179
2012年01月27日
原因調査の行き着く先か・・・
原因調査の為、core dumpさせたい時がある。 ulimitを設定すれば良い訳だが、サービス管理はUpstartを利用している。 SysVinitではなく、Upstartでulimitを設定するには、どうしたものか。
検証環境
- RHEL 6.0 / CentOS 6.0 (x86_64)
- Upstart 0.6.5
要件定義
- SysVinitとUpstartで同じ設定ファイルを使いたい
- ジョブ単位で設定したい
作業概要
下記の事前調査を元に作業概要をまとめると、下記の通り。
- /etc/sysctl.confによるカーネルパラメータ設定
- /etc/sysconfig/(ジョブ名) を追記(or作成)し、変数DAEMON_COREFILE_LIMITを定義
- /etc/init/(ジョブ名).conf を修正し、
- /etc/sysconfig/init を読み込む
- /etc/sysconfig/(ジョブ名) を読み込む
- 強制core dumpさせてcore dumpファイルを作成してみる
事前調査
SysVinitの起動スクリプトがulimitを設定する流れを追ってみる。
- サンプルとして/etc/init.d/ssh を確認。
- /etc/init.d/sshの30行目で /etc/rc.d/init.d/functions を読み込んでる
29 # source function library 30 . /etc/rc.d/init.d/functions
- /etc/rc.d/init.d/functionsの239行目でulimit設定してるのが分かる
239 corelimit="ulimit -S -c ${DAEMON_COREFILE_LIMIT:-0}" - 変数 DAEMON_CORE_LIMIT を定義してるのはどこか?
- /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
- /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/sushellDAEMON_COREFILE_LIMIT は存在しない。 - /etc/sysconfig/sshd の33行目
32 # pull in sysconfig settings 33 [ -f /etc/sysconfig/sshd ] && . /etc/sysconfig/sshd
/etc/sysconfig/sshd を読み込んでるのが分かる。ここでもDAEMON_COREFILE_LIMITは可能だ。 - /etc/sysconfig/sshdは存在しない。
# ls -l /etc/sysconfig/sshd ls: cannot access /etc/sysconfig/sshd: No such file or directory
- ${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- /etc/sysconfig/initを先に読み込む。
- /etc/sysconfig/fake-serviceを次に読み込む。
- 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の設定値をハードコードしてしまっても良いのでは無いか?
技術評論社
売り上げランキング: 6581
2012年01月26日
v.s. ログローテート未対応プログラム
- 標準出力しかしないプログラムがあったとする。
- プログラムの出力をログファイルとして保存する為に、標準出力をリダイレクトしてログファイルを作成して対応したとする。
こんな状況。
$ 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
要件定義
- サービス監視プログラムは修正しない
- 標準出力をログファイルへ出力・保存
- サービスを再起動する事無く、ログファイルを安全にローテート
作業概要
- flog環境構築
- 残念ながらflogのrpmは無く、debは存在するので、debからrpmを作成する。
- flogのdebパッケージをダウンロード
- alienを使ってdebからrpmへ変換
- flogをインストール
- upstart configを作成
- logrotate configを作成
- ログローテート確認
環境定義
| サービスプログラム | /tmp/fake-service.sh |
| ログファイル | /var/log/fake-service.log |
| upstart | /etc/init/fake-service.conf |
| logrotate | /etc/logrotate.d/fake-service |
事前作業
- alienでパッケージ変換(deb→rpm)により、alienがインストールされている事
作業内容
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設定
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 として記録
/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-service | 28692 |
| flog | 28694 |
ローテート前のログ状態を確認。
$ 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-service | 28692 |
| flog | 28694 |
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が悩みを解決してくれるだろう。
技術評論社
売り上げランキング: 6253
2012年01月25日
debをrpmへ変換したい
rpmは無いけどもdebには存在する場合に時々使える。 小さいパッケージであればalienで変換すれば手軽にrpmへ変換が可能。
検証環境
- RHEL 6.0 / CentOS 6.0 (x86_64)
- alien 8.81
作業概要
- alianのtarballをダウンロード
- 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日
名前は聞いた事があるのに、構築しなかった環境の1つ
DRBD環境構築が必要だったので、DRBD環境を構築。
構築完了したのは1ヶ月半も前の事。作業記録のタイムスタンプを見ると、11/08。 アウトプットするまでに随分と時間がかかってしまった事に反省。
検証環境
- RHEL 6.0 / CentOS 6.0 (i686)
- drbd 8.4.0
要件定義
作業概要
- DRBDをインストール
- DRBDの設定ファイルを作成
- DRBDを起動
- データ同期確認
サーバ構成
| ノード名 | 用途 | IPアドレス | NIC |
|---|---|---|---|
| node1 | master | 192.0.2.2 | eth0 |
| node2 | backup | 192.0.2.3 | |
| - | Virtual IP | 192.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日
複数NICと複数IPアドレス、複数VIP
本エントリは、前エントリ 『Linux + ucarpによるサーバ冗長化』 の続編。前エントリでは、単一ネットワークにおける冗長化。それに対し、本エントリでは複数ネットワークを扱う。
検証環境
- RHEL 6.0 / CentOS 6.0
- ucarp 1.5.2-1.el6
要件定義
- 障害が発生したネットワークのVIPのみfailover
- 正常ネットワークのVIPはfailoverしなくて良い
作業概要
- VIPの数だけconfigを作成
- ucarpを起動
- サービスの状態を確認
サーバ構成
| node1 | node2 | vip | |
|---|---|---|---|
| 役割 | master | backup | |
| eth2 | 192.0.2.2/25 | 192.0.2.3/25 | 192.0.2.126/25 |
| eth3 | 192.0.2.130/25 | 192.0.2.131/25 | 192.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となる為である。
- master(今回はnode1)
- 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
- 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している - 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つ
【確認】 down後のucarp状態
【確認】 ucarpプロセスはどうなっているのか
この結果により、eth3側のみfailoverしている事が分かる。 VIPを更に1つ2つ追加しても、問題なく動作してくれるだろう。
あとがき
/etc/ucarp/vip-*.conf を追加した後は、upscript/downscriptを充実させれば良いだけか。
2011年11月04日
環境構築する為の準備運動
ここ数日のエントリは、本エントリの環境を構築する為の検証作業。
準備運動が終わったので、いよいよ結合する時が来た。 この構成で環境構築する事が本エントリの主目的であって、信頼性を問うのは議論の対象外である。
検証環境
- RHEL 6.0 / CentOS 6.0
- ucarp 1.5.2-1.el6
- nfs-utils 1.2.2-7.el6
- mysql-server 5.1.52-1.el6_0.1
要件定義
- mysql + nfs
- 隣のノードの/var/lib/mysqlをdatadirとしてMySQLを起動
- mysqlクライアントはVIP指定でmysqlサーバへ接続
- ucarp
- failoverによりVIPが切り替わる
- 自動failbackは不要
- 手動failbackで良い
前提条件
- mysql datadir on nfsまで作業が完了している事
作業概要
- ucarpの設定ファイルを作成
- upscript, downscriptを配置
- ucarpを起動
- サービスの状態を確認
環境定義
| 用途 | IPアドレス | nfsディレクトリ | NIC | ucarp状態 |
|---|---|---|---|---|
| nfsクライアント | 192.0.2.12/24 | export: /var/lib/mysql/ | eth0 | master |
| nfsサーバ | 192.0.2.13/24 | mount: /var/lib/mysql/ | backup | |
| mysqlサーバ | 192.0.2.254/24 | - | - |
事前作業
作業前にucarpを停止しておく。 これは後の作業で更新する設定により、ucarp停止時の振る舞いが変化するのを避ける為。 必ず、backup側のucarpを停止してから、master側のucarpを停止する事。
- ucarp-backup
# /etc/init.d/ucarp stop
- ucarp-master
# /etc/init.d/ucarp stop
ucarpがmysqlのサービス起動・停止を行うので、mysqldがSysV initやupstartによって管理され無い事を確認しておく事。
# chkconfig --list mysqld mysqld 0:off 1:off 2:off 3:off 4:off 5:off 6:off
作業内容
Linux + ucarpによるサーバ冗長化で触れた様に、upscript/downscriptに冗長化したいアプリケーションの起動停止処理を記述出来る。nfsマウントとmysqlの起動停止を記述しておけば今回の要件を満たせる。
ucarp共通
upscriptとdownscriptを配置するディレクトリを作成。推奨されている配置先ディレクトリが定められてないので、今回は/etc/ucarp/vip-{up,down}.d/ に配置する。
# mkdir /etc/ucarp/vip-up.d # mkdir /etc/ucarp/vip-down.d
ucarp-masterに設定ファイルとupscript/downscriptを配置
master側にはnfsマウントに関する処理が入る。
- /etc/ucarp/vip-001.conf
SOURCE_ADDRESS=192.0.2.12 ID=001 BIND_INTERFACE=eth0 VIP_ADDRESS=192.0.2.254 OPTIONS="--shutdown --preempt" UPSCRIPT=/etc/ucarp/vip-up.d/mysql-master DOWNSCRIPT=/etc/ucarp/vip-down.d/mysql-master
- /etc/ucarp/vip-up.d/mysql-master
#!/bin/sh exec 2>/dev/null /sbin/ip address add "$2"/32 dev "$1" /bin/mount -t nfs 192.0.2.13:/var/lib/mysql/ /var/lib/mysql/ /etc/init.d/mysqld start
- /etc/ucarp/vip-down.d/mysql-master
#!/bin/sh exec 2>/dev/null /sbin/ip address del "$2"/32 dev "$1" /etc/init.d/mysqld stop /bin/umount /var/lib/mysql/
ucarp-backupに設定ファイルとupscript/downscriptを配置
backup側はmysql datadirがローカルディスクであるため、mount処理が無い。
- /etc/ucarp/vip-001.conf
SOURCE_ADDRESS=192.0.2.13 ID=001 BIND_INTERFACE=eth0 VIP_ADDRESS=192.0.2.254 OPTIONS="--shutdown --preempt" UPSCRIPT=/etc/ucarp/vip-up.d/mysql-backup DOWNSCRIPT=/etc/ucarp/vip-down.d/mysql-backup
- /etc/ucarp/vip-up.d/mysql-backup
#!/bin/sh exec 2>/dev/null /sbin/ip address add "$2"/32 dev "$1" /etc/init.d/mysqld start
- /etc/ucarp/vip-down.d/mysql-backup
#!/bin/sh exec 2>/dev/null /sbin/ip address del "$2"/32 dev "$1" /etc/init.d/mysqld stop
ucarpを起動
ucarp停止処理の順番とは逆で、master側ucarpを起動してから、backup側ucarpを起動する事。
- ucarp-master
# /etc/init.d/ucarp start
- ucarp-backup
# /etc/init.d/ucarp start
ucarp起動後の状態確認
master側でmysqlがサービスされていれば良い。大まかに確認するには、下記内容で問題ないはずだ。
ucarp-master
- VIPが割り当てられている事
# ip addr show eth0 | grep -w inet inet 192.0.2.12/24 brd 192.0.2.255 scope global eth0 inet 192.0.2.254/32 scope global eth0 - /var/lib/mysqlにnfsマウントされている事
# mount -t nfs 192.0.2.13:/var/lib/mysql/ on /var/lib/mysql type nfs (rw,vers=4,addr=192.0.2.13,clientaddr=192.0.2.12)
- mysqlが起動している事
# /etc/init.d/mysqld status mysqld (pid XXX) is running...
ucarp-backup
- VIPが割り当てられてない事
# ip addr show eth0 | grep -w inet inet 192.0.2.13/24 brd 192.0.2.255 scope global eth0 - mysqlが起動してない事
# /etc/init.d/mysqld status mysqld is stopped
failoverとfailbackを確認
ucarp-master, ucarp-backupのucarpを起動・停止させればmysqlとVIPが切り替わる。 failover/failbackの手順はLinux + ucarpによるサーバ冗長化を参照の事。手元の環境ではfailover/failbackする事を確認出来ている。
必要に応じて接続許可設定
追加設定無しではVIP指定で接続出来ないはずなので、GRANTで許可を付与しておく。
# mysql -uroot mysql> GRANT ALL PRIVILEGES ON *.* TO root@'%' WITH GRANT OPTION; mysql> FLUSH PRIVILEGES;
あとがき
ucarpを使えば簡単に冗長化させる事が可能だ。
秀和システム
売り上げランキング: 190665
信頼性はどうであれ、共有ディスクを使ったMySQL
nfsマウント領域にmysql datadirを配置し、mysqlを起動させる。
検証環境
- RHEL 6.0 / CentOS 6.0
- nfs-utils 1.2.2-7.el6
- mysql-server 5.1.52-1.el6_0.1
要件定義
- 隣のノードの/var/lib/mysqlをdatadirとしてMySQLを起動
作業概要
- nfsサーバ
- /var/lib/mysql を公開領域として設定
- nfsクライアント, mysqld
- nfsサーバの/var/lib/mysqlを、自身の/var/lib/mysqlにnfsマウント
- mysqlを起動
環境定義
| 用途 | IPアドレス | nfsディレクトリ |
|---|---|---|
| nfsクライアント | 192.0.2.12/24 | /var/lib/mysql/ |
| nfsサーバ | 192.0.2.13/24 | /var/lib/mysql/ |
事前作業
NFSの設定作業は ファイルサーバ構築 を参照の事。公開ディレクトリとマウントポイントを、それぞれ /var/lib/mysql に置き換えれば良い。
- 共通
-
# yum -y install mysql-server
- nfsサーバ
-
# echo '/var/lib/mysql 192.0.2.0/24(rw)' >> /etc/exports # exportfs -ra
作業内容
事前作業にて、nfsサーバの設定が終わってるものとする。
SELinuxを無効化
mysql datadirがnfsマウントされているとmysqldが起動しない。
# /etc/init.d/mysqld start chown: changing ownership of `/var/lib/mysql': Operation not permitted chmod: changing permissions of `/var/lib/mysql': Operation not permitted MySQL Daemon failed to start. Starting mysqld: [FAILED]
nfsマウントしたmysql datadir領域でもmysqlが起動する様にSELinuxを設定するのが良いのだろうが、本題はmysqlを起動させる事なのでSELinux無効化で済ませる。
# cp -pi /etc/sysconfig/selinux /etc/sysconfig/selinux.0 # diff /etc/sysconfig/selinux.0 /etc/sysconfig/selinux 7c7 < SELINUX=enforcing --- > SELINUX=disabled
システム再起動
# reboot
SELinuxが無効化さていればmysqlが起動するはず。
mysql datadirをnfsマウント
mountコマンドでnfsマウント。
# mount -t nfs 192.0.2.13:/var/lib/mysql /var/lib/mysql
必要に応じて/etc/fstabにマウントエントリを追加しておく事。
mysql起動
mysqlを起動
# /etc/init.d/mysqld start
mysqlが起動してる事を確認
# mysqladmin -uroot ping mysqld is alive
mysql接続して内容を確認
# mysql -uroot mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | test | +--------------------+ 3 rows in set (0.06 sec)
必要に応じてmysqlをサービス起動対象に追加しておくこと。
# chkconfig --list mysqld mysqld 0:off 1:off 2:off 3:off 4:off 5:off 6:off
あとがき
疑わしい挙動をする時はSELinuxを無効化か
秀和システム
売り上げランキング: 190665
稀に発生する作業なので、次に次に作業する時には忘れている
RHEL6系でNFS環境を構築した事がなかったので、本エントリに作業メモを残しておく。
検証環境
- RHEL 6.0 / CentOS 6.0
- nfs-utils 1.2.2-7.el6
要件定義
- プライベートネットワークでnfsマウント
- nfs公開領域はread/write許可
作業概要
- 共通
- nfs関連パッケージをインストール
- rpcbind起動
- nfs-server
- 公開ディレクトリ設定
- nfsd起動
- nfs-client
- nfsマウント
作業内容
環境定義
| 用途 | IPアドレス | nfsディレクトリ |
|---|---|---|
| nfsクライアント | 192.0.2.12/24 | /path/to/export/ |
| nfsサーバ | 192.0.2.13/24 | /mnt/nfs/ |
共通作業
nfs-utilsをインストール
# yum -y install nfs-utils
インストール直後のサービス状態を確認
# chkconfig --list | grep nfs nfs 0:off 1:off 2:off 3:off 4:off 5:off 6:off nfslock 0:off 1:off 2:off 3:on 4:on 5:on 6:off # chkconfig --list | grep rpcbind rpcbind 0:off 1:off 2:on 3:on 4:on 5:on 6:off
nfs-server/nfs-client共に必要なrpcbindを起動。インストールしただけではrpcbindが起動してない為。
# /etc/init.d/rpcbind start
nfsサーバ
必要に応じてiptablesの設定変更
# chkconfig --list iptables iptables 0:off 1:off 2:on 3:on 4:on 5:on 6:off
iptablesが有効の場合はtcp/2049を許可する
# cp -pi /etc/sysconfig/iptables /etc/sysconfig/iptables.0 # vi /etc/sysconfig/iptables
# diff /etc/sysconfig/iptables.0 /etc/sysconfig/iptables 10a11,14 > > -A INPUT -s 192.0.2.0/24 -p tcp --dport 2049 -j ACCEPT > -A INPUT -s 192.0.2.0/24 -p tcp --sport 2049 -j ACCEPT >
iptablesのruleを反映
# /etc/init.d/iptables restart
nfsサービスを起動
# /etc/init.d/nfs start
nfsを起動対象サービスに追加
# chkconfig nfs on # chkconfig --list nfs nfs 0:off 1:off 2:on 3:on 4:on 5:on 6:off
公開ディレクトリ設定。
# echo '/path/to/export/ 192.0.2.0/24(rw)' >> /etc/exports
/etc/exportsの内容を反映し、公開状態を確認
# exportfs -ra # exportfs -v /path/to/export 192.0.2.0/24(rw,wdelay,root_squash,no_subtree_check)
公開可能状態になった。
nfsクライアント
nfsマウント
# mkdir /mnt/nfs # mount -t nfs 192.0.2.13:/path/to/export/ /mnt/nfs
マウント状態を確認
# mount -t nfs 192.0.2.13:/path/to/export/ on /mnt/nfs type nfs (rw,vers=4,addr=192.0.2.13,clientaddr=192.0.2.12)
nfsマウント完了。後は必要に応じて/etc/fstabにマウントエントリを追加する。
あとがき
最初、iptablesが有効になっててnfsマウント出来なかった。
秀和システム
売り上げランキング: 190665
2011年11月02日
『ucarpは設定が簡単』
keepalivedでもなくheartbeatでもなく、ucarp。 ucarpを選択した理由の1つは、『何となく設定が簡単そう』だったから。 実際に設定してみると、簡単だった。
本エントリは、failoverによりVIPが切り替わる設定手順をまとめた物である。 もう少し踏み込んだサーバ冗長化構成は、別エントリにまとめるかも知れない。
検証環境
- RHEL 6.0 / CentOS 6.0
- ucarp 1.5.2-1.el6
要件定義
- failoverによりVIPが切り替わる
- 自動failbackは不要
- 手動failbackで良い
作業概要
- ucarpをインストール
- ucarpの設定ファイルを作成
- ucarpを起動
- failoverによるVIP切り替え
サーバ構成
| ノード名 | 用途 | IPアドレス | NIC |
|---|---|---|---|
| node1 | master | 192.0.2.2 | eth0 |
| node2 | backup | 192.0.2.3 | |
| - | Virtual IP | 192.0.2.254 |
作業内容
ucarpをインストール
ucarpはepelリポジトリを利用する為、必要に応じてepelリポジトリを利用する準備をしておく。
# rpm -ivh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-5.noarch.rpm
ucarpをインストール
# yum -y install ucarp
ucarp設定
設定ファイル名は、 『/etc/ucarp/vip-*.conf』であれば、読み込まれる。今回は設定ファイル /etc/ucarp/vip-001.conf を対象ノードに新規作成する。ノード間の差分は、SOURCE_ADDRESSのみ。
- node1:/etc/ucarp/vip-001.conf
-
SOURCE_ADDRESS=192.0.2.2 ID=001 BIND_INTERFACE=eth0 VIP_ADDRESS=192.0.2.254 OPTIONS="--shutdown --preempt"
- node2:/etc/ucarp/vip-001.conf
-
SOURCE_ADDRESS=192.0.2.3 ID=001 BIND_INTERFACE=eth0 VIP_ADDRESS=192.0.2.254 OPTIONS="--shutdown --preempt"
- ※backupノードに、「--advskew」を指定する設定例が多い
-
「--advskew」を指定すると、masterノードとbackupノードが明確になる。しかし、failoverによりbackupノードがmasterに昇格後、masterノードが復旧して来ると、自動failbackしてしまう。今回の要件では、自動failback不要であるため、「--advskew」を指定してない。
ucarpを起動対象サービスに追加
ucarpをインストールしただけでは、システム起動時の起動サービス対象には入ってない。
# chkconfig --list ucarp ucarp 0:off 1:off 2:off 3:off 4:off 5:off 6:off
システム起動時のサービス起動対象に追加する。
# chkconfig ucarp on
起動対象になってるのを確認。
# chkconfig --list ucarp ucarp 0:off 1:off 2:on 3:on 4:on 5:on 6:off
システム起動時にucarpが起動する。
ucarp起動
今回の設定で重要なのは、ucarpの起動順番。 先にucarpを起動させたノードがucarp-masterとなる。
- master(今回はnode1)
- 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 eth0 | grep -w inet inet 192.0.2.2/24 brd 192.0.2.255 scope global eth0 inet 192.0.2.254/32 scope global eth0 - node2
-
# ip addr show eth0 | grep -w inet inet 192.0.2.3/24 brd 192.0.2.255 scope global eth0
failover検証(VIPとucarp状態)
異常を検知させ、failoverによる状態遷移を確認しておく。
- 正常時
- node1, node2の順にucarpを起動(前述作業でucarp起動済み)
- 障害時
- node1のucarpを停止
- failoverした事を確認(VIPが切り替わる)
- 復旧時
- node1のucarpを起動
- failbackしない事を確認(VIPが切り替わらない)
failover検証時に期待するucarpの状態遷移
| ノード | 正常時 | 障害時 | 復旧時 |
| node1 | master | backup | backup |
| node2 | backup | master | master |
障害時(意図的にfailoverさせる)
node1(master)のucarpを停止してみると、failoverしてnode2(backup)にVIPが割り当てられる事を観察出来る。
node1# /etc/init.d/ucarp stop
- node1(master⇒backup)
-
# ip addr show eth0 | grep -w inet inet 192.0.2.2/24 brd 192.0.2.255 scope global eth0 - node2(backup⇒master)
-
# ip addr show eth0 | grep -w inet inet 192.0.2.3/24 brd 192.0.2.255 scope global eth0 inet 192.0.2.254/32 scope global eth0
復旧時(意図的にfailoverさせたまま)
failover確認後、node1のucarpを起動。
node1# /etc/init.d/ucarp start
- node1(backup⇒backup)
-
# ip addr show eth0 | grep -w inet inet 192.0.2.2/24 brd 192.0.2.255 scope global eth0 - node2(master⇒master)
-
# ip addr show eth0 | grep -w inet inet 192.0.2.3/24 brd 192.0.2.255 scope global eth0 inet 192.0.2.254/32 scope global eth0
node1のucarpを起動した後も、VIPはnode2に割り当てられたままである事が確認出来れば良い。 今回の要件では、これが正しい動き。
failbackさせるには?
failbackは、意図的にfailoverを行えば良い。ただし、実行対象ノードは反対となる。
- node2のucarpを停止
- failback(node2からnode1へfailover)させる
- node2のucarpを起動
upscriptとdownscript(状態遷移時の実行スクリプト)
特に指定がない場合は、/etc/init.d/ucarpでvipのup/down用スクリプトが指定されている。
- /etc/init.d/ucarpの該当箇所
-
34行目 UPSCRIPT=/usr/libexec/ucarp/vip-up 35行目 DOWNSCRIPT=/usr/libexec/ucarp/vip-down
- /usr/libexec/ucarp/vip-up
-
#!/bin/sh exec 2>/dev/null /sbin/ip address add "$2"/32 dev "$1"
- /usr/libexec/ucarp/vip-down
-
#!/bin/sh exec 2>/dev/null /sbin/ip address del "$2"/32 dev "$1"
- /etc/ucarp/vip-001.conf への追記例
-
UPSCRIPT=/path/to/ucarp/vip-001-up DOWNSCRIPT=/path/to/ucarp/vip-001-down
UPSCRIPTとDOWNSCRIPTは、設定ファイル毎(VIP毎)に上書き指定が可能となっていて、 例えば今回の設定ファイル/etc/ucarp/vip-001.confにも追記可能。
upscript/downscriptには、冗長化したいアプリケーションの起動停止処理を書いておけば良い。 そうすれば、ucarpがVIPの切り替えと共にアプリケーションの起動・停止まで面倒を見てくれる。
参考ページ
あとがき
あとは実戦投入して、どうなるか。
秀和システム
売り上げランキング: 98150


